mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-07-27 18:41:15 +08:00
⛄ Sync 2026-03-31 23:53:13
This commit is contained in:
parent
029b517c03
commit
be9ee994ab
@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=hickory-dns
|
||||
PKG_VERSION:=2026.03.31
|
||||
PKG_RELEASE:=6
|
||||
PKG_VERSION:=2026.03.31-b57b7ae
|
||||
PKG_RELEASE:=7
|
||||
|
||||
HICKORY_COMMIT:=b57b7aec2c6c18d64b90f01c97595171963e0e56
|
||||
|
||||
|
||||
@ -4,6 +4,37 @@
|
||||
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
|
||||
|
||||
## [2.0.2] - 2026-03-31
|
||||
|
||||
### 新增功能
|
||||
|
||||
#### 支持自定义安装路径
|
||||
|
||||
- **功能描述**: 用户现在可以将 OpenClaw 运行环境安装到自定义路径(如第二块硬盘 `/mnt/data`)
|
||||
- **LuCI 界面**: 安装对话框增加自定义路径输入框,支持实时检测目标路径的可用空间
|
||||
- **系统检测**: 安装前系统配置检测会检测自定义路径的磁盘空间,而非默认的 `/opt`
|
||||
- **服务状态**: 状态 API 返回当前安装路径信息
|
||||
- **最小空间提示**: 安装界面提示最小需要 2GB 可用空间
|
||||
|
||||
#### 技术实现
|
||||
|
||||
- 新增 UCI 配置项 `openclaw.main.install_path`,默认值为 `/opt`
|
||||
- 程序会在用户指定路径下自动创建 `openclaw` 目录进行安装
|
||||
- 例如:用户输入 `/mnt/data`,实际安装路径为 `/mnt/data/openclaw`
|
||||
- 所有脚本和配置文件支持从 UCI 读取自定义路径:
|
||||
- `openclaw-env`: 通过 `OC_INSTALL_PATH` 环境变量或 UCI 配置
|
||||
- `init.d/openclaw`: 启动时从 UCI 读取路径
|
||||
- `oc-config.sh`: 支持自定义路径的环境变量
|
||||
- `profile.d/openclaw.sh`: SSH 环境变量支持
|
||||
- `uci-defaults/99-openclaw`: 首次安装初始化支持
|
||||
|
||||
|
||||
### 感谢
|
||||
|
||||
感谢 @hotwa 提供的修改思路和建议。
|
||||
|
||||
---
|
||||
|
||||
## [2.0.1] - 2026-03-30
|
||||
|
||||
### 适配 OpenClaw v2026.3.28
|
||||
|
||||
@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-openclaw
|
||||
PKG_VERSION:=$(strip $(shell cat $(CURDIR)/VERSION 2>/dev/null || echo "1.0.0"))
|
||||
PKG_RELEASE:=4
|
||||
PKG_RELEASE:=5
|
||||
|
||||
PKG_MAINTAINER:=10000ge10000 <10000ge10000@users.noreply.github.com>
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
|
||||
@ -1 +1 @@
|
||||
2.0.1
|
||||
2.0.2
|
||||
|
||||
@ -57,6 +57,9 @@ function action_status()
|
||||
local port = uci:get("openclaw", "main", "port") or "18789"
|
||||
local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
local enabled = uci:get("openclaw", "main", "enabled") or "0"
|
||||
local install_path_uci = uci:get("openclaw", "main", "install_path") or "/opt"
|
||||
-- 实际安装路径会在用户路径下创建 openclaw 子目录
|
||||
local install_path = install_path_uci .. "/openclaw"
|
||||
|
||||
-- 验证端口值为纯数字,防止命令注入
|
||||
if not port:match("^%d+$") then port = "18789" end
|
||||
@ -66,6 +69,7 @@ function action_status()
|
||||
enabled = enabled,
|
||||
port = port,
|
||||
pty_port = pty_port,
|
||||
install_path = install_path,
|
||||
gateway_running = false,
|
||||
gateway_starting = false,
|
||||
pty_running = false,
|
||||
@ -75,6 +79,7 @@ function action_status()
|
||||
node_version = "",
|
||||
oc_version = "",
|
||||
plugin_version = "",
|
||||
disk_free = "",
|
||||
}
|
||||
|
||||
-- 插件版本
|
||||
@ -86,8 +91,8 @@ function action_status()
|
||||
|
||||
-- 安装方式检测 (离线 / 在线)
|
||||
|
||||
-- 检查 Node.js
|
||||
local node_bin = "/opt/openclaw/node/bin/node"
|
||||
-- 检查 Node.js (使用自定义安装路径)
|
||||
local node_bin = install_path .. "/node/bin/node"
|
||||
local f = io.open(node_bin, "r")
|
||||
if f then
|
||||
f:close()
|
||||
@ -95,11 +100,11 @@ function action_status()
|
||||
result.node_version = node_ver
|
||||
end
|
||||
|
||||
-- OpenClaw 版本 (从 package.json 读取)
|
||||
-- OpenClaw 版本 (从 package.json 读取,使用自定义安装路径)
|
||||
local oc_dirs = {
|
||||
"/opt/openclaw/global/lib/node_modules/openclaw",
|
||||
"/opt/openclaw/global/node_modules/openclaw",
|
||||
"/opt/openclaw/node/lib/node_modules/openclaw",
|
||||
install_path .. "/global/lib/node_modules/openclaw",
|
||||
install_path .. "/global/node_modules/openclaw",
|
||||
install_path .. "/node/lib/node_modules/openclaw",
|
||||
}
|
||||
for _, d in ipairs(oc_dirs) do
|
||||
local pf = io.open(d .. "/package.json", "r")
|
||||
@ -131,8 +136,8 @@ function action_status()
|
||||
local pty_check = sys.exec("netstat -tulnp 2>/dev/null | grep -c ':" .. pty_port .. " ' || echo 0"):gsub("%s+", "")
|
||||
result.pty_running = (tonumber(pty_check) or 0) > 0
|
||||
|
||||
-- 读取当前活跃模型
|
||||
local config_file = "/opt/openclaw/data/.openclaw/openclaw.json"
|
||||
-- 读取当前活跃模型 (使用自定义安装路径)
|
||||
local config_file = install_path .. "/data/.openclaw/openclaw.json"
|
||||
local cf = io.open(config_file, "r")
|
||||
if cf then
|
||||
local content = cf:read("*a")
|
||||
@ -192,6 +197,13 @@ function action_status()
|
||||
end
|
||||
end
|
||||
|
||||
-- 磁盘剩余空间 (检测安装路径所在分区)
|
||||
local install_parent = install_path:match("^(.*)/[^/]*$") or "/"
|
||||
local df_output = sys.exec("df -h " .. install_parent .. " 2>/dev/null | tail -1 | awk '{print $4}'"):gsub("%s+", "")
|
||||
if df_output and df_output ~= "" then
|
||||
result.disk_free = df_output
|
||||
end
|
||||
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(result)
|
||||
end
|
||||
@ -225,6 +237,8 @@ function action_service_ctl()
|
||||
sys.exec("rm -f /tmp/openclaw-setup.log /tmp/openclaw-setup.pid /tmp/openclaw-setup.exit")
|
||||
-- 获取用户选择的版本 (stable=指定版本, latest=最新版)
|
||||
local version = http.formvalue("version") or ""
|
||||
-- 获取自定义安装路径 (用户输入的是基础路径,如 /opt 或 /mnt/data)
|
||||
local install_path = http.formvalue("install_path") or ""
|
||||
local env_prefix = ""
|
||||
if version == "stable" then
|
||||
-- 稳定版: 读取 openclaw-env 中定义的 OC_TESTED_VERSION
|
||||
@ -238,6 +252,17 @@ function action_service_ctl()
|
||||
env_prefix = "OC_VERSION=" .. version .. " "
|
||||
end
|
||||
end
|
||||
-- 处理自定义安装路径
|
||||
if install_path ~= "" and install_path ~= "/opt" then
|
||||
-- 安全检查: 路径不能包含危险字符
|
||||
install_path = install_path:gsub("[`$;&|<>]", "")
|
||||
install_path = install_path:gsub("/+$", "")
|
||||
if install_path ~= "" then
|
||||
-- 保存到 UCI 配置 (保存用户输入的基础路径)
|
||||
sys.exec("uci set openclaw.main.install_path='" .. install_path .. "'; uci commit openclaw 2>/dev/null")
|
||||
env_prefix = env_prefix .. "OC_INSTALL_PATH='" .. install_path .. "' "
|
||||
end
|
||||
end
|
||||
-- 后台安装,成功后自动启用并启动服务
|
||||
-- 注: openclaw-env 脚本有 set -e,init_openclaw 中的非关键失败不应阻止启动
|
||||
sys.exec("( " .. env_prefix .. "/usr/bin/openclaw-env setup > /tmp/openclaw-setup.log 2>&1; RC=$?; echo $RC > /tmp/openclaw-setup.exit; if [ $RC -eq 0 ]; then uci set openclaw.main.enabled=1; uci commit openclaw; /etc/init.d/openclaw enable 2>/dev/null; sleep 1; /etc/init.d/openclaw start >> /tmp/openclaw-setup.log 2>&1; fi ) & echo $! > /tmp/openclaw-setup.pid")
|
||||
@ -368,6 +393,12 @@ end
|
||||
function action_uninstall()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
-- 获取安装路径
|
||||
local install_path_uci = uci:get("openclaw", "main", "install_path") or "/opt"
|
||||
-- 实际安装路径
|
||||
local install_path = install_path_uci .. "/openclaw"
|
||||
|
||||
-- 停止服务
|
||||
sys.exec("/etc/init.d/openclaw stop >/dev/null 2>&1")
|
||||
@ -376,7 +407,7 @@ function action_uninstall()
|
||||
-- 设置 UCI enabled=0
|
||||
sys.exec("uci set openclaw.main.enabled=0; uci commit openclaw 2>/dev/null")
|
||||
-- 删除 Node.js + OpenClaw 运行环境 (包含所有插件: qqbot, 飞书等)
|
||||
sys.exec("rm -rf /opt/openclaw")
|
||||
sys.exec("rm -rf " .. install_path)
|
||||
-- 清理旧数据迁移后可能残留的目录
|
||||
sys.exec("rm -rf /root/.openclaw 2>/dev/null")
|
||||
-- 清理临时文件
|
||||
@ -389,7 +420,7 @@ function action_uninstall()
|
||||
http.prepare_content("application/json")
|
||||
http.write_json({
|
||||
status = "ok",
|
||||
message = "运行环境已卸载。已清理: Node.js 运行环境 (/opt/openclaw)、所有插件 (qqbot/飞书等)、旧数据目录 (/root/.openclaw)、临时文件、LuCI 缓存。"
|
||||
message = "运行环境已卸载。已清理: Node.js 运行环境 (" .. install_path .. ")、所有插件 (qqbot/飞书等)、旧数据目录 (/root/.openclaw)、临时文件、LuCI 缓存。"
|
||||
})
|
||||
end
|
||||
|
||||
@ -544,16 +575,21 @@ end
|
||||
function action_backup()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local action = http.formvalue("action") or "create"
|
||||
|
||||
local node_bin = "/opt/openclaw/node/bin/node"
|
||||
-- 获取安装路径
|
||||
local install_path_uci = uci:get("openclaw", "main", "install_path") or "/opt"
|
||||
-- 实际安装路径
|
||||
local install_path = install_path_uci .. "/openclaw"
|
||||
local node_bin = install_path .. "/node/bin/node"
|
||||
local oc_entry = ""
|
||||
|
||||
-- 查找 openclaw 入口
|
||||
-- 查找 openclaw 入口 (使用自定义安装路径)
|
||||
local search_dirs = {
|
||||
"/opt/openclaw/global/lib/node_modules/openclaw",
|
||||
"/opt/openclaw/global/node_modules/openclaw",
|
||||
"/opt/openclaw/node/lib/node_modules/openclaw",
|
||||
install_path .. "/global/lib/node_modules/openclaw",
|
||||
install_path .. "/global/node_modules/openclaw",
|
||||
install_path .. "/node/lib/node_modules/openclaw",
|
||||
}
|
||||
for _, d in ipairs(search_dirs) do
|
||||
if nixio.fs.stat(d .. "/openclaw.mjs", "type") then
|
||||
@ -572,14 +608,15 @@ function action_backup()
|
||||
end
|
||||
|
||||
local env_prefix = string.format(
|
||||
"HOME=/opt/openclaw/data OPENCLAW_HOME=/opt/openclaw/data " ..
|
||||
"OPENCLAW_STATE_DIR=/opt/openclaw/data/.openclaw " ..
|
||||
"OPENCLAW_CONFIG_PATH=/opt/openclaw/data/.openclaw/openclaw.json " ..
|
||||
"PATH=/opt/openclaw/node/bin:/opt/openclaw/global/bin:$PATH "
|
||||
"HOME=%s/data OPENCLAW_HOME=%s/data " ..
|
||||
"OPENCLAW_STATE_DIR=%s/data/.openclaw " ..
|
||||
"OPENCLAW_CONFIG_PATH=%s/data/.openclaw/openclaw.json " ..
|
||||
"PATH=%s/node/bin:%s/global/bin:$PATH ",
|
||||
install_path, install_path, install_path, install_path, install_path, install_path
|
||||
)
|
||||
|
||||
-- 备份目录 (openclaw backup create 输出到 CWD,需要 cd)
|
||||
local backup_dir = "/opt/openclaw/data/.openclaw/backups"
|
||||
local backup_dir = install_path .. "/data/.openclaw/backups"
|
||||
local cd_prefix = "mkdir -p " .. backup_dir .. " && cd " .. backup_dir .. " && "
|
||||
|
||||
-- ── 辅助: 解析单个备份文件的 manifest 信息 ──
|
||||
@ -646,7 +683,7 @@ function action_backup()
|
||||
end
|
||||
local output = sys.exec(backup_cmd)
|
||||
-- 完整备份可能输出到 HOME,移动到 backup_dir
|
||||
sys.exec("mv /opt/openclaw/data/*-openclaw-backup.tar.gz " .. backup_dir .. "/ 2>/dev/null")
|
||||
sys.exec("mv " .. install_path .. "/data/*-openclaw-backup.tar.gz " .. backup_dir .. "/ 2>/dev/null")
|
||||
-- 提取备份文件路径
|
||||
local backup_path = output:match("([%S]+%.tar%.gz)")
|
||||
http.prepare_content("application/json")
|
||||
@ -692,7 +729,7 @@ function action_backup()
|
||||
http.write_json({ status = "error", message = "未找到备份文件,请先创建备份" })
|
||||
return
|
||||
end
|
||||
local oc_data_dir = "/opt/openclaw/data/.openclaw"
|
||||
local oc_data_dir = install_path .. "/data/.openclaw"
|
||||
local config_path = oc_data_dir .. "/openclaw.json"
|
||||
|
||||
-- 1) 先验证备份中的 openclaw.json 是否有效
|
||||
@ -811,10 +848,20 @@ end
|
||||
-- 系统配置检测 API (安装前检测)
|
||||
-- 检测内存和磁盘空间是否满足最低要求
|
||||
-- 要求: 内存 > 1GB, 磁盘可用空间 > 2GB (OpenClaw v2026.3.28+ 包体积约 200MB)
|
||||
-- 支持自定义安装路径,检测对应路径的磁盘空间
|
||||
-- ═══════════════════════════════════════════
|
||||
function action_check_system()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
-- 获取自定义安装路径 (用户输入的是基础路径,如 /opt 或 /mnt/data)
|
||||
local install_path = http.formvalue("install_path") or uci:get("openclaw", "main", "install_path") or "/opt"
|
||||
-- 安全检查: 路径不能包含危险字符
|
||||
install_path = install_path:gsub("[`$;&|<>]", "")
|
||||
-- 确保路径不以 / 结尾
|
||||
install_path = install_path:gsub("/+$", "")
|
||||
if install_path == "" then install_path = "/opt" end
|
||||
|
||||
-- 最低要求配置 (v2026.3.28: 包体积 ~200MB, 建议 2GB 可用空间)
|
||||
local MIN_MEMORY_MB = 1024 -- 1GB
|
||||
@ -826,6 +873,8 @@ function action_check_system()
|
||||
disk_mb = 0,
|
||||
disk_ok = false,
|
||||
disk_path = "",
|
||||
install_path = install_path,
|
||||
disk_free_str = "",
|
||||
pass = false,
|
||||
message = ""
|
||||
}
|
||||
@ -845,14 +894,40 @@ function action_check_system()
|
||||
result.memory_ok = result.memory_mb >= MIN_MEMORY_MB
|
||||
|
||||
-- 检测磁盘可用空间
|
||||
-- 优先检测 /opt 所在分区,如果 /opt 不存在则检测 /overlay 或 /
|
||||
local disk_paths = {"/opt", "/overlay", "/"}
|
||||
for _, path in ipairs(disk_paths) do
|
||||
local df_output = sys.exec("df -m " .. path .. " 2>/dev/null | tail -1 | awk '{print $4}'"):gsub("%s+", "")
|
||||
-- 策略: 从目标路径开始,逐级向上找到存在的挂载点进行检测
|
||||
-- 例如: /mnt/data -> /mnt/data (若存在) -> /mnt (若存在) -> /
|
||||
local function find_mount_point(path)
|
||||
-- 如果路径存在,直接返回
|
||||
if nixio.fs.stat(path, "type") then
|
||||
return path
|
||||
end
|
||||
-- 逐级向上查找
|
||||
while path ~= "/" and path ~= "" do
|
||||
path = path:match("^(.*)/[^/]*$") or "/"
|
||||
if path == "" then path = "/" end
|
||||
if nixio.fs.stat(path, "type") then
|
||||
return path
|
||||
end
|
||||
end
|
||||
return "/"
|
||||
end
|
||||
|
||||
local disk_check_path = find_mount_point(install_path)
|
||||
|
||||
-- 使用 df 检测磁盘空间
|
||||
local df_output = sys.exec("df -m " .. disk_check_path .. " 2>/dev/null | tail -1 | awk '{print $4}'"):gsub("%s+", "")
|
||||
if df_output and df_output ~= "" and tonumber(df_output) then
|
||||
result.disk_mb = tonumber(df_output)
|
||||
result.disk_path = disk_check_path
|
||||
-- 获取可读的磁盘空间格式
|
||||
result.disk_free_str = sys.exec("df -h " .. disk_check_path .. " 2>/dev/null | tail -1 | awk '{print $4}'"):gsub("%s+", "")
|
||||
else
|
||||
-- 如果检测失败,尝试检测根分区
|
||||
df_output = sys.exec("df -m / 2>/dev/null | tail -1 | awk '{print $4}'"):gsub("%s+", "")
|
||||
if df_output and df_output ~= "" and tonumber(df_output) then
|
||||
result.disk_mb = tonumber(df_output)
|
||||
result.disk_path = path
|
||||
break
|
||||
result.disk_path = "/"
|
||||
result.disk_free_str = sys.exec("df -h / 2>/dev/null | tail -1 | awk '{print $4}'"):gsub("%s+", "")
|
||||
end
|
||||
end
|
||||
result.disk_ok = result.disk_mb >= MIN_DISK_MB
|
||||
|
||||
@ -42,9 +42,9 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = '<div id="action-result" style="margin-top:8px;"></div>'
|
||||
html[#html+1] = '<div id="oc-update-action" style="margin-top:8px;display:none;"></div>'
|
||||
|
||||
-- 版本选择对话框 (默认隐藏)
|
||||
-- 版本选择对话框 (默认隐藏) - 支持自定义安装路径
|
||||
html[#html+1] = '<div id="oc-setup-dialog" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:10000;align-items:center;justify-content:center;">'
|
||||
html[#html+1] = '<div style="background:#fff;border-radius:12px;padding:24px 28px;max-width:480px;width:90%;box-shadow:0 8px 32px rgba(0,0,0,0.2);">'
|
||||
html[#html+1] = '<div style="background:#fff;border-radius:12px;padding:24px 28px;max-width:520px;width:92%;box-shadow:0 8px 32px rgba(0,0,0,0.2);">'
|
||||
html[#html+1] = '<h3 style="margin:0 0 16px 0;font-size:16px;color:#333;">📦 选择安装版本</h3>'
|
||||
html[#html+1] = '<div style="display:flex;flex-direction:column;gap:12px;">'
|
||||
-- 稳定版选项
|
||||
@ -60,6 +60,15 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = '<div style="font-size:12px;color:#e36209;margin-top:4px;">⚠️ 安装 npm 上的最新发布版本,可能存在未经验证的兼容性问题。</div>'
|
||||
html[#html+1] = '</div></label>'
|
||||
html[#html+1] = '</div>'
|
||||
-- 自定义安装路径
|
||||
html[#html+1] = '<div style="margin-top:16px;padding-top:14px;border-top:1px solid #eee;">'
|
||||
html[#html+1] = '<div style="font-weight:600;font-size:13px;color:#333;margin-bottom:8px;">📂 安装路径</div>'
|
||||
html[#html+1] = '<div style="display:flex;gap:8px;align-items:center;">'
|
||||
html[#html+1] = '<input type="text" id="oc-install-path" value="/opt" style="flex:1;padding:8px 12px;border:1px solid #d0d7de;border-radius:6px;font-size:13px;" placeholder="/opt">'
|
||||
html[#html+1] = '<button class="btn cbi-button" type="button" onclick="ocCheckInstallPath()" style="font-size:12px;padding:4px 10px;">检测空间</button>'
|
||||
html[#html+1] = '</div>'
|
||||
html[#html+1] = '<div id="oc-path-info" style="font-size:11px;color:#666;margin-top:6px;">💡 程序将在此路径下创建 openclaw 目录进行安装。最小需要 2GB 可用空间。如安装在第二块硬盘,请确保硬盘已挂载。</div>'
|
||||
html[#html+1] = '</div>'
|
||||
-- 按钮区
|
||||
html[#html+1] = '<div style="display:flex;gap:10px;justify-content:flex-end;margin-top:20px;">'
|
||||
html[#html+1] = '<button class="btn cbi-button" type="button" onclick="ocCloseSetupDialog()" style="min-width:80px;">取消</button>'
|
||||
@ -79,6 +88,7 @@ act.cfgvalue = function(self, section)
|
||||
|
||||
-- JavaScript
|
||||
html[#html+1] = '<script type="text/javascript">'
|
||||
html[#html+1] = 'console.log("OpenClaw JS loading...");'
|
||||
|
||||
-- 版本选择对话框逻辑
|
||||
html[#html+1] = 'var _setupTimer=null;'
|
||||
@ -91,10 +101,30 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = 'function ocCloseSetupDialog(){'
|
||||
html[#html+1] = 'document.getElementById("oc-setup-dialog").style.display="none";'
|
||||
html[#html+1] = '}'
|
||||
-- 检测自定义安装路径的磁盘空间
|
||||
html[#html+1] = 'function ocCheckInstallPath(){'
|
||||
html[#html+1] = 'var pathEl=document.getElementById("oc-install-path");'
|
||||
html[#html+1] = 'var infoEl=document.getElementById("oc-path-info");'
|
||||
html[#html+1] = 'var path=pathEl.value.trim();'
|
||||
html[#html+1] = 'if(!path){path="/opt";pathEl.value=path;}'
|
||||
html[#html+1] = 'infoEl.innerHTML="⏳ 正在检测空间...";'
|
||||
html[#html+1] = '(new XHR()).get("' .. check_system_url .. '?install_path="+encodeURIComponent(path),null,function(x){'
|
||||
html[#html+1] = 'try{'
|
||||
html[#html+1] = 'var r=JSON.parse(x.responseText);'
|
||||
html[#html+1] = 'if(r.disk_ok){'
|
||||
html[#html+1] = 'infoEl.innerHTML="<span style=\\"color:#1a7f37;\\">✅ 可用空间: "+r.disk_free_str+" (检测路径: "+r.disk_path+")</span>";'
|
||||
html[#html+1] = '}else{'
|
||||
html[#html+1] = 'infoEl.innerHTML="<span style=\\"color:#cf222e;\\">❌ 空间不足: "+r.disk_mb+" MB 可用,需要 ≥ 2048 MB (检测路径: "+r.disk_path+")</span>";'
|
||||
html[#html+1] = '}'
|
||||
html[#html+1] = '}catch(e){infoEl.innerHTML="<span style=\\"color:#e36209;\\">⚠️ 检测失败</span>";}'
|
||||
html[#html+1] = '});'
|
||||
html[#html+1] = '}'
|
||||
html[#html+1] = 'function ocConfirmSetup(){'
|
||||
html[#html+1] = 'var btn=document.getElementById("btn-setup");'
|
||||
html[#html+1] = 'var pathEl=document.getElementById("oc-install-path");'
|
||||
html[#html+1] = 'var installPath=pathEl.value.trim()||"/opt";'
|
||||
html[#html+1] = 'btn.disabled=true;btn.textContent="⏳ 检测系统配置...";'
|
||||
html[#html+1] = '(new XHR()).get("' .. check_system_url .. '",null,function(x){'
|
||||
html[#html+1] = '(new XHR()).get("' .. check_system_url .. '?install_path="+encodeURIComponent(installPath),null,function(x){'
|
||||
html[#html+1] = 'try{'
|
||||
html[#html+1] = 'var r=JSON.parse(x.responseText);'
|
||||
html[#html+1] = 'var panel=document.getElementById("setup-log-panel");'
|
||||
@ -111,6 +141,7 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = 'logEl.textContent+="════════════════════════════════════════\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="🔍 系统配置检测\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="════════════════════════════════════════\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="安装路径: "+r.install_path+"\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="内存: "+r.memory_mb+" MB (需要 ≥ 1024 MB) — "+(r.memory_ok?"✅ 通过":"❌ 不达标")+"\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="磁盘: "+r.disk_mb+" MB 可用 (需要 ≥ 2048 MB) — "+(r.disk_ok?"✅ 通过":"❌ 不达标")+"\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="\\n";'
|
||||
@ -133,7 +164,7 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = 'var choice="stable";'
|
||||
html[#html+1] = 'for(var i=0;i<radios.length;i++){if(radios[i].checked){choice=radios[i].value;break;}}'
|
||||
html[#html+1] = 'var verParam=(choice==="stable")?"stable":"latest";'
|
||||
html[#html+1] = 'ocSetup(verParam,r.memory_mb,r.disk_mb);'
|
||||
html[#html+1] = 'ocSetup(verParam,r.memory_mb,r.disk_mb,r.install_path);'
|
||||
html[#html+1] = '}catch(e){'
|
||||
html[#html+1] = 'ocCloseSetupDialog();'
|
||||
html[#html+1] = 'btn.disabled=false;btn.textContent="📦 安装运行环境";'
|
||||
@ -141,16 +172,17 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = '}});'
|
||||
html[#html+1] = '}'
|
||||
|
||||
-- 安装运行环境 (带实时日志)
|
||||
html[#html+1] = 'function ocSetup(version,mem_mb,disk_mb){'
|
||||
-- 安装运行环境 (带实时日志,支持自定义路径)
|
||||
html[#html+1] = 'function ocSetup(version,mem_mb,disk_mb,install_path){'
|
||||
html[#html+1] = 'var btn=document.getElementById("btn-setup");'
|
||||
html[#html+1] = 'var logEl=document.getElementById("setup-log-content");'
|
||||
html[#html+1] = 'btn.disabled=true;btn.textContent="⏳ 安装中...";'
|
||||
html[#html+1] = 'logEl.textContent+="════════════════════════════════════════\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="📦 安装运行环境 ("+((version==="stable")?"稳定版":"最新版")+")\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="════════════════════════════════════════\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="安装路径: "+install_path+"\\n";'
|
||||
html[#html+1] = 'logEl.textContent+="正在启动安装...\\n";'
|
||||
html[#html+1] = '(new XHR()).get("' .. ctl_url .. '?action=setup&version="+encodeURIComponent(version),null,function(x){'
|
||||
html[#html+1] = '(new XHR()).get("' .. ctl_url .. '?action=setup&version="+encodeURIComponent(version)+"&install_path="+encodeURIComponent(install_path),null,function(x){'
|
||||
html[#html+1] = 'try{JSON.parse(x.responseText);}catch(e){}'
|
||||
html[#html+1] = 'ocPollSetupLog();'
|
||||
html[#html+1] = '});'
|
||||
@ -231,15 +263,15 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = '}'
|
||||
-- npm 安装失败
|
||||
html[#html+1] = 'if(ll.indexOf("npm err")>=0||ll.indexOf("npm warn")>=0&&ll.indexOf("openclaw 安装验证失败")>=0){'
|
||||
html[#html+1] = 'reasons.push("📦 <b>npm 安装 OpenClaw 失败</b> — npm 包下载或安装出错。<br/> 💡 解决: 尝试手动安装 <code>PATH=/opt/openclaw/node/bin:$PATH npm install -g openclaw@latest --prefix=/opt/openclaw/global</code>");'
|
||||
html[#html+1] = 'reasons.push("📦 <b>npm 安装 OpenClaw 失败</b> — npm 包下载或安装出错。<br/> 💡 解决: 尝试手动安装 <code>openclaw-env setup</code> 或检查网络连接。");'
|
||||
html[#html+1] = '}'
|
||||
-- 权限问题
|
||||
html[#html+1] = 'if(ll.indexOf("permission denied")>=0||ll.indexOf("eacces")>=0){'
|
||||
html[#html+1] = 'reasons.push("🔒 <b>权限不足</b> — 文件或目录权限问题。<br/> 💡 解决: 运行 <code>chown -R openclaw:openclaw /opt/openclaw</code> 或以 root 用户重试。");'
|
||||
html[#html+1] = 'reasons.push("🔒 <b>权限不足</b> — 文件或目录权限问题。<br/> 💡 解决: 运行 <code>openclaw-env setup</code> 或以 root 用户重试。");'
|
||||
html[#html+1] = '}'
|
||||
-- tar 解压失败
|
||||
html[#html+1] = 'if(ll.indexOf("tar")>=0&&(ll.indexOf("error")>=0||ll.indexOf("fail")>=0)){'
|
||||
html[#html+1] = 'reasons.push("📂 <b>解压失败</b> — Node.js 安装包可能下载不完整。<br/> 💡 解决: 删除缓存重试 <code>rm -rf /opt/openclaw/node && openclaw-env setup</code>");'
|
||||
html[#html+1] = 'reasons.push("📂 <b>解压失败</b> — Node.js 安装包可能下载不完整。<br/> 💡 解决: 删除缓存重试 <code>openclaw-env setup</code>");'
|
||||
html[#html+1] = '}'
|
||||
-- 验证失败
|
||||
html[#html+1] = 'if(ll.indexOf("安装验证失败")>=0){'
|
||||
@ -384,7 +416,7 @@ act.cfgvalue = function(self, section)
|
||||
|
||||
-- 卸载运行环境
|
||||
html[#html+1] = 'function ocUninstall(){'
|
||||
html[#html+1] = 'if(!confirm("确定要卸载 OpenClaw 运行环境?\\n\\n将删除 Node.js、OpenClaw 程序及配置数据(/opt/openclaw 目录),服务将停止运行。\\n\\n插件本身不会被删除,之后可重新安装运行环境。"))return;'
|
||||
html[#html+1] = 'if(!confirm("确定要卸载 OpenClaw 运行环境?\\n\\n将删除 Node.js、OpenClaw 程序及配置数据,服务将停止运行。\\n\\n插件本身不会被删除,之后可重新安装运行环境。"))return;'
|
||||
html[#html+1] = 'var btn=document.getElementById("btn-uninstall");'
|
||||
html[#html+1] = 'var el=document.getElementById("action-result");'
|
||||
html[#html+1] = 'btn.disabled=true;btn.textContent="⏳ 正在卸载...";'
|
||||
@ -400,6 +432,7 @@ act.cfgvalue = function(self, section)
|
||||
html[#html+1] = '}else{el.innerHTML="<span style=\\"color:red\\">❌ "+(r.message||"卸载失败")+"</span>";}'
|
||||
html[#html+1] = '}catch(e){el.innerHTML="<span style=\\"color:red\\">❌ 请求失败</span>";}'
|
||||
html[#html+1] = '});}'
|
||||
html[#html+1] = 'console.log("OpenClaw JS first block loaded");'
|
||||
|
||||
-- ═══ 备份/恢复 对话框 + 功能 (v2026.3.8+ openclaw backup) ═══
|
||||
local backup_url = luci.dispatcher.build_url("admin", "services", "openclaw", "backup")
|
||||
|
||||
@ -78,6 +78,8 @@
|
||||
<tr><td>Node.js</td><td id="oc-st-node">-</td></tr>
|
||||
<tr><td>OpenClaw</td><td id="oc-st-oc-ver">-</td></tr>
|
||||
<tr><td>插件版本</td><td id="oc-st-plugin">-</td></tr>
|
||||
<tr><td>安装路径</td><td id="oc-st-path">-</td></tr>
|
||||
<tr><td>剩余空间</td><td id="oc-st-disk">-</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@ -147,6 +149,22 @@
|
||||
document.getElementById('oc-st-node').textContent = d.node_version || '未安装';
|
||||
document.getElementById('oc-st-oc-ver').textContent = d.oc_version ? ('v' + d.oc_version) : '未安装';
|
||||
document.getElementById('oc-st-plugin').textContent = d.plugin_version ? ('v' + d.plugin_version) : '-';
|
||||
|
||||
// 安装路径和剩余空间
|
||||
var pathEl = document.getElementById('oc-st-path');
|
||||
if (d.install_path) {
|
||||
pathEl.innerHTML = '<code style="padding:2px 8px;background:#f0f3f6;border-radius:4px;font-size:12px;">' + d.install_path + '</code>';
|
||||
} else {
|
||||
pathEl.textContent = '-';
|
||||
}
|
||||
|
||||
// 剩余空间
|
||||
var diskEl = document.getElementById('oc-st-disk');
|
||||
if (d.disk_free) {
|
||||
diskEl.innerHTML = '<span style="color:#1a7f37;font-weight:500;">' + d.disk_free + '</span> 可用';
|
||||
} else {
|
||||
diskEl.textContent = '-';
|
||||
}
|
||||
} catch(e) {
|
||||
document.getElementById('oc-st-status').innerHTML = '<span class="oc-badge oc-badge-unknown">查询失败</span>';
|
||||
}
|
||||
|
||||
@ -4,3 +4,4 @@ config openclaw 'main'
|
||||
option bind 'lan'
|
||||
option token ''
|
||||
option pty_port '18793'
|
||||
option install_path '/opt'
|
||||
|
||||
@ -10,14 +10,21 @@ EXTRA_HELP=" setup 下载 Node.js 并安装 OpenClaw
|
||||
status_service 显示服务状态
|
||||
restart_gateway 仅重启 Gateway 实例 (不影响 Web PTY)"
|
||||
|
||||
NODE_BASE="/opt/openclaw/node"
|
||||
OC_GLOBAL="/opt/openclaw/global"
|
||||
OC_DATA="/opt/openclaw/data"
|
||||
# ── 安装路径 (支持自定义) ──
|
||||
# 从 UCI 配置读取自定义路径,默认为 /opt
|
||||
# 程序会在此路径下自动创建 openclaw 目录
|
||||
OC_BASE_PATH="$(uci -q get openclaw.main.install_path || echo '/opt')"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
NODE_BASE="${OC_INSTALL_PATH}/node"
|
||||
OC_GLOBAL="${OC_INSTALL_PATH}/global"
|
||||
OC_DATA="${OC_INSTALL_PATH}/data"
|
||||
|
||||
# ── OverlayFS 兼容性修复 ──
|
||||
# Docker bind mount (/overlay/upper/opt/docker) 会导致 /opt 不可写
|
||||
# 解决: bind mount upper 层的 /opt 到合并视图的 /opt
|
||||
# 注意: 仅当基础路径为 /opt 时才需要此修复
|
||||
_oc_fix_opt() {
|
||||
[ "$OC_BASE_PATH" != "/opt" ] && return 0
|
||||
mkdir -p /opt/openclaw/.probe 2>/dev/null && { rmdir /opt/openclaw/.probe 2>/dev/null; return 0; }
|
||||
if [ -d /overlay/upper/opt ]; then
|
||||
mkdir -p /overlay/upper/opt/openclaw 2>/dev/null
|
||||
|
||||
@ -2,12 +2,17 @@
|
||||
# ============================================================================
|
||||
# luci-app-openclaw — 全局环境变量
|
||||
# 仅在 Node.js 已安装时生效,为 SSH 登录用户提供正确的运行环境
|
||||
# 解决 Issue #42: 统一配置文件路径,避免 /root/.openclaw 与 /opt/openclaw/data/.openclaw 混乱
|
||||
# 解决 Issue #42: 统一配置文件路径,避免 /root/.openclaw 与安装路径混乱
|
||||
# 支持自定义安装路径
|
||||
# ============================================================================
|
||||
|
||||
NODE_BASE="/opt/openclaw/node"
|
||||
OC_GLOBAL="/opt/openclaw/global"
|
||||
OC_DATA="/opt/openclaw/data"
|
||||
# 从 UCI 配置读取自定义安装路径
|
||||
# 用户配置的是基础路径,程序会在此路径下创建 openclaw 目录
|
||||
OC_BASE_PATH="$(uci -q get openclaw.main.install_path 2>/dev/null || echo '/opt')"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
NODE_BASE="${OC_INSTALL_PATH}/node"
|
||||
OC_GLOBAL="${OC_INSTALL_PATH}/global"
|
||||
OC_DATA="${OC_INSTALL_PATH}/data"
|
||||
|
||||
# 检查 Node.js 是否已安装
|
||||
[ -x "${NODE_BASE}/bin/node" ] || return 0
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
#!/bin/sh
|
||||
# luci-app-openclaw — 首次安装/升级初始化脚本
|
||||
|
||||
# 获取安装路径 (支持自定义)
|
||||
# 用户配置的是基础路径,程序会在此路径下创建 openclaw 目录
|
||||
OC_BASE_PATH="$(uci -q get openclaw.main.install_path || echo '/opt')"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
|
||||
# ── v1.0.16: 清理错误路径下的配置文件 (Issue #42) ──
|
||||
# 用户在 SSH 中直接运行 openclaw 命令时,可能创建了 /root/.openclaw/ 目录
|
||||
# 需要迁移数据并清理,避免路径混乱
|
||||
if [ -d "/root/.openclaw" ]; then
|
||||
OC_DATA="/opt/openclaw/data"
|
||||
OC_DATA="${OC_INSTALL_PATH}/data"
|
||||
# 迁移 skills 目录 (如果存在且目标不存在)
|
||||
if [ -d "/root/.openclaw/skills" ] && [ ! -d "${OC_DATA}/.openclaw/skills" ]; then
|
||||
mkdir -p "${OC_DATA}/.openclaw"
|
||||
@ -41,7 +46,7 @@ if ! id openclaw >/dev/null 2>&1; then
|
||||
done
|
||||
# OpenWrt 方式:直接写入 /etc/passwd 和 /etc/shadow
|
||||
if ! grep -q '^openclaw:' /etc/passwd 2>/dev/null; then
|
||||
echo "openclaw:x:${OC_UID}:${OC_GID}:openclaw:/opt/openclaw/data:/bin/false" >> /etc/passwd
|
||||
echo "openclaw:x:${OC_UID}:${OC_GID}:openclaw:${OC_INSTALL_PATH}/data:/bin/false" >> /etc/passwd
|
||||
fi
|
||||
if ! grep -q '^openclaw:' /etc/shadow 2>/dev/null; then
|
||||
echo 'openclaw:x:0:0:99999:7:::' >> /etc/shadow
|
||||
@ -52,20 +57,22 @@ if ! id openclaw >/dev/null 2>&1; then
|
||||
fi
|
||||
|
||||
# 创建数据目录
|
||||
# ── OverlayFS 兼容: Docker bind mount 可能导致 /opt 不可写 ──
|
||||
if ! mkdir -p /opt/openclaw/.probe 2>/dev/null; then
|
||||
if [ -d /overlay/upper/opt ]; then
|
||||
mkdir -p /overlay/upper/opt/openclaw 2>/dev/null
|
||||
mount --bind /overlay/upper/opt /opt 2>/dev/null
|
||||
# ── OverlayFS 兼容: Docker bind mount 可能导致 /opt 不可写 (仅当基础路径为 /opt 时) ──
|
||||
if [ "$OC_BASE_PATH" = "/opt" ]; then
|
||||
if ! mkdir -p /opt/openclaw/.probe 2>/dev/null; then
|
||||
if [ -d /overlay/upper/opt ]; then
|
||||
mkdir -p /overlay/upper/opt/openclaw 2>/dev/null
|
||||
mount --bind /overlay/upper/opt /opt 2>/dev/null
|
||||
fi
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
else
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
fi
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
else
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
fi
|
||||
mkdir -p /opt/openclaw/data/.openclaw
|
||||
mkdir -p /opt/openclaw/node
|
||||
mkdir -p /opt/openclaw/global
|
||||
chown -R openclaw:openclaw /opt/openclaw 2>/dev/null || true
|
||||
mkdir -p "${OC_INSTALL_PATH}/data/.openclaw"
|
||||
mkdir -p "${OC_INSTALL_PATH}/node"
|
||||
mkdir -p "${OC_INSTALL_PATH}/global"
|
||||
chown -R openclaw:openclaw "${OC_INSTALL_PATH}" 2>/dev/null || true
|
||||
|
||||
# 生成随机 Token (如果尚未设置)
|
||||
CURRENT_TOKEN=$(uci -q get openclaw.main.token)
|
||||
|
||||
@ -22,15 +22,25 @@ NODE_VERSION="${NODE_VERSION:-${NODE_VERSION_V2}}"
|
||||
OC_TESTED_VERSION="2026.3.28"
|
||||
# 用户可通过 OC_VERSION 环境变量覆盖安装版本
|
||||
OC_VERSION="${OC_VERSION:-}"
|
||||
NODE_BASE="/opt/openclaw/node"
|
||||
OC_GLOBAL="/opt/openclaw/global"
|
||||
OC_DATA="/opt/openclaw/data"
|
||||
|
||||
# ── 安装路径 (支持自定义) ──
|
||||
# 从 UCI 配置读取自定义路径,默认为 /opt
|
||||
# 用户可在 LuCI 界面或通过 uci set openclaw.main.install_path=/mnt/data 设置
|
||||
# 程序会在此路径下自动创建 openclaw 目录
|
||||
OC_BASE_PATH="${OC_INSTALL_PATH:-$(uci -q get openclaw.main.install_path || echo '/opt')}"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
NODE_BASE="${OC_INSTALL_PATH}/node"
|
||||
OC_GLOBAL="${OC_INSTALL_PATH}/global"
|
||||
OC_DATA="${OC_INSTALL_PATH}/data"
|
||||
|
||||
# ── OverlayFS 兼容性修复 ──
|
||||
# iStoreOS/OpenWrt 上 Docker 的 bind mount (/overlay/upper/opt/docker)
|
||||
# 会导致 OverlayFS 合并视图中 /opt 完全不可写 (mkdir 报 "Directory not empty")。
|
||||
# 解决方案: 将 /overlay/upper/opt bind mount 到 /opt,绕过 OverlayFS 冲突。
|
||||
# 注意: 仅当基础路径为 /opt 时才需要此修复
|
||||
_oc_fix_opt() {
|
||||
# 如果基础路径不是 /opt,无需修复
|
||||
[ "$OC_BASE_PATH" != "/opt" ] && return 0
|
||||
# 如果 /opt 可正常写入,无需修复
|
||||
if mkdir -p /opt/openclaw/.probe 2>/dev/null; then
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
@ -97,7 +107,7 @@ find_oc_entry() {
|
||||
${OC_GLOBAL}/node_modules/openclaw
|
||||
${NODE_BASE}/lib/node_modules/openclaw"
|
||||
|
||||
# 添加 pnpm 版本化目录 (如 /opt/openclaw/global/5/node_modules/openclaw)
|
||||
# 添加 pnpm 版本化目录 (如 $OC_GLOBAL/5/node_modules/openclaw)
|
||||
for ver_dir in "${OC_GLOBAL}"/*/node_modules/openclaw; do
|
||||
[ -d "$ver_dir" ] 2>/dev/null && search_dirs="$search_dirs
|
||||
$ver_dir"
|
||||
@ -439,7 +449,7 @@ do_setup() {
|
||||
else
|
||||
echo " OpenClaw: 最新版"
|
||||
fi
|
||||
echo " 安装路径: ${NODE_BASE}"
|
||||
echo " 安装路径: ${OC_INSTALL_PATH}"
|
||||
echo " 数据路径: ${OC_DATA}"
|
||||
echo ""
|
||||
|
||||
@ -493,10 +503,11 @@ do_check() {
|
||||
echo " 配置: 未初始化"
|
||||
fi
|
||||
|
||||
# 磁盘使用
|
||||
# 磁盘使用 (检测实际安装路径)
|
||||
local used
|
||||
used=$(du -sh /opt/openclaw 2>/dev/null | awk '{print $1}')
|
||||
used=$(du -sh "$OC_INSTALL_PATH" 2>/dev/null | awk '{print $1}')
|
||||
echo " 磁盘: ${used:-N/A}"
|
||||
echo " 安装路径: ${OC_INSTALL_PATH}"
|
||||
|
||||
# libc 类型
|
||||
echo " C库: $(detect_libc)"
|
||||
@ -651,7 +662,7 @@ do_setup_offline() {
|
||||
echo "╚══════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo " 架构: $(uname -m)"
|
||||
echo " 安装路径: ${NODE_BASE}"
|
||||
echo " 安装路径: ${OC_INSTALL_PATH}"
|
||||
echo " 数据路径: ${OC_DATA}"
|
||||
echo " 离线包: ${offline_dir}"
|
||||
echo ""
|
||||
|
||||
@ -28,10 +28,14 @@ get_pid_by_port() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 路径 (OpenWrt 适配) ──
|
||||
NODE_BASE="${NODE_BASE:-/opt/openclaw/node}"
|
||||
OC_GLOBAL="${OC_GLOBAL:-/opt/openclaw/global}"
|
||||
OC_DATA="${OC_DATA:-/opt/openclaw/data}"
|
||||
# ── 路径 (OpenWrt 适配,支持自定义安装路径) ──
|
||||
# 从 UCI 配置读取自定义路径,环境变量可覆盖
|
||||
# 用户配置的是基础路径,程序会在此路径下创建 openclaw 目录
|
||||
OC_BASE_PATH="${OC_INSTALL_PATH:-$(uci -q get openclaw.main.install_path 2>/dev/null || echo '/opt')}"
|
||||
OC_INSTALL_PATH="${OC_BASE_PATH}/openclaw"
|
||||
NODE_BASE="${NODE_BASE:-${OC_INSTALL_PATH}/node}"
|
||||
OC_GLOBAL="${OC_GLOBAL:-${OC_INSTALL_PATH}/global}"
|
||||
OC_DATA="${OC_DATA:-${OC_INSTALL_PATH}/data}"
|
||||
NODE_BIN="${NODE_BASE}/bin/node"
|
||||
OC_STATE_DIR="${OC_DATA}/.openclaw"
|
||||
CONFIG_FILE="${OC_STATE_DIR}/openclaw.json"
|
||||
@ -99,7 +103,7 @@ json_set() {
|
||||
local parent_dir="$(dirname "$CONFIG_FILE")"
|
||||
if ! mkdir -p "$parent_dir" 2>/dev/null; then
|
||||
echo "ERROR: 无法创建配置目录 $parent_dir" >&2
|
||||
echo "HINT: 请检查 /opt/openclaw/data 是否存在且有写权限" >&2
|
||||
echo "HINT: 请检查 $OC_DATA 是否存在且有写权限" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
@ -2428,7 +2432,7 @@ backup_restore_menu() {
|
||||
# 提取 payload 到根目录 (还原到原始绝对路径)
|
||||
tar -xzf "$latest" --strip-components=3 -C / "${backup_name}/payload/posix/" 2>&1
|
||||
# 修复权限
|
||||
chown -R openclaw:openclaw /opt/openclaw/data/.openclaw 2>/dev/null
|
||||
chown -R openclaw:openclaw "$OC_STATE_DIR" 2>/dev/null
|
||||
echo -e " ${GREEN}✅ 配置和数据已完整恢复!原配置已保存为 openclaw.json.pre-restore${NC}"
|
||||
echo ""
|
||||
prompt_with_default "是否重启服务使配置生效? (Y/n)" "Y" do_restart
|
||||
|
||||
@ -17,9 +17,16 @@ const os = require('os');
|
||||
// ── 配置 (OpenWrt 适配) ──
|
||||
const PORT = parseInt(process.env.OC_CONFIG_PORT || '18793', 10);
|
||||
const HOST = process.env.OC_CONFIG_HOST || '0.0.0.0'; // token 认证保护,可安全绑定所有接口
|
||||
const NODE_BASE = process.env.NODE_BASE || '/opt/openclaw/node';
|
||||
const OC_GLOBAL = process.env.OC_GLOBAL || '/opt/openclaw/global';
|
||||
const OC_DATA = process.env.OC_DATA || '/opt/openclaw/data';
|
||||
// 从 UCI 读取安装路径,默认为 /opt/openclaw
|
||||
const { execSync } = require('child_process');
|
||||
let installPath = '/opt/openclaw';
|
||||
try {
|
||||
const uciPath = execSync('uci -q get openclaw.main.install_path 2>/dev/null', { encoding: 'utf8', timeout: 3000 }).trim();
|
||||
if (uciPath) installPath = uciPath + '/openclaw';
|
||||
} catch {}
|
||||
const NODE_BASE = process.env.NODE_BASE || installPath + '/node';
|
||||
const OC_GLOBAL = process.env.OC_GLOBAL || installPath + '/global';
|
||||
const OC_DATA = process.env.OC_DATA || installPath + '/data';
|
||||
const SCRIPT_PATH = process.env.OC_CONFIG_SCRIPT || '/usr/share/openclaw/oc-config.sh';
|
||||
const SSL_CERT = '/etc/uhttpd.crt';
|
||||
const SSL_KEY = '/etc/uhttpd.key';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user