mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-03 02:23:56 +08:00
🚀 Sync 2026-03-18 20:29:42
This commit is contained in:
1 parent
c62c96aa04
commit
79996b4e00
212 files changed
+6047
-30308
No files matched your search
@@ -1,12 +1,12 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_VERSION:=0.1.0
|
||||
PKG_RELEASE:=2
|
||||
PKG_VERSION:=0.1.1
|
||||
PKG_RELEASE:=3
|
||||
|
||||
LUCI_TITLE:=LuCI support for OpenClaw Launcher
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+luci-base +luci-compat +luci-lib-taskd +curl +ca-bundle +tar +xz-utils +jsonfilter
|
||||
LUCI_DEPENDS:=+luci-base +luci-compat +luci-lib-taskd +curl +ca-bundle +tar +xz-utils +jsonfilter +git +git-http
|
||||
|
||||
define Package/luci-app-openclawmgr/conffiles
|
||||
/etc/config/openclawmgr
|
||||
|
||||
@@ -34,11 +34,12 @@
|
||||
activeTab: "basic",
|
||||
savingSection: "",
|
||||
lastAppliedAt: "",
|
||||
showLogModal: false,
|
||||
logText: "",
|
||||
logTimer: null,
|
||||
statusTimer: null,
|
||||
installWatchTimer: null
|
||||
installWatchTimer: null,
|
||||
lastTaskRunning: false,
|
||||
taskLogOpenTs: 0,
|
||||
consoleReady: false,
|
||||
consoleCheckTimer: null
|
||||
};
|
||||
var styleText = "";
|
||||
|
||||
@@ -247,45 +248,22 @@
|
||||
'</svg>';
|
||||
}
|
||||
|
||||
function openLogModal() {
|
||||
state.showLogModal = true;
|
||||
if (state.logTimer) {
|
||||
window.clearTimeout(state.logTimer);
|
||||
state.logTimer = null;
|
||||
}
|
||||
pollLogs();
|
||||
render();
|
||||
function taskWindowAvailable() {
|
||||
return !!(window.taskd && window.taskd.show_log);
|
||||
}
|
||||
|
||||
function closeLogModal() {
|
||||
state.showLogModal = false;
|
||||
if (state.logTimer) {
|
||||
window.clearTimeout(state.logTimer);
|
||||
state.logTimer = null;
|
||||
}
|
||||
refreshStatus();
|
||||
}
|
||||
|
||||
function pollLogs() {
|
||||
if (!state.showLogModal) {
|
||||
function showTaskLog(taskId) {
|
||||
taskId = taskId || "openclawmgr";
|
||||
if (!taskWindowAvailable()) {
|
||||
window.alert("任务窗口不可用(未加载 taskd/xterm)。请安装 luci-lib-taskd 和 luci-lib-xterm,然后强制刷新页面。");
|
||||
return;
|
||||
}
|
||||
if (state.logTimer) {
|
||||
window.clearTimeout(state.logTimer);
|
||||
state.logTimer = null;
|
||||
var now = Date.now ? Date.now() : (+new Date());
|
||||
if (state.taskLogOpenTs && now - state.taskLogOpenTs < 1500) {
|
||||
return;
|
||||
}
|
||||
request(config.logUrl + "?n=200").then(function(data) {
|
||||
state.logText = (data && data.log) || "";
|
||||
refreshStatus(function() {
|
||||
if (state.showLogModal) {
|
||||
state.logTimer = window.setTimeout(pollLogs, 3000);
|
||||
}
|
||||
});
|
||||
}).catch(function() {
|
||||
if (state.showLogModal) {
|
||||
state.logTimer = window.setTimeout(pollLogs, 5000);
|
||||
}
|
||||
});
|
||||
state.taskLogOpenTs = now;
|
||||
window.taskd.show_log(taskId);
|
||||
}
|
||||
|
||||
function stopStatusPolling() {
|
||||
@@ -302,6 +280,41 @@
|
||||
}
|
||||
}
|
||||
|
||||
function stopConsoleCheck() {
|
||||
if (state.consoleCheckTimer) {
|
||||
window.clearTimeout(state.consoleCheckTimer);
|
||||
state.consoleCheckTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function pollConsoleReady(rounds) {
|
||||
rounds = typeof rounds === "number" ? rounds : 20;
|
||||
stopConsoleCheck();
|
||||
state.consoleReady = false;
|
||||
|
||||
function tick(remaining) {
|
||||
request(config.readyUrl).then(function(rv) {
|
||||
state.consoleReady = !!(rv && rv.ok && rv.ready);
|
||||
render();
|
||||
if (!state.consoleReady && remaining > 1) {
|
||||
state.consoleCheckTimer = window.setTimeout(function() { tick(remaining - 1); }, 1000);
|
||||
} else {
|
||||
state.consoleCheckTimer = null;
|
||||
}
|
||||
}).catch(function() {
|
||||
state.consoleReady = false;
|
||||
render();
|
||||
if (remaining > 1) {
|
||||
state.consoleCheckTimer = window.setTimeout(function() { tick(remaining - 1); }, 1500);
|
||||
} else {
|
||||
state.consoleCheckTimer = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tick(rounds);
|
||||
}
|
||||
|
||||
function backgroundStatusDelay(status) {
|
||||
if (status && status.installing) {
|
||||
return 3000;
|
||||
@@ -317,9 +330,6 @@
|
||||
|
||||
function ensureInstallWatch() {
|
||||
stopInstallWatch();
|
||||
if (state.status && state.status.installing && state.showLogModal) {
|
||||
return;
|
||||
}
|
||||
state.installWatchTimer = window.setTimeout(function() {
|
||||
refreshStatus(function() {
|
||||
ensureInstallWatch();
|
||||
@@ -347,16 +357,6 @@
|
||||
tick(rounds);
|
||||
}
|
||||
|
||||
function scrollLogToBottom() {
|
||||
if (!state.showLogModal) {
|
||||
return;
|
||||
}
|
||||
var body = root.querySelector(".oclm-log-body");
|
||||
if (body) {
|
||||
body.scrollTop = body.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
var status = state.status || {};
|
||||
var form = state.form || {};
|
||||
@@ -381,6 +381,12 @@
|
||||
var savingBasic = state.savingSection === "basic";
|
||||
var savingAccess = state.savingSection === "access";
|
||||
|
||||
var serviceButtons = showServiceActions ? (
|
||||
(!status.running ? '<button class="oclm-button" type="button" data-op="start">启动服务</button>' : '') +
|
||||
(status.running ? '<button class="oclm-button" type="button" data-op="stop">停止服务</button>' : '') +
|
||||
'<button class="oclm-button" type="button" data-op="restart">重启服务</button>'
|
||||
) : '';
|
||||
|
||||
root.innerHTML =
|
||||
'<style>' + styleText + '</style>' +
|
||||
'<div class="oclm-app"' + (detectDarkMode() ? ' data-darkmode="true"' : '') + '>' +
|
||||
@@ -403,10 +409,7 @@
|
||||
'</div>' +
|
||||
'<div class="oclm-status-actions">' +
|
||||
(showInstallAction ? '<div class="oclm-install-inline"><button class="oclm-button oclm-button-primary" type="button" data-install-action="1">' + installLabel + '</button><label class="oclm-check"><input type="checkbox" id="oclm-install-accelerated"' + (installAcceleratedChecked ? ' checked' : '') + ' />Kspeeder 加速安装</label></div>' : '') +
|
||||
(status.running ? '<a class="oclm-button oclm-button-primary" href="' + escapeAttr(status.token_url || "#") + '" target="_blank" rel="noreferrer">' + openclawIcon("oclm-button-icon") + '打开控制台</a>' : '') +
|
||||
(!status.running && showServiceActions ? '<button class="oclm-button" type="button" data-op="start">启动服务</button>' : '') +
|
||||
(status.running && showServiceActions ? '<button class="oclm-button" type="button" data-op="stop">停止服务</button>' : '') +
|
||||
(showServiceActions ? '<button class="oclm-button" type="button" data-op="restart">重启服务</button>' : '') +
|
||||
(status.running ? '<button class="oclm-button oclm-button-primary" type="button" data-open-console="1"' + (state.consoleReady ? '' : ' disabled') + '>' + openclawIcon("oclm-button-icon") + (state.consoleReady ? '打开控制台' : '控制台准备中…') + '</button>' : '') +
|
||||
(status.installing ? '<button class="oclm-button oclm-button-danger" type="button" data-op="cancel_install">停止安装</button>' : '') +
|
||||
'</div>' +
|
||||
(status.installing ? '<div class="oclm-status-note">安装任务正在后台运行,点击“安装中”可继续查看日志。</div>' : '') +
|
||||
@@ -421,7 +424,6 @@
|
||||
'<div class="' + (activeTab === "basic" ? '' : 'oclm-hidden') + '">' +
|
||||
'<h2>基础配置</h2>' +
|
||||
'<div class="oclm-form-grid">' +
|
||||
fieldToggle("启用服务", "enabled", form.enabled) +
|
||||
fieldInput("监听端口", '<input class="oclm-control" type="number" min="1" max="65535" id="oclm-port" value="' + escapeHtml(form.port || "18789") + '" />') +
|
||||
fieldInput("监听范围", selectHtml("oclm-bind", form.bind, [
|
||||
["lan", "所有地址"],
|
||||
@@ -438,7 +440,7 @@
|
||||
fieldInput("API 密钥", passwordHtml("oclm-api-key", form.provider_api_key || "", "sk-...")) +
|
||||
fieldInput("中转地址(可选)", '<input class="oclm-control" type="text" id="oclm-base-url" value="' + escapeHtml(form.provider_base_url || "") + '" placeholder="https://api.example.com" />') +
|
||||
fieldInput("默认模型", '<input class="oclm-control" type="text" id="oclm-model" value="' + escapeAttr(resolveModelValue(form)) + '" placeholder="请按照<provider>/<model-id>格式填写" />') +
|
||||
'<div class="oclm-section-submit"><button class="oclm-button oclm-button-primary" type="button" id="oclm-save-basic"' + (savingBasic ? ' disabled' : '') + '>' + (savingBasic ? '应用中…' : '保存并应用') + '</button>' + (state.lastAppliedAt ? '<span class="oclm-applied-hint">已于 ' + escapeHtml(state.lastAppliedAt) + ' 更新配置</span>' : '') + '</div>' +
|
||||
'<div class="oclm-section-submit"><button class="oclm-button oclm-button-primary" type="button" id="oclm-save-basic"' + (savingBasic ? ' disabled' : '') + '>' + (savingBasic ? '应用中…' : '保存并应用') + '</button>' + serviceButtons + (state.lastAppliedAt ? '<span class="oclm-applied-hint">已于 ' + escapeHtml(state.lastAppliedAt) + ' 更新配置</span>' : '') + '</div>' +
|
||||
'</div></div>' +
|
||||
|
||||
'<div class="' + (activeTab === "access" ? '' : 'oclm-hidden') + '">' +
|
||||
@@ -463,27 +465,9 @@
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</section>' +
|
||||
|
||||
(state.showLogModal ? (
|
||||
'<div class="oclm-log-modal" data-close-log="1">' +
|
||||
'<div class="oclm-log-dialog" onclick="event.stopPropagation()">' +
|
||||
'<div class="oclm-log-head">' +
|
||||
'<h3>安装日志</h3>' +
|
||||
'<div class="oclm-log-actions">' +
|
||||
'<button class="oclm-button" type="button" data-refresh-log="1">刷新</button>' +
|
||||
'<button class="oclm-button" type="button" data-copy-log="1">复制日志</button>' +
|
||||
'<button class="oclm-button" type="button" data-close-log-btn="1">关闭</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="oclm-log-body"><pre>' + escapeHtml(state.logText || "日志为空") + '</pre></div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
) : '') +
|
||||
|
||||
'</div></div></div>';
|
||||
|
||||
bindEvents();
|
||||
scrollLogToBottom();
|
||||
}
|
||||
|
||||
function fieldInput(label, control) {
|
||||
@@ -547,18 +531,45 @@
|
||||
if (op === "purge" && !window.confirm("彻底清理会删除运行时和数据目录。确认继续?")) return;
|
||||
postForm(config.opUrl, { op: op }).then(function(rv) {
|
||||
if (!rv || !rv.ok) {
|
||||
if (rv && rv.busy && rv.running_task_id) {
|
||||
showTaskLog(rv.running_task_id);
|
||||
return;
|
||||
}
|
||||
window.alert((rv && rv.error) || "操作失败");
|
||||
return;
|
||||
}
|
||||
state.lastTaskRunning = true;
|
||||
showTaskLog((rv && (rv.running_task_id || rv.task_id)) || "openclawmgr");
|
||||
scheduleStatusRefresh(op === "restart" ? 8 : 6, 1000);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(root.querySelectorAll("[data-open-console]"), function(el) {
|
||||
el.onclick = function() {
|
||||
if (!state.consoleReady) {
|
||||
window.alert("控制台正在启动,请稍候再试。");
|
||||
return;
|
||||
}
|
||||
var url = (state.status && state.status.token_url) || "";
|
||||
if (!url) {
|
||||
window.alert("控制台地址不可用");
|
||||
return;
|
||||
}
|
||||
window.open(url, "_blank", "noreferrer");
|
||||
};
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(root.querySelectorAll("[data-install-action]"), function(el) {
|
||||
el.onclick = function() {
|
||||
openLogModal();
|
||||
var accelerated = !!(root.getElementById("oclm-install-accelerated") && root.getElementById("oclm-install-accelerated").checked);
|
||||
var baseDirEl = root.getElementById("oclm-base-dir");
|
||||
var baseDir = baseDirEl && baseDirEl.value ? baseDirEl.value.trim() : "";
|
||||
if (!baseDir) {
|
||||
window.alert("请先选择数据目录并保存应用,再执行安装。");
|
||||
if (baseDirEl) baseDirEl.focus();
|
||||
return;
|
||||
}
|
||||
if (!state.status || state.status.installing) {
|
||||
return;
|
||||
}
|
||||
@@ -566,7 +577,7 @@
|
||||
state.status.task_running = true;
|
||||
state.status.task_op = "install";
|
||||
render();
|
||||
postJson(config.configUrl, { install_accelerated: accelerated }).then(function(cfgRv) {
|
||||
postJson(config.configUrl, { base_dir: baseDir, install_accelerated: accelerated }).then(function(cfgRv) {
|
||||
if (!cfgRv || !cfgRv.ok) {
|
||||
state.status.installing = false;
|
||||
render();
|
||||
@@ -574,15 +585,22 @@
|
||||
return;
|
||||
}
|
||||
state.form.install_accelerated = accelerated;
|
||||
state.form.base_dir = baseDir;
|
||||
return postForm(config.opUrl, { op: "install" });
|
||||
}).then(function(rv) {
|
||||
if (!rv) return;
|
||||
if (!rv || !rv.ok) {
|
||||
if (rv && rv.busy && rv.running_task_id) {
|
||||
showTaskLog(rv.running_task_id);
|
||||
return;
|
||||
}
|
||||
state.status.installing = false;
|
||||
render();
|
||||
window.alert((rv && rv.error) || "启动安装失败");
|
||||
return;
|
||||
}
|
||||
state.lastTaskRunning = true;
|
||||
showTaskLog((rv && (rv.running_task_id || rv.task_id)) || "openclawmgr");
|
||||
scheduleStatusRefresh(10, 1000);
|
||||
}).catch(function() {
|
||||
state.status.installing = false;
|
||||
@@ -592,12 +610,6 @@
|
||||
};
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(root.querySelectorAll("[data-close-log], [data-close-log-btn]"), function(el) {
|
||||
el.onclick = function() {
|
||||
closeLogModal();
|
||||
};
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(root.querySelectorAll("[data-toggle-password]"), function(el) {
|
||||
el.onclick = function() {
|
||||
var id = el.getAttribute("data-toggle-password");
|
||||
@@ -616,18 +628,6 @@
|
||||
};
|
||||
}
|
||||
|
||||
Array.prototype.forEach.call(root.querySelectorAll("[data-refresh-log]"), function(el) {
|
||||
el.onclick = function() {
|
||||
pollLogs();
|
||||
};
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(root.querySelectorAll("[data-copy-log]"), function(el) {
|
||||
el.onclick = function() {
|
||||
copyText(state.logText || "");
|
||||
};
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(root.querySelectorAll("[data-copy-token-url]"), function(el) {
|
||||
el.onclick = function() {
|
||||
var value = (state.status && (state.status.token_url || state.status.base_url)) || "";
|
||||
@@ -687,7 +687,6 @@
|
||||
if (saveBasic) {
|
||||
saveBasic.onclick = function() {
|
||||
var payload = {
|
||||
enabled: !!root.getElementById("oclm-enabled").checked,
|
||||
port: root.getElementById("oclm-port").value,
|
||||
bind: root.getElementById("oclm-bind").value,
|
||||
base_dir: root.getElementById("oclm-base-dir").value,
|
||||
@@ -759,6 +758,18 @@
|
||||
function refreshStatus(done) {
|
||||
request(config.statusUrl).then(function(data) {
|
||||
state.status = data || {};
|
||||
if (state.status && state.status.running) {
|
||||
if (!state.consoleReady) {
|
||||
pollConsoleReady(20);
|
||||
}
|
||||
} else {
|
||||
stopConsoleCheck();
|
||||
state.consoleReady = false;
|
||||
}
|
||||
if (state.status && state.status.task_running && !state.lastTaskRunning) {
|
||||
showTaskLog("openclawmgr");
|
||||
}
|
||||
state.lastTaskRunning = !!(state.status && state.status.task_running);
|
||||
render();
|
||||
ensureInstallWatch();
|
||||
if (typeof done === "function") {
|
||||
@@ -782,6 +793,12 @@
|
||||
state.form = data.config || {};
|
||||
state.form.default_model = resolveModelValue(state.form);
|
||||
state.options = data.options || {};
|
||||
if (!state.form.base_dir) {
|
||||
var suggested = state.options && state.options.suggested_base_dir ? String(state.options.suggested_base_dir) : "";
|
||||
if (suggested) {
|
||||
state.form.base_dir = suggested;
|
||||
}
|
||||
}
|
||||
render();
|
||||
refreshStatus();
|
||||
}).catch(function() {
|
||||
|
||||
@@ -11,10 +11,10 @@ function index()
|
||||
page.leaf = true
|
||||
|
||||
entry({"admin", "services", "openclawmgr", "status"}, call("action_status")).leaf = true
|
||||
entry({"admin", "services", "openclawmgr", "ready"}, call("action_ready")).leaf = true
|
||||
entry({"admin", "services", "openclawmgr", "op"}, call("action_op")).leaf = true
|
||||
entry({"admin", "services", "openclawmgr", "config_data"}, call("action_config_data")).leaf = true
|
||||
entry({"admin", "services", "openclawmgr", "apply_config"}, call("action_apply_config")).leaf = true
|
||||
entry({"admin", "services", "openclawmgr", "log"}, call("action_log")).leaf = true
|
||||
|
||||
entry({"admin", "services", "openclawmgr", "diag_info"}, call("action_diag_info")).leaf = true
|
||||
entry({"admin", "services", "openclawmgr", "diag_run"}, call("action_diag_run")).leaf = true
|
||||
@@ -181,7 +181,10 @@ end
|
||||
|
||||
local function configured_base_path(base_dir)
|
||||
local jsonc = require "luci.jsonc"
|
||||
local path = (base_dir or "/opt/openclawmgr") .. "/data/.openclaw/openclaw.json"
|
||||
if type(base_dir) ~= "string" or base_dir == "" then
|
||||
return "/"
|
||||
end
|
||||
local path = base_dir .. "/data/.openclaw/openclaw.json"
|
||||
local f = io.open(path, "r")
|
||||
if not f then
|
||||
return "/"
|
||||
@@ -307,29 +310,40 @@ function action_status()
|
||||
local enabled = uci:get("openclawmgr", "main", "enabled") or "0"
|
||||
local port = uci:get("openclawmgr", "main", "port") or "18789"
|
||||
local bind = uci:get("openclawmgr", "main", "bind") or "lan"
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or "/opt/openclawmgr"
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or ""
|
||||
local token = uci:get("openclawmgr", "main", "token") or ""
|
||||
|
||||
if not port:match("^%d+$") then port = "18789" end
|
||||
|
||||
local st = sys.exec("/usr/libexec/istorec/openclawmgr.sh status 2>/dev/null"):gsub("%s+$", "")
|
||||
local running = (st == "running")
|
||||
local installed = (st == "running" or st == "stopped")
|
||||
local running = false
|
||||
local installed = false
|
||||
if base_dir ~= "" then
|
||||
local st = sys.exec("/usr/libexec/istorec/openclawmgr.sh status 2>/dev/null"):gsub("%s+$", "")
|
||||
running = (st == "running")
|
||||
installed = (st == "running" or st == "stopped")
|
||||
end
|
||||
local lock_running, lock_pid = installer_lock_running()
|
||||
local installing = (task.running and (task.op == "install" or task.op == "upgrade")) or lock_running
|
||||
if not installing and task.running and not installed and not running then
|
||||
installing = true
|
||||
end
|
||||
|
||||
local node_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh node_version 2>/dev/null"):gsub("%s+$", "")
|
||||
local oc_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh openclaw_version 2>/dev/null"):gsub("%s+$", "")
|
||||
local node_ver = ""
|
||||
local oc_ver = ""
|
||||
if base_dir ~= "" then
|
||||
node_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh node_version 2>/dev/null"):gsub("%s+$", "")
|
||||
oc_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh openclaw_version 2>/dev/null"):gsub("%s+$", "")
|
||||
end
|
||||
local pid = running and get_running_pid() or ""
|
||||
if pid == "" and installing and lock_pid ~= "" then
|
||||
pid = lock_pid
|
||||
end
|
||||
local uptime_human = running and get_pid_uptime_human(pid) or ""
|
||||
|
||||
local base_url = "http://" .. get_host() .. ":" .. port .. configured_base_path(base_dir)
|
||||
local base_url = ""
|
||||
if base_dir ~= "" then
|
||||
base_url = "http://" .. get_host() .. ":" .. port .. configured_base_path(base_dir)
|
||||
end
|
||||
local token_url = base_url
|
||||
if token ~= "" then
|
||||
token_url = token_url .. "#token=" .. token
|
||||
@@ -357,19 +371,36 @@ function action_status()
|
||||
})
|
||||
end
|
||||
|
||||
function action_log()
|
||||
function action_ready()
|
||||
local sys = require "luci.sys"
|
||||
local util = require "luci.util"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or "/opt/openclawmgr"
|
||||
local log_file = base_dir .. "/log/installer.log"
|
||||
|
||||
local n = tonumber((require "luci.http").formvalue("n") or "") or 200
|
||||
if n < 10 then n = 10 end
|
||||
if n > 2000 then n = 2000 end
|
||||
local port = uci:get("openclawmgr", "main", "port") or "18789"
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or ""
|
||||
|
||||
local content = sys.exec("tail -n " .. n .. " " .. util.shellquote(log_file) .. " 2>/dev/null") or ""
|
||||
write_json({ ok = true, log = content })
|
||||
if not port:match("^%d+$") then port = "18789" end
|
||||
|
||||
if base_dir == "" then
|
||||
write_json({ ok = true, ready = false, reason = "base_dir missing" })
|
||||
return
|
||||
end
|
||||
|
||||
local base_url = "http://127.0.0.1:" .. port .. configured_base_path(base_dir)
|
||||
local cmd = string.format(
|
||||
"curl -fsS -o /dev/null --connect-timeout 1 --max-time 2 -w '%%{http_code}' %s 2>/dev/null",
|
||||
util.shellquote(base_url)
|
||||
)
|
||||
local code = sys.exec(cmd):gsub("%s+$", "")
|
||||
local n = tonumber(code) or 0
|
||||
local ready = (n >= 200 and n < 400)
|
||||
|
||||
write_json({
|
||||
ok = true,
|
||||
ready = ready,
|
||||
http_code = code,
|
||||
url = base_url,
|
||||
})
|
||||
end
|
||||
|
||||
function action_apply_config()
|
||||
@@ -402,8 +433,8 @@ function action_config_data()
|
||||
return
|
||||
end
|
||||
|
||||
local body = read_json_body() or {}
|
||||
local section = "main"
|
||||
local body = read_json_body() or {}
|
||||
local section = "main"
|
||||
|
||||
local function bool_to_uci(value)
|
||||
return value and "1" or "0"
|
||||
@@ -513,7 +544,7 @@ function action_config_data()
|
||||
return
|
||||
end
|
||||
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or "/opt/openclawmgr"
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or ""
|
||||
local port = uci:get("openclawmgr", "main", "port") or "18789"
|
||||
local blocks = model.blocks()
|
||||
local home = model.home()
|
||||
@@ -528,11 +559,13 @@ function action_config_data()
|
||||
end
|
||||
end
|
||||
|
||||
add_choice(base_dir)
|
||||
if base_dir ~= "" then
|
||||
add_choice(base_dir)
|
||||
end
|
||||
for _, path in ipairs(paths or {}) do
|
||||
add_choice(path)
|
||||
end
|
||||
add_choice(default_path or "/opt/openclawmgr")
|
||||
add_choice(default_path or "/root/Configs/OpenClawMgr")
|
||||
|
||||
local allowed_origins = {}
|
||||
for _, item in ipairs(uci:get_list("openclawmgr", "main", "allowed_origins") or {}) do
|
||||
@@ -558,6 +591,7 @@ function action_config_data()
|
||||
},
|
||||
options = {
|
||||
base_dir_choices = choices,
|
||||
suggested_base_dir = default_path or "",
|
||||
default_origin = default_allowed_origin(port),
|
||||
}
|
||||
})
|
||||
@@ -665,22 +699,34 @@ function action_diag_info()
|
||||
local util = require "luci.util"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or "/opt/openclawmgr"
|
||||
local base_dir = uci:get("openclawmgr", "main", "base_dir") or ""
|
||||
local port = uci:get("openclawmgr", "main", "port") or "18789"
|
||||
local bind = uci:get("openclawmgr", "main", "bind") or "lan"
|
||||
local enabled = uci:get("openclawmgr", "main", "enabled") or "0"
|
||||
|
||||
if not port:match("^%d+$") then port = "18789" end
|
||||
|
||||
local df_kb = sys.exec("df -kP " .. util.shellquote(base_dir) .. " 2>/dev/null | awk 'NR==2{print $4}'"):gsub("%s+", "")
|
||||
local avail_mb = math.floor((tonumber(df_kb) or 0) / 1024)
|
||||
local avail_mb = 0
|
||||
if base_dir ~= "" then
|
||||
local df_kb = sys.exec("df -kP " .. util.shellquote(base_dir) .. " 2>/dev/null | awk 'NR==2{print $4}'"):gsub("%s+", "")
|
||||
avail_mb = math.floor((tonumber(df_kb) or 0) / 1024)
|
||||
end
|
||||
|
||||
local node_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh node_version 2>/dev/null"):gsub("%s+$", "")
|
||||
local oc_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh openclaw_version 2>/dev/null"):gsub("%s+$", "")
|
||||
local node_ver = ""
|
||||
local oc_ver = ""
|
||||
if base_dir ~= "" then
|
||||
node_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh node_version 2>/dev/null"):gsub("%s+$", "")
|
||||
oc_ver = sys.exec("/usr/libexec/istorec/openclawmgr.sh openclaw_version 2>/dev/null"):gsub("%s+$", "")
|
||||
end
|
||||
|
||||
local has_node = sys.call("[ -x " .. util.shellquote(base_dir .. "/node/bin/node") .. " ] >/dev/null 2>&1") == 0
|
||||
local has_openclaw = sys.call("[ -x " .. util.shellquote(base_dir .. "/global/bin/openclaw") .. " ] >/dev/null 2>&1") == 0
|
||||
local has_config = sys.call("[ -f " .. util.shellquote(base_dir .. "/data/.openclaw/openclaw.json") .. " ] >/dev/null 2>&1") == 0
|
||||
local has_node = false
|
||||
local has_openclaw = false
|
||||
local has_config = false
|
||||
if base_dir ~= "" then
|
||||
has_node = sys.call("[ -x " .. util.shellquote(base_dir .. "/node/bin/node") .. " ] >/dev/null 2>&1") == 0
|
||||
has_openclaw = sys.call("[ -x " .. util.shellquote(base_dir .. "/global/bin/openclaw") .. " ] >/dev/null 2>&1") == 0
|
||||
has_config = sys.call("[ -f " .. util.shellquote(base_dir .. "/data/.openclaw/openclaw.json") .. " ] >/dev/null 2>&1") == 0
|
||||
end
|
||||
|
||||
local default_gw = sys.exec("ip route 2>/dev/null | awk '/^default/{print $3; exit}' 2>/dev/null"):gsub("%s+", "")
|
||||
|
||||
@@ -709,9 +755,9 @@ function action_diag_info()
|
||||
has_config = has_config,
|
||||
procd_pid = pid,
|
||||
running = running,
|
||||
url = "http://" .. get_host() .. ":" .. port .. configured_base_path(base_dir),
|
||||
})
|
||||
end
|
||||
url = (base_dir ~= "" and ("http://" .. get_host() .. ":" .. port .. configured_base_path(base_dir)) or ""),
|
||||
})
|
||||
end
|
||||
|
||||
function action_diag_run()
|
||||
local http = require "luci.http"
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<%+header%>
|
||||
|
||||
<%+tasks/embed%>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
window.openclawmgrConfig = {
|
||||
token: "<%=token or ''%>",
|
||||
statusUrl: "<%=url('admin/services/openclawmgr/status')%>",
|
||||
readyUrl: "<%=url('admin/services/openclawmgr/ready')%>",
|
||||
opUrl: "<%=url('admin/services/openclawmgr/op')%>",
|
||||
configUrl: "<%=url('admin/services/openclawmgr/config_data')%>",
|
||||
applyUrl: "<%=url('admin/services/openclawmgr/apply_config')%>",
|
||||
logUrl: "<%=url('admin/services/openclawmgr/log')%>",
|
||||
staticBase: "<%=resource%>/openclawmgr"
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -5,7 +5,6 @@ local info_url = luci.dispatcher.build_url("admin", "services", "openclawmgr", "
|
||||
local run_url = luci.dispatcher.build_url("admin", "services", "openclawmgr", "diag_run")
|
||||
local poll_url = luci.dispatcher.build_url("admin", "services", "openclawmgr", "diag_poll")
|
||||
local op_url = luci.dispatcher.build_url("admin", "services", "openclawmgr", "op")
|
||||
local log_url = luci.dispatcher.build_url("admin", "services", "openclawmgr", "log")
|
||||
local token = (luci.dispatcher.context and luci.dispatcher.context.token) or ""
|
||||
%>
|
||||
|
||||
@@ -60,7 +59,6 @@ local token = (luci.dispatcher.context and luci.dispatcher.context.token) or ""
|
||||
<button class="btn" onclick="ocSvc('upgrade')"><%:Upgrade%></button>
|
||||
<button class="btn" onclick="ocConfirmUninstallOpenclaw()"><%:Uninstall OpenClaw (Keep Node)%></button>
|
||||
<button class="btn" onclick="ocConfirmUninstall()"><%:Uninstall%></button>
|
||||
<button class="btn" onclick="ocShowInstallerLog()"><%:Installer Log%></button>
|
||||
<button class="btn danger" onclick="ocConfirmPurge()"><%:Purge%></button>
|
||||
</div>
|
||||
<div style="margin-top:10px;color:#666;font-size:12px;line-height:1.6">
|
||||
@@ -101,7 +99,6 @@ local token = (luci.dispatcher.context and luci.dispatcher.context.token) or ""
|
||||
var runUrl = '<%=run_url%>';
|
||||
var pollUrl = '<%=poll_url%>';
|
||||
var opUrl = '<%=op_url%>';
|
||||
var logUrl = '<%=log_url%>';
|
||||
var csrfToken = '<%=token%>';
|
||||
|
||||
var currentOp = '';
|
||||
@@ -238,17 +235,6 @@ local token = (luci.dispatcher.context and luci.dispatcher.context.token) or ""
|
||||
window.ocSvc('purge');
|
||||
};
|
||||
|
||||
window.ocShowInstallerLog = function() {
|
||||
(new XHR()).get(logUrl, { n: 400 }, function(x) {
|
||||
try {
|
||||
var d = JSON.parse(x.responseText || '{}');
|
||||
if (window.taskd && window.taskd.show_log_txt) {
|
||||
window.taskd.show_log_txt('installer.log', d.log || '-');
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
};
|
||||
|
||||
refreshInfo();
|
||||
window.setInterval(refreshInfo, 5000);
|
||||
})();
|
||||
|
||||
@@ -2,10 +2,9 @@ config openclawmgr 'main'
|
||||
option enabled '0'
|
||||
option port '18789'
|
||||
option bind 'lan'
|
||||
option base_dir '/opt/openclawmgr'
|
||||
option token ''
|
||||
option allow_insecure_auth '0'
|
||||
option disable_device_auth '0'
|
||||
option allow_insecure_auth '1'
|
||||
option disable_device_auth '1'
|
||||
option install_accelerated '1'
|
||||
option default_agent 'anthropic'
|
||||
option default_model ''
|
||||
|
||||
@@ -19,10 +19,11 @@ start_service() {
|
||||
config_get_bool enabled main enabled 0
|
||||
config_get port main port 18789
|
||||
config_get bind main bind lan
|
||||
config_get base_dir main base_dir /opt/openclawmgr
|
||||
config_get base_dir main base_dir ""
|
||||
config_get token main token ""
|
||||
|
||||
[ "$enabled" -eq 1 ] || return 0
|
||||
[ -n "$base_dir" ] || return 1
|
||||
|
||||
local node_bin="${base_dir}/node/bin/node"
|
||||
local global_dir="${base_dir}/global"
|
||||
@@ -38,7 +39,7 @@ start_service() {
|
||||
[ -n "$entry" ] || return 1
|
||||
[ -n "$token" ] || return 1
|
||||
|
||||
mkdir -p "${data_dir}/.openclaw" 2>/dev/null
|
||||
mkdir -p "${data_dir}/.openclaw/workspace" 2>/dev/null
|
||||
if [ -f "$env_file" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "$env_file"
|
||||
@@ -59,6 +60,10 @@ start_service() {
|
||||
if id openclawmgr >/dev/null 2>&1; then
|
||||
user_opt="openclawmgr"
|
||||
fi
|
||||
if [ -n "$user_opt" ]; then
|
||||
chown -R "$user_opt:$user_opt" "$data_dir" 2>/dev/null || true
|
||||
chmod -R u+rwX "$data_dir" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
procd_open_instance "gateway"
|
||||
procd_set_param command "$node_bin" "$entry" gateway run --port "$port" --bind "$bind" --auth token --token "$token" --allow-unconfigured $force_opt
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
conf_dir="$(uci -q get quickstart.@main[0].conf_dir 2>/dev/null || true)"
|
||||
[ -n "$conf_dir" ] && suggested_base_dir="$conf_dir/OpenClawMgr" || suggested_base_dir=""
|
||||
|
||||
# Ensure section exists
|
||||
if ! uci -q get openclawmgr.main >/dev/null 2>&1; then
|
||||
uci -q set openclawmgr.main=openclawmgr >/dev/null 2>&1 || true
|
||||
@@ -14,23 +11,13 @@ fi
|
||||
[ -n "$(uci -q get openclawmgr.main.bind 2>/dev/null)" ] || uci -q set openclawmgr.main.bind='lan'
|
||||
[ -n "$(uci -q get openclawmgr.main.install_accelerated 2>/dev/null)" ] || uci -q set openclawmgr.main.install_accelerated='1'
|
||||
[ -n "$(uci -q get openclawmgr.main.token 2>/dev/null)" ] || uci -q set openclawmgr.main.token=''
|
||||
[ -n "$(uci -q get openclawmgr.main.allow_insecure_auth 2>/dev/null)" ] || uci -q set openclawmgr.main.allow_insecure_auth='0'
|
||||
[ -n "$(uci -q get openclawmgr.main.disable_device_auth 2>/dev/null)" ] || uci -q set openclawmgr.main.disable_device_auth='0'
|
||||
[ -n "$(uci -q get openclawmgr.main.allow_insecure_auth 2>/dev/null)" ] || uci -q set openclawmgr.main.allow_insecure_auth='1'
|
||||
[ -n "$(uci -q get openclawmgr.main.disable_device_auth 2>/dev/null)" ] || uci -q set openclawmgr.main.disable_device_auth='1'
|
||||
[ -n "$(uci -q get openclawmgr.main.default_agent 2>/dev/null)" ] || uci -q set openclawmgr.main.default_agent='anthropic'
|
||||
[ -n "$(uci -q get openclawmgr.main.default_model 2>/dev/null)" ] || uci -q set openclawmgr.main.default_model=''
|
||||
[ -n "$(uci -q get openclawmgr.main.provider_api_key 2>/dev/null)" ] || uci -q set openclawmgr.main.provider_api_key=''
|
||||
[ -n "$(uci -q get openclawmgr.main.provider_base_url 2>/dev/null)" ] || uci -q set openclawmgr.main.provider_base_url=''
|
||||
|
||||
# Improve default base_dir on iStoreOS: if still unset or using legacy /opt, prefer quickstart conf_dir.
|
||||
current_base_dir="$(uci -q get openclawmgr.main.base_dir 2>/dev/null || true)"
|
||||
if [ -z "$current_base_dir" ] || [ "$current_base_dir" = "/opt/openclawmgr" ]; then
|
||||
if [ -n "$suggested_base_dir" ]; then
|
||||
uci -q set openclawmgr.main.base_dir="$suggested_base_dir"
|
||||
else
|
||||
uci -q set openclawmgr.main.base_dir='/opt/openclawmgr'
|
||||
fi
|
||||
fi
|
||||
|
||||
uci -q commit openclawmgr >/dev/null 2>&1 || true
|
||||
|
||||
# best-effort: create an unprivileged user for procd
|
||||
|
||||
@@ -119,7 +119,17 @@ default_gateway() {
|
||||
}
|
||||
|
||||
ensure_dirs() {
|
||||
mkdir -p "$BASE_DIR" "$BASE_DIR/log" "$NODE_DIR" "$GLOBAL_DIR" "$DATA_DIR/.openclaw" 2>/dev/null || true
|
||||
mkdir -p "$BASE_DIR" "$NODE_DIR" "$GLOBAL_DIR" "$DATA_DIR/.openclaw/workspace" "$BASE_DIR/npm-cache" 2>/dev/null || true
|
||||
fix_data_permissions || true
|
||||
}
|
||||
|
||||
fix_data_permissions() {
|
||||
# When running under procd as user "openclawmgr", OpenClaw needs write access to data/.openclaw/*
|
||||
if ! id openclawmgr >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
chown -R openclawmgr:openclawmgr "$DATA_DIR" 2>/dev/null || true
|
||||
chmod -R u+rwX "$DATA_DIR" 2>/dev/null || true
|
||||
}
|
||||
|
||||
check_space_mb() {
|
||||
@@ -308,11 +318,9 @@ download() {
|
||||
|
||||
write_installer_log() {
|
||||
local msg="$1"
|
||||
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
|
||||
local line
|
||||
line="$(printf "%s [%s] %s" "$(log_ts)" "$APP" "$msg")"
|
||||
printf "%s\n" "$line"
|
||||
printf "%s\n" "$line" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
openclaw_bin() {
|
||||
@@ -689,6 +697,73 @@ install_openclaw() {
|
||||
local flags="" npm_registry="" effective_registry=""
|
||||
[ -x "$NPM_BIN" ] || return 1
|
||||
|
||||
ensure_git() {
|
||||
ensure_remote_https() {
|
||||
command -v git >/dev/null 2>&1 || return 1
|
||||
local execp
|
||||
execp="$(git --exec-path 2>/dev/null || true)"
|
||||
[ -n "$execp" ] || return 1
|
||||
[ -x "$execp/git-remote-https" ] && return 0
|
||||
# Some builds ship helpers under libexec paths; exec-path should cover it,
|
||||
# but keep a fallback in case of unusual layouts.
|
||||
[ -x /usr/lib/git-core/git-remote-https ] && return 0
|
||||
[ -x /usr/libexec/git-core/git-remote-https ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
command -v git >/dev/null 2>&1 || {
|
||||
write_installer_log "git not found; some npm dependencies require git. Trying to install git via opkg."
|
||||
local pm=""
|
||||
if command -v is-opkg >/dev/null 2>&1; then
|
||||
pm="is-opkg"
|
||||
elif command -v opkg >/dev/null 2>&1; then
|
||||
pm="opkg"
|
||||
fi
|
||||
if [ -z "$pm" ]; then
|
||||
write_installer_log "git is required but opkg/is-opkg is not available; please install git and retry."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if "$pm" install git >/dev/null 2>&1; then
|
||||
command -v git >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
command -v git >/dev/null 2>&1 || {
|
||||
write_installer_log "git is required but could not be installed automatically; please opkg install git and retry."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Ensure HTTPS transport is available (git-remote-https), required for git URL rewrites.
|
||||
if ensure_remote_https; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
write_installer_log "git HTTPS transport helper not found (git-remote-https); trying to install git-http/git-https."
|
||||
local pm=""
|
||||
if command -v is-opkg >/dev/null 2>&1; then
|
||||
pm="is-opkg"
|
||||
elif command -v opkg >/dev/null 2>&1; then
|
||||
pm="opkg"
|
||||
fi
|
||||
if [ -z "$pm" ]; then
|
||||
write_installer_log "git-remote-https is required but opkg/is-opkg is not available; please install git-http (or equivalent) and retry."
|
||||
return 1
|
||||
fi
|
||||
|
||||
"$pm" install git-http >/dev/null 2>&1 || true
|
||||
"$pm" install git-https >/dev/null 2>&1 || true
|
||||
|
||||
if ensure_remote_https; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
write_installer_log "git-remote-https is required but could not be installed automatically; please opkg install git-http (or git-https) and retry."
|
||||
return 1
|
||||
}
|
||||
|
||||
ensure_git || return 1
|
||||
|
||||
if is_musl; then
|
||||
flags="--ignore-scripts"
|
||||
fi
|
||||
@@ -698,7 +773,7 @@ install_openclaw() {
|
||||
fi
|
||||
|
||||
write_installer_log "Installing OpenClaw from npm"
|
||||
write_installer_log "Node.js: $($NODE_BIN --version 2>/dev/null || echo unknown), npm: $($NPM_BIN --version 2>/dev/null || echo unknown)"
|
||||
write_installer_log "Node.js: $(PATH=\"${NODE_DIR}/bin:/usr/sbin:/usr/bin:/sbin:/bin\" \"$NODE_BIN\" --version 2>/dev/null || echo unknown), npm: $(PATH=\"${NODE_DIR}/bin:/usr/sbin:/usr/bin:/sbin:/bin\" \"$NPM_BIN\" --version 2>/dev/null || echo unknown)"
|
||||
write_installer_log "npm prefix: $GLOBAL_DIR, cache: ${BASE_DIR}/npm-cache, musl: $(is_musl && echo yes || echo no) ${flags:+($flags)}"
|
||||
write_installer_log "npm registry: ${npm_registry:-default}"
|
||||
if [ -n "$npm_registry" ]; then
|
||||
@@ -722,6 +797,7 @@ install_openclaw() {
|
||||
mkdir -p "$DATA_DIR" 2>/dev/null || true
|
||||
# Use --add because url.*.insteadOf is multi-valued (git config without --add overwrites).
|
||||
git config --file "$DATA_DIR/.gitconfig" --add url."https://github.com/".insteadOf "ssh://git@github.com/" 2>/dev/null || true
|
||||
git config --file "$DATA_DIR/.gitconfig" --add url."https://github.com/".insteadOf "ssh://git@github.com" 2>/dev/null || true
|
||||
git config --file "$DATA_DIR/.gitconfig" --add url."https://github.com/".insteadOf "git@github.com:" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
@@ -786,28 +862,26 @@ install_openclaw() {
|
||||
|
||||
local npm_rc=0
|
||||
wait "$npmpid" || npm_rc=$?
|
||||
if [ "$npm_rc" -ne 0 ]; then
|
||||
write_installer_log "npm install failed (rc=$npm_rc); dumping recent output"
|
||||
kill "$tailpid" 2>/dev/null || true
|
||||
wait "$tailpid" 2>/dev/null || true
|
||||
tail -n 200 "$tmp" >> "$LOG_FILE" 2>/dev/null || true
|
||||
rm -f "$tmp" 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
if [ "$npm_rc" -ne 0 ]; then
|
||||
write_installer_log "npm install failed (rc=$npm_rc); dumping recent output"
|
||||
kill "$tailpid" 2>/dev/null || true
|
||||
wait "$tailpid" 2>/dev/null || true
|
||||
rm -f "$tmp" 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
local end_ts elapsed_s elapsed_h
|
||||
end_ts="$(date +%s 2>/dev/null || echo 0)"
|
||||
elapsed_s=$((end_ts - start_ts))
|
||||
elapsed_h="$(fmt_elapsed "$elapsed_s")"
|
||||
write_installer_log "npm install finished (${elapsed_h} elapsed)"
|
||||
kill "$tailpid" 2>/dev/null || true
|
||||
wait "$tailpid" 2>/dev/null || true
|
||||
tail -n 200 "$tmp" >> "$LOG_FILE" 2>/dev/null || true
|
||||
rm -f "$tmp" 2>/dev/null || true
|
||||
find_entry >/dev/null 2>&1 || return 1
|
||||
write_installer_log "OpenClaw installed: $(openclaw_version || echo unknown)"
|
||||
return 0
|
||||
}
|
||||
write_installer_log "npm install finished (${elapsed_h} elapsed)"
|
||||
kill "$tailpid" 2>/dev/null || true
|
||||
wait "$tailpid" 2>/dev/null || true
|
||||
rm -f "$tmp" 2>/dev/null || true
|
||||
find_entry >/dev/null 2>&1 || return 1
|
||||
write_installer_log "OpenClaw installed: $(openclaw_version || echo unknown)"
|
||||
return 0
|
||||
}
|
||||
|
||||
do_install() {
|
||||
acquire_lock
|
||||
@@ -834,16 +908,18 @@ install_openclaw() {
|
||||
uci -q set "${UCI_NS}.main.token=$TOKEN" && uci -q commit "$UCI_NS" || true
|
||||
fi
|
||||
|
||||
install_node
|
||||
install_openclaw
|
||||
ensure_gateway_config || true
|
||||
install_node
|
||||
install_openclaw
|
||||
ensure_gateway_config || true
|
||||
fix_data_permissions || true
|
||||
# Do not auto-enable/start on first install; let user Save & Apply after choosing base_dir and settings.
|
||||
if [ "${ENABLED:-0}" = "1" ]; then
|
||||
/etc/init.d/openclawmgr enable >/dev/null 2>&1 || true
|
||||
/etc/init.d/openclawmgr restart >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
/etc/init.d/openclawmgr enable >/dev/null 2>&1 || true
|
||||
uci -q set "${UCI_NS}.main.enabled=1" && uci -q commit "$UCI_NS" || true
|
||||
/etc/init.d/openclawmgr restart >/dev/null 2>&1 || true
|
||||
|
||||
write_installer_log "== install done =="
|
||||
}
|
||||
write_installer_log "== install done =="
|
||||
}
|
||||
|
||||
do_uninstall() {
|
||||
acquire_lock
|
||||
@@ -885,6 +961,7 @@ do_start() {
|
||||
acquire_lock
|
||||
write_installer_log "== start begin =="
|
||||
ensure_dirs
|
||||
fix_data_permissions || true
|
||||
/etc/init.d/openclawmgr enable >/dev/null 2>&1 || true
|
||||
uci -q set "${UCI_NS}.main.enabled=1" && uci -q commit "$UCI_NS" || true
|
||||
ensure_gateway_config || true
|
||||
@@ -905,28 +982,32 @@ do_restart() {
|
||||
acquire_lock
|
||||
write_installer_log "== restart begin =="
|
||||
ensure_dirs
|
||||
fix_data_permissions || true
|
||||
ensure_gateway_config || true
|
||||
/etc/init.d/openclawmgr restart >/dev/null 2>&1 || true
|
||||
write_installer_log "== restart done =="
|
||||
}
|
||||
|
||||
do_apply_config() {
|
||||
acquire_lock
|
||||
write_installer_log "== apply_config begin =="
|
||||
ensure_dirs
|
||||
ensure_gateway_config || true
|
||||
do_apply_config() {
|
||||
acquire_lock
|
||||
write_installer_log "== apply_config begin =="
|
||||
ensure_dirs
|
||||
fix_data_permissions || true
|
||||
ensure_gateway_config || true
|
||||
|
||||
local pid=""
|
||||
pid="$(ubus call service list "{\"name\":\"openclawmgr\"}" 2>/dev/null | jsonfilter -e '$.openclawmgr.instances.gateway.pid' 2>/dev/null || true)"
|
||||
if [ "${ENABLED:-0}" = "1" ]; then
|
||||
/etc/init.d/openclawmgr enable >/dev/null 2>&1 || true
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
/etc/init.d/openclawmgr restart >/dev/null 2>&1 || true
|
||||
local pid=""
|
||||
pid="$(ubus call service list "{\"name\":\"openclawmgr\"}" 2>/dev/null | jsonfilter -e '$.openclawmgr.instances.gateway.pid' 2>/dev/null || true)"
|
||||
if [ "${ENABLED:-0}" = "1" ]; then
|
||||
/etc/init.d/openclawmgr enable >/dev/null 2>&1 || true
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
/etc/init.d/openclawmgr restart >/dev/null 2>&1 || true
|
||||
else
|
||||
/etc/init.d/openclawmgr start >/dev/null 2>&1 || true
|
||||
fi
|
||||
else
|
||||
/etc/init.d/openclawmgr stop >/dev/null 2>&1 || true
|
||||
/etc/init.d/openclawmgr disable >/dev/null 2>&1 || true
|
||||
fi
|
||||
else
|
||||
/etc/init.d/openclawmgr stop >/dev/null 2>&1 || true
|
||||
/etc/init.d/openclawmgr disable >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
write_installer_log "== apply_config done =="
|
||||
}
|
||||
@@ -1052,10 +1133,10 @@ diag_poll() {
|
||||
ACTION="${1:-help}"
|
||||
shift 1 || true
|
||||
|
||||
BASE_DIR="$(uci_get base_dir)"
|
||||
PORT="$(uci_get port)"
|
||||
BIND="$(uci_get bind)"
|
||||
TOKEN="$(uci_get token)"
|
||||
BASE_DIR="$(uci_get base_dir)"
|
||||
PORT="$(uci_get port)"
|
||||
BIND="$(uci_get bind)"
|
||||
TOKEN="$(uci_get token)"
|
||||
ALLOW_INSECURE_AUTH="$(uci_get allow_insecure_auth)"
|
||||
DISABLE_DEVICE_AUTH="$(uci_get disable_device_auth)"
|
||||
ALLOWED_ORIGINS="$(uci_get_list allowed_origins)"
|
||||
@@ -1065,12 +1146,11 @@ INSTALL_ACCELERATED="$(uci_get install_accelerated)"
|
||||
PROVIDER_API_KEY="$(uci_get provider_api_key)"
|
||||
PROVIDER_BASE_URL="$(uci_get provider_base_url)"
|
||||
|
||||
[ -n "$BASE_DIR" ] || BASE_DIR="/opt/openclawmgr"
|
||||
[ -n "$PORT" ] || PORT="18789"
|
||||
[ -n "$BIND" ] || BIND="lan"
|
||||
NODE_VERSION="24.14.0"
|
||||
[ -n "$ALLOW_INSECURE_AUTH" ] || ALLOW_INSECURE_AUTH="0"
|
||||
[ -n "$DISABLE_DEVICE_AUTH" ] || DISABLE_DEVICE_AUTH="0"
|
||||
[ -n "$PORT" ] || PORT="18789"
|
||||
[ -n "$BIND" ] || BIND="lan"
|
||||
NODE_VERSION="24.14.0"
|
||||
[ -n "$ALLOW_INSECURE_AUTH" ] || ALLOW_INSECURE_AUTH="1"
|
||||
[ -n "$DISABLE_DEVICE_AUTH" ] || DISABLE_DEVICE_AUTH="1"
|
||||
[ -n "$DEFAULT_AGENT" ] || DEFAULT_AGENT="anthropic"
|
||||
[ -n "$DEFAULT_MODEL" ] || DEFAULT_MODEL=""
|
||||
[ -n "$INSTALL_ACCELERATED" ] || INSTALL_ACCELERATED="1"
|
||||
@@ -1101,43 +1181,59 @@ case "$INSTALL_ACCELERATED" in
|
||||
*) INSTALL_ACCELERATED="0" ;;
|
||||
esac
|
||||
|
||||
require_base_dir() {
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
write_installer_log "base_dir is not configured; please choose a data directory in LuCI and Save & Apply, then retry."
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
NODE_DIR="${BASE_DIR}/node"
|
||||
GLOBAL_DIR="${BASE_DIR}/global"
|
||||
DATA_DIR="${BASE_DIR}/data"
|
||||
LOG_FILE="${BASE_DIR}/log/installer.log"
|
||||
|
||||
NODE_BIN="${NODE_DIR}/bin/node"
|
||||
NPM_BIN="${NODE_DIR}/bin/npm"
|
||||
NODE_BIN="${NODE_DIR}/bin/node"
|
||||
NPM_BIN="${NODE_DIR}/bin/npm"
|
||||
|
||||
case "$ACTION" in
|
||||
install|upgrade)
|
||||
require_base_dir
|
||||
do_install
|
||||
;;
|
||||
uninstall)
|
||||
require_base_dir
|
||||
do_uninstall
|
||||
;;
|
||||
uninstall_openclaw)
|
||||
require_base_dir
|
||||
do_uninstall_openclaw
|
||||
;;
|
||||
purge)
|
||||
require_base_dir
|
||||
do_purge
|
||||
;;
|
||||
rm)
|
||||
require_base_dir
|
||||
do_uninstall
|
||||
;;
|
||||
start)
|
||||
require_base_dir
|
||||
do_start
|
||||
;;
|
||||
stop)
|
||||
require_base_dir
|
||||
do_stop
|
||||
;;
|
||||
restart)
|
||||
require_base_dir
|
||||
do_restart
|
||||
;;
|
||||
apply_config)
|
||||
require_base_dir
|
||||
do_apply_config
|
||||
;;
|
||||
status)
|
||||
[ -n "$BASE_DIR" ] || exit 0
|
||||
do_status
|
||||
;;
|
||||
port)
|
||||
|
||||
Reference in new issue
Block a user