@okclaw-build/cli 1.0.0-beta.42 → 1.0.0-beta.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/service.js +21 -31
- package/dist/commands/service.js.map +1 -1
- package/dist/installers/openclaw.js +8 -4
- package/dist/installers/openclaw.js.map +1 -1
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.js +4 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/openclaw-daemon.d.ts +43 -8
- package/dist/utils/openclaw-daemon.js +134 -18
- package/dist/utils/openclaw-daemon.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/service.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { shell, shellCapture } from '../utils/shell.js';
|
|
2
1
|
import { info, success } from '../utils/logger.js';
|
|
3
2
|
import { NdjsonEmitter, registerExitHandlers } from '../output/ndjson.js';
|
|
4
3
|
import { isNdjson } from '../output/mode.js';
|
|
4
|
+
import { OPENCLAW_GATEWAY_PORT } from '../utils/constants.js';
|
|
5
|
+
import { startGateway, stopGateway, restartGateway, probeGatewayState } from '../utils/openclaw-daemon.js';
|
|
5
6
|
async function runSimpleOp(op, step, humanVerb, action) {
|
|
6
7
|
const emitter = new NdjsonEmitter(op);
|
|
7
8
|
registerExitHandlers(emitter);
|
|
@@ -20,34 +21,14 @@ async function runSimpleOp(op, step, humanVerb, action) {
|
|
|
20
21
|
throw e;
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
|
-
// openclaw 是 supervisor:fork 出 openclaw-gateway 后自己 epoll_wait 不退。
|
|
24
|
-
// 直接 `nohup ... &` 会让外层 bash 在脚本末尾仍停在 wait4(-1) 上死等 supervisor,
|
|
25
|
-
// Node 的 child.on('close') 因此永远不触发。用 `( nohup ... & )` 子 shell 双 fork:
|
|
26
|
-
// 内层子 shell 背景化 supervisor 后立即退出,supervisor 被 init 收养,外层 bash
|
|
27
|
-
// 没有子进程可等,直接 exit。
|
|
28
|
-
const START_GATEWAY = "mkdir -p /root/.openclaw && ( nohup openclaw gateway </dev/null >/root/.openclaw/gateway.out 2>&1 & ) && sleep 3 && ps -C openclaw-gateway -o pid= >/dev/null";
|
|
29
|
-
// `pkill -f openclaw-gateway` 会按 cmdline substring 命中,误杀任何 cmdline 含此
|
|
30
|
-
// 字符串的进程(实测:bootstrap script 里跑 restart 时,其 bash -c 命令行也含
|
|
31
|
-
// 'openclaw-gateway',被自杀,导致 restart 命令 exit null/1)。
|
|
32
|
-
// `pkill -x openclaw-gateway` 用 comm 字段精确匹配,但 Linux comm 只 15 字符,
|
|
33
|
-
// 而 'openclaw-gateway' 16 字符,直接报错。
|
|
34
|
-
// 唯一稳的办法:`ps -C openclaw-gateway`(by command name,支持超 15 字符) →
|
|
35
|
-
// xargs kill,只杀真的 gateway 进程,不命中 cmdline substring。
|
|
36
|
-
const STOP_GATEWAY = "ps -C openclaw-gateway -o pid= 2>/dev/null | xargs -r kill 2>/dev/null || true";
|
|
37
24
|
export async function startCommand() {
|
|
38
|
-
await runSimpleOp('start', 'start', 'Starting',
|
|
39
|
-
await shell(START_GATEWAY);
|
|
40
|
-
});
|
|
25
|
+
await runSimpleOp('start', 'start', 'Starting', startGateway);
|
|
41
26
|
}
|
|
42
27
|
export async function stopCommand() {
|
|
43
|
-
await runSimpleOp('stop', 'stop', 'Stopping',
|
|
44
|
-
await shell(STOP_GATEWAY);
|
|
45
|
-
});
|
|
28
|
+
await runSimpleOp('stop', 'stop', 'Stopping', stopGateway);
|
|
46
29
|
}
|
|
47
30
|
export async function restartCommand() {
|
|
48
|
-
await runSimpleOp('restart', 'restart', 'Restarting',
|
|
49
|
-
await shell(`${STOP_GATEWAY}; sleep 1; ${START_GATEWAY}`);
|
|
50
|
-
});
|
|
31
|
+
await runSimpleOp('restart', 'restart', 'Restarting', restartGateway);
|
|
51
32
|
}
|
|
52
33
|
export async function statusCommand() {
|
|
53
34
|
const emitter = new NdjsonEmitter('status');
|
|
@@ -55,17 +36,26 @@ export async function statusCommand() {
|
|
|
55
36
|
emitter.start('querying gateway status');
|
|
56
37
|
emitter.stepStart('status', 'checking openclaw gateway process');
|
|
57
38
|
try {
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
const
|
|
61
|
-
const
|
|
39
|
+
// 健康判定以 18789 端口监听为准 —— systemd 服务 active ≠ 端口已对外服务。
|
|
40
|
+
// probeGatewayState 内含启动窗口的 bounded wait。
|
|
41
|
+
const state = await probeGatewayState();
|
|
42
|
+
const running = state === 'listening';
|
|
43
|
+
const output = state === 'listening'
|
|
44
|
+
? `Gateway listening on port ${OPENCLAW_GATEWAY_PORT}`
|
|
45
|
+
: state === 'starting'
|
|
46
|
+
? `Gateway service active but not listening on port ${OPENCLAW_GATEWAY_PORT} (starting/degraded)`
|
|
47
|
+
: `No gateway process found on port ${OPENCLAW_GATEWAY_PORT}`;
|
|
62
48
|
if (!isNdjson()) {
|
|
63
49
|
console.log(output);
|
|
64
50
|
}
|
|
65
|
-
// ps -C 没命中时输出只有 header,没有 PID 行;命中时 stdout 含 'openclaw-gateway'
|
|
66
|
-
const running = /openclaw-gateway/.test(result.stdout);
|
|
67
51
|
emitter.stepDone('status', 'status query done');
|
|
68
|
-
emitter.end(running, running ? 0 : 1, running ? undefined : 'E_STATUS_NOT_RUNNING', { running, rawOutput: output });
|
|
52
|
+
emitter.end(running, running ? 0 : 1, running ? undefined : state === 'starting' ? 'E_STATUS_DEGRADED' : 'E_STATUS_NOT_RUNNING', { running, state, rawOutput: output });
|
|
53
|
+
// gateway 没真正对外监听时进程退出码也必须非 0 —— os-api 的 bootstrap
|
|
54
|
+
// 「Step 6」和迁移「target:status」都靠 shell 退出码做校验门
|
|
55
|
+
// (`okclaw status || 失败`),只写 ndjson、进程仍 exit 0 会让校验形同虚设。
|
|
56
|
+
if (!running) {
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
69
59
|
}
|
|
70
60
|
catch (e) {
|
|
71
61
|
const msg = e instanceof Error ? e.message : String(e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/commands/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/commands/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE3G,KAAK,UAAU,WAAW,CACxB,EAAU,EACV,IAAY,EACZ,SAAiB,EACjB,MAA2B;IAE3B,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC;IACtC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG,SAAS,sBAAsB,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,SAAS,UAAU,CAAC,CAAC;QAChD,MAAM,MAAM,EAAE,CAAC;QACf,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/B,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACtE,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC5C,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACzC,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,mCAAmC,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,qDAAqD;QACrD,0CAA0C;QAC1C,MAAM,KAAK,GAAG,MAAM,iBAAiB,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,KAAK,KAAK,WAAW,CAAC;QACtC,MAAM,MAAM,GACV,KAAK,KAAK,WAAW;YACnB,CAAC,CAAC,6BAA6B,qBAAqB,EAAE;YACtD,CAAC,CAAC,KAAK,KAAK,UAAU;gBACpB,CAAC,CAAC,oDAAoD,qBAAqB,sBAAsB;gBACjG,CAAC,CAAC,oCAAoC,qBAAqB,EAAE,CAAC;QACpE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CACT,OAAO,EACP,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACf,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,sBAAsB,EACzF,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CACtC,CAAC;QACF,oDAAoD;QACpD,6CAA6C;QAC7C,yDAAyD;QACzD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { readFileSync, writeFileSync, existsSync, cpSync, mkdirSync, rmSync } fr
|
|
|
2
2
|
import { shell, shellRetry, shellCapture } from '../utils/shell.js';
|
|
3
3
|
import { ensureNodeVersion, checkDiskSpace } from '../utils/deps.js';
|
|
4
4
|
import { info, warn } from '../utils/logger.js';
|
|
5
|
-
import { stopDaemonForExclusiveAccess } from '../utils/openclaw-daemon.js';
|
|
5
|
+
import { stopDaemonForExclusiveAccess, stopGateway, cleanupGatewayServiceFiles, } from '../utils/openclaw-daemon.js';
|
|
6
6
|
import { OPENCLAW_HOME, OKCLAW_BACKUP_DIR, NPM_REGISTRY } from '../utils/constants.js';
|
|
7
7
|
import { purgePhaseB } from './openviking-purge.js';
|
|
8
8
|
import { backupOpenclawUserData } from '../openclaw-user-data.js';
|
|
@@ -162,9 +162,13 @@ export class OpenclawInstaller {
|
|
|
162
162
|
// 否则 pkill + npm uninstall 只删二进制,service 文件留着仍指向旧路径,新版装完
|
|
163
163
|
// systemd 会在旧 ExecStart 上无限 restart 直到下次手工 restart。
|
|
164
164
|
await shell(`openclaw gateway uninstall 2>/dev/null || true`).catch(() => { });
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
await
|
|
165
|
+
// `openclaw gateway uninstall` 只删主 .service,残留的 .bak / .service.d/
|
|
166
|
+
// drop-in 会污染下次 install,一并清掉。
|
|
167
|
+
await cleanupGatewayServiceFiles();
|
|
168
|
+
// 兜底停掉残留 gateway 进程(systemd 没接管的情况)。按监听端口杀 ——
|
|
169
|
+
// gateway 进程名在新版 openclaw 下是 `openclaw` / `node`,旧的
|
|
170
|
+
// `pkill -f openclaw-gateway` 匹配不到;按端口杀也绝不会误命中本 CLI 进程。
|
|
171
|
+
await stopGateway().catch(() => { });
|
|
168
172
|
// 多 package manager 容忍:主机可能用 npm / pnpm / yarn 任一装过 openclaw,
|
|
169
173
|
// 没装的包管理器跑也 tolerate,各自清各自的 store。
|
|
170
174
|
// 见 P5 真机排障:测试主机 which openclaw 指向 /root/.local/share/pnpm/openclaw,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/installers/openclaw.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE7F,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,
|
|
1
|
+
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/installers/openclaw.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE7F,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,4BAA4B,EAC5B,WAAW,EACX,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,MAAM,eAAe,GAAG,GAAG,aAAa,gBAAgB,CAAC;AAEzD,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,SAAS;QACb,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,iBAAiB,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAe;QAC3B,IAAI,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YAChC,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtE,MAAM,SAAS,GAAG,GAAG,iBAAiB,oBAAoB,EAAE,EAAE,CAAC;YAC/D,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1C,MAAM,CAAC,eAAe,EAAE,GAAG,SAAS,gBAAgB,CAAC,CAAC;YACtD,IAAI,CAAC,gCAAgC,SAAS,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,CAAC,uBAAuB,OAAO,KAAK,CAAC,CAAC;QAC1C,mFAAmF;QACnF,mEAAmE;QACnE,MAAM,UAAU,CACd,2BAA2B,OAAO,eAAe,YAAY,wCAAwC,CACtG,CAAC;QACF,0EAA0E;QAC1E,IAAI,CAAC,iCAAiC,CAAC,CAAC;QACxC,MAAM,KAAK,CACT,qHAAqH,CACtH,CAAC;QACF,MAAM,KAAK,CACT,6EAA6E,CAC9E,CAAC;QAEF,yEAAyE;QACzE,6EAA6E;QAC7E,IAAI,CAAC,mEAAmE,CAAC,CAAC;QAC1E,MAAM,WAAW,EAAE,CAAC;QAEpB,2DAA2D;QAC3D,2EAA2E;QAC3E,4EAA4E;QAC5E,kFAAkF;QAClF,IAAI,CAAC,4CAA4C,CAAC,CAAC;QACnD,wDAAwD;QACxD,sCAAsC;QACtC,iDAAiD;QACjD,iCAAiC;QACjC,MAAM,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAE9E,mEAAmE;QACnE,wEAAwE;QACxE,uEAAuE;QACvE,0EAA0E;QAC1E,sEAAsE;QACtE,yEAAyE;QACzE,wEAAwE;QACxE,6CAA6C;QAC7C,MAAM,4BAA4B,CAAC,8BAA8B,CAAC,CAAC;QAEnE,IAAI,CAAC,0CAA0C,CAAC,CAAC;QACjD,MAAM,KAAK,CAAC,mDAAmD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC1E,IAAI,CAAC,0DAA0D,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QACH,yEAAyE;QACzE,0CAA0C;QAC1C,gEAAgE;QAChE,+DAA+D;QAC/D,uCAAuC;QACvC,MAAM,KAAK,CAAC,sDAAsD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC7E,IAAI,CAAC,iFAAiF,CAAC,CAAC;QAC1F,CAAC,CAAC,CAAC;QACH,MAAM,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAEtD,IAAI,CAAC,YAAY,OAAO,aAAa,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,SAAS,CAAC,MAA+B;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE7C,mEAAmE;QACnE,qEAAqE;QACrE,gEAAgE;QAChE,oEAAoE;QACpE,yBAAyB;QACzB,yEAAyE;QACzE,wEAAwE;QACxE,uEAAuE;QACvE,iEAAiE;QACjE,2CAA2C;QAC3C,mEAAmE;QACnE,qEAAqE;QACrE,MAAM,4BAA4B,CAAC,0BAA0B,CAAC,CAAC;QAE/D,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAEnD,IAAI,cAAc,GAA4B,EAAE,CAAC;QACjD,IAAI,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;YACrE,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,4EAA4E,CAAC,CAAC;YACrF,CAAC;QACH,CAAC;QAED,iCAAiC;QACjC,IAAI,CAAC,cAAc,CAAC,MAAM,IAAI,OAAO,cAAc,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxE,cAAc,CAAC,MAAM,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;QAC3D,CAAC;QACD,MAAM,MAAM,GAAG,cAAc,CAAC,MAAiC,CAAC;QAChE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC9D,MAAM,CAAC,SAAS,GAAG,EAAE,CAAC;QACxB,CAAC;QACD,MAAM,iBAAiB,GAAG,MAAM,CAAC,SAAoC,CAAC;QAEtE,yCAAyC;QACzC,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,KAAK,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACpE,iBAAiB,CAAC,YAAY,CAAC,GAAG,cAAc,CAAC;YACjD,IAAI,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAC;YAExC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,EAAE,GAAG,cAAyC,CAAC;gBACrD,MAAM,SAAS,GAAG,EAAE,CAAC,MAAoD,CAAC;gBAC1E,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC;oBACvB,YAAY,GAAG,GAAG,YAAY,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBACtD,CAAC;YACH,CAAC;QACH,CAAC;QAED,eAAe;QACf,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,aAAa,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;QACvF,IAAI,CAAC,WAAW,eAAe,EAAE,CAAC,CAAC;QAEnC,iFAAiF;QACjF,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,0BAA0B,YAAY,EAAE,CAAC,CAAC;YAC/C,MAAM,KAAK,CAAC,sDAAsD,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBAC5F,IAAI,CAAC,2DAA2D,CAAC,CAAC;gBAClE,MAAM,MAAM,GAAG,CAAC,cAAc,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;gBACxE,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAA4B,CAAC;gBACpE,QAAQ,CAAC,KAAK,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;gBAC3C,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBAC3B,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC;gBAC/B,aAAa,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;YACzF,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,kBAAkB,YAAY,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,SAAS;QACb,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC7B,2DAA2D;QAC3D,MAAM,KAAK,CAAC,iCAAiC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAE/D,MAAM,iBAAiB,GAAG,sBAAsB,EAAE,CAAC;QACnD,IAAI,iBAAiB,EAAE,CAAC;YACtB,IAAI,CAAC,mCAAmC,iBAAiB,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,0DAA0D,CAAC,CAAC;QACnE,CAAC;QAED,sEAAsE;QACtE,yDAAyD;QACzD,oDAAoD;QACpD,MAAM,KAAK,CAAC,gDAAgD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC9E,mEAAmE;QACnE,8BAA8B;QAC9B,MAAM,0BAA0B,EAAE,CAAC;QACnC,8CAA8C;QAC9C,oDAAoD;QACpD,wDAAwD;QACxD,MAAM,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEpC,8DAA8D;QAC9D,mCAAmC;QACnC,qEAAqE;QACrE,qEAAqE;QACrE,uBAAuB;QACvB,IAAI,CAAC,mEAAmE,CAAC,CAAC;QAC1E,MAAM,KAAK,CAAC,oEAAoE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAClG,MAAM,KAAK,CAAC,yCAAyC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACvE,MAAM,KAAK,CAAC,iDAAiD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAE/E,sDAAsD;QACtD,mCAAmC;QACnC,MAAM,KAAK,CAAC,mDAAmD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEjF,4DAA4D;QAC5D,oCAAoC;QACpC,+DAA+D;QAC/D,0CAA0C;QAC1C,4CAA4C;QAC5C,MAAM,QAAQ,GAAG,uFAAuF,CAAC;QACzG,IAAI,CAAC,uDAAuD,CAAC,CAAC;QAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,SAAS,QAAQ,qCAAqC,CAAC,CAAC;YACxF,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,QAAQ;gBAAE,MAAM;YACrB,IAAI,CAAC,qBAAqB,QAAQ,YAAY,CAAC,CAAC;YAChD,uCAAuC;YACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC7C,MAAM,KAAK,CAAC,UAAU,IAAI,uBAAuB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,CAAC,qCAAqC,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,SAAS,QAAQ,qCAAqC,CAAC,CAAC;QACzF,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,yCAAyC,YAAY,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,IAAI,CAAC,YAAY,aAAa,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,GAAG,aAAa,6BAA6B,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -4,6 +4,7 @@ export declare const OKCLAW_BACKUP_DIR = "/root/okclaw/backup";
|
|
|
4
4
|
export declare const OKCLAW_TMP_DIR = "/root/okclaw/tmp";
|
|
5
5
|
export declare const OPENCLAW_HOME = "/root/.openclaw";
|
|
6
6
|
export declare const OPENCLAW_WORKSPACE = "/root/.openclaw/workspace";
|
|
7
|
+
export declare const OPENCLAW_GATEWAY_PORT = 18789;
|
|
7
8
|
export declare const OPENVIKING_HOME = "/root/.openviking";
|
|
8
9
|
export declare const OPENVIKING_CONF = "/root/.openviking/ov.conf";
|
|
9
10
|
export declare const OPENVIKING_ENV = "/root/.openclaw/openviking.env";
|
package/dist/utils/constants.js
CHANGED
|
@@ -5,6 +5,10 @@ export const OKCLAW_BACKUP_DIR = `${OKCLAW_HOME}/backup`;
|
|
|
5
5
|
export const OKCLAW_TMP_DIR = `${OKCLAW_HOME}/tmp`;
|
|
6
6
|
export const OPENCLAW_HOME = '/root/.openclaw';
|
|
7
7
|
export const OPENCLAW_WORKSPACE = `${OPENCLAW_HOME}/workspace`;
|
|
8
|
+
// openclaw gateway 默认 WebSocket 端口。gateway 进程名在不同启动方式下不固定
|
|
9
|
+
// (`openclaw gateway run` → `openclaw`,systemd → `node`),所以进程识别一律
|
|
10
|
+
// 按这个监听端口来,不能用 `ps -C` / `pkill -f` 匹配进程名。
|
|
11
|
+
export const OPENCLAW_GATEWAY_PORT = 18789;
|
|
8
12
|
export const OPENVIKING_HOME = '/root/.openviking';
|
|
9
13
|
export const OPENVIKING_CONF = `${OPENVIKING_HOME}/ov.conf`;
|
|
10
14
|
export const OPENVIKING_ENV = `${OPENCLAW_HOME}/openviking.env`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC;AAC1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,WAAW,SAAS,CAAC;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,WAAW,SAAS,CAAC;AACzD,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,WAAW,MAAM,CAAC;AAEnD,MAAM,CAAC,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,aAAa,YAAY,CAAC;AAC/D,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AACnD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,eAAe,UAAU,CAAC;AAC5D,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,aAAa,iBAAiB,CAAC;AAChE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC,yEAAyE;AACzE,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,gBAAgB;AAChB,MAAM,CAAC,MAAM,YAAY,GAAG,gCAAgC,CAAC;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,0CAA0C,CAAC;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,WAAW,GAAG,oCAAoC,CAAC;AAEhE,wEAAwE;AACxE,MAAM,CAAC,MAAM,WAAW,GAAG,6BAA6B,CAAC;AACzD,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AACvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAEhE,gDAAgD;AAChD,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;AAC1F,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,mBAAmB,EAAE,WAAW,EAAE,oBAAoB;IACtD,mBAAmB,EAAE,eAAe,EAAE,iBAAiB;IACvD,8BAA8B,EAAE,sBAAsB;IACtD,eAAe;CAChB,CAAC;AAEF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC1D,QAAQ,EAAE,iBAAiB;IAC3B,MAAM,EAAE,iCAAiC;IACzC,iDAAiD;IACjD,mEAAmE;CACpE,CAAC;AAEF,yEAAyE;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC;AAC1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,WAAW,SAAS,CAAC;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,WAAW,SAAS,CAAC;AACzD,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,WAAW,MAAM,CAAC;AAEnD,MAAM,CAAC,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,aAAa,YAAY,CAAC;AAC/D,0DAA0D;AAC1D,kEAAkE;AAClE,2CAA2C;AAC3C,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAC3C,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AACnD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,eAAe,UAAU,CAAC;AAC5D,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,aAAa,iBAAiB,CAAC;AAChE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC,yEAAyE;AACzE,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,gBAAgB;AAChB,MAAM,CAAC,MAAM,YAAY,GAAG,gCAAgC,CAAC;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,0CAA0C,CAAC;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,WAAW,GAAG,oCAAoC,CAAC;AAEhE,wEAAwE;AACxE,MAAM,CAAC,MAAM,WAAW,GAAG,6BAA6B,CAAC;AACzD,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AACvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAEhE,gDAAgD;AAChD,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;AAC1F,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,mBAAmB,EAAE,WAAW,EAAE,oBAAoB;IACtD,mBAAmB,EAAE,eAAe,EAAE,iBAAiB;IACvD,8BAA8B,EAAE,sBAAsB;IACtD,eAAe;CAChB,CAAC;AAEF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC1D,QAAQ,EAAE,iBAAiB;IAC3B,MAAM,EAAE,iCAAiC;IACzC,iDAAiD;IACjD,mEAAmE;CACpE,CAAC;AAEF,yEAAyE;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC"}
|
|
@@ -1,8 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* 确保 gateway 的 systemd 服务已安装且能常驻。
|
|
3
|
+
* - `loginctl enable-linger`:systemd user 服务默认随最后一个登录会话退出而停,
|
|
4
|
+
* 开 linger 后才能在部署 SSH 断开后 / 主机重启后继续运行。
|
|
5
|
+
* - `openclaw gateway install --force`:幂等(重装覆盖),顺带在 openclaw 升级后
|
|
6
|
+
* 刷新 unit 的 ExecStart。
|
|
7
|
+
*/
|
|
8
|
+
export declare function installGatewayService(): Promise<void>;
|
|
9
|
+
/** 启动 gateway(先确保 systemd 服务已装)。 */
|
|
10
|
+
export declare function startGateway(): Promise<void>;
|
|
11
|
+
/** 重启 gateway(先确保 systemd 服务已装)。 */
|
|
12
|
+
export declare function restartGateway(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* 停掉 gateway:先停掉所有已知的 systemd unit(新 + 旧 unit 名),再按监听
|
|
15
|
+
* 端口兜底杀掉非 systemd 托管的残留进程。顺序见 {@link STOP_GATEWAY_UNITS}。
|
|
16
|
+
*/
|
|
17
|
+
export declare function stopGateway(): Promise<void>;
|
|
18
|
+
/** gateway 运行状态。健康的唯一标准是端口已监听。 */
|
|
19
|
+
export type GatewayState = 'listening' | 'starting' | 'down';
|
|
20
|
+
/**
|
|
21
|
+
* 探测 gateway 状态。**健康的唯一标准是 18789 端口已监听** —— 进程 active
|
|
22
|
+
* 不等于对外可服务。
|
|
23
|
+
*
|
|
24
|
+
* - `listening`:端口已监听,健康。
|
|
25
|
+
* - `starting` :systemd 服务 active,但端口在 bounded wait 内始终没监听 ——
|
|
26
|
+
* 配置异常 / 启动卡住 / 仍在初始化,**不算健康**。
|
|
27
|
+
* - `down` :systemd 服务非 active 且端口未监听。
|
|
4
28
|
*
|
|
5
|
-
*
|
|
29
|
+
* `openclaw gateway restart` 返回后服务立刻是 active,但 gateway 进程还要几秒
|
|
30
|
+
* 才 bind 端口。所以端口没起来、服务却 active 时给一段 bounded wait 覆盖这个
|
|
31
|
+
* 启动窗口;服务都不 active 则直接 `down`,不等。
|
|
32
|
+
*/
|
|
33
|
+
export declare function probeGatewayState(): Promise<GatewayState>;
|
|
34
|
+
/**
|
|
35
|
+
* 清掉 systemd user 目录下的 gateway unit 残留。`openclaw gateway uninstall`
|
|
36
|
+
* 只删主 `.service` 文件,残留的 `.service.bak` 备份和 `.service.d/` drop-in
|
|
37
|
+
* 会在下次 install 时被 systemd 自动 merge 进来(注入过时的 env 等),必须一并清。
|
|
38
|
+
*/
|
|
39
|
+
export declare function cleanupGatewayServiceFiles(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Best-effort stop of the openclaw gateway so cli operations have exclusive
|
|
42
|
+
* write access to openclaw.json + extensions/.
|
|
43
|
+
*
|
|
44
|
+
* Why this is needed: the gateway has a config file watcher that writes its
|
|
6
45
|
* own metadata back into openclaw.json on every config change. Concurrent
|
|
7
46
|
* writes during cli's cleanup / `openclaw plugins install` / `openclaw config
|
|
8
47
|
* set` race with that watcher and produce:
|
|
@@ -10,12 +49,8 @@
|
|
|
10
49
|
* - ConfigMutationConflictError: config changed since last load (hash check
|
|
11
50
|
* in openclaw plugins install commit / openclaw config set atomic write)
|
|
12
51
|
*
|
|
13
|
-
* Tries every supervisor we know of, each tolerated if absent. Order matters:
|
|
14
|
-
* ask the supervisor (openclaw cli / systemd) first so it doesn't auto-restart
|
|
15
|
-
* on us, then pkill -9 as the last resort.
|
|
16
|
-
*
|
|
17
52
|
* Bootstrap orchestrator (commands/install.ts) is responsible for restarting
|
|
18
|
-
* the
|
|
53
|
+
* the gateway after the full component install pipeline finishes.
|
|
19
54
|
*
|
|
20
55
|
* @param context A short label for logs, e.g. "dingtalk install" or
|
|
21
56
|
* "openclaw deployment defaults".
|
|
@@ -1,10 +1,137 @@
|
|
|
1
|
-
import { shell } from './shell.js';
|
|
1
|
+
import { shell, shellCapture } from './shell.js';
|
|
2
2
|
import { info } from './logger.js';
|
|
3
|
+
import { OPENCLAW_GATEWAY_PORT } from './constants.js';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
* exclusive write access to openclaw.json + extensions/.
|
|
5
|
+
* openclaw gateway 生命周期管理。
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* 关键决策:gateway 交给 openclaw 自带的 systemd 服务管理,cli 不再自己用
|
|
8
|
+
* nohup + ps + pkill 管进程。
|
|
9
|
+
*
|
|
10
|
+
* 为什么:openclaw 2026.5 的 gateway 有自己的单实例 lock、restart-handoff、
|
|
11
|
+
* 进程改名(`openclaw` / `node`)机制。cli 旧实现按进程名 `openclaw-gateway`
|
|
12
|
+
* 识别 + nohup 拉起 + 手动 kill,实测都顶不住:
|
|
13
|
+
* - 进程名匹配 0 个 → restart 存活检测恒失败,报 E_RESTART_FAILED
|
|
14
|
+
* (即使 gateway 其实已经起来了)
|
|
15
|
+
* - 改用 `openclaw gateway run --force` + nohup,会和 openclaw 自身的
|
|
16
|
+
* lock / handoff 互相赛跑 → 双进程、端口悬空、健康检查 abnormal closure
|
|
17
|
+
* 而 `openclaw gateway install/start/stop/restart`(systemd user 服务)实测
|
|
18
|
+
* 连续重启始终单进程、端口干净、状态准确。所以一律走 openclaw 的 service 命令。
|
|
19
|
+
*/
|
|
20
|
+
// gateway / systemctl 命令的环境前缀。
|
|
21
|
+
//
|
|
22
|
+
// unset SUDO_*:cli 在非 root 登录的主机(如 AWS Ubuntu AMI 的 ubuntu 用户)
|
|
23
|
+
// 上由 os-api 用 `sudo -H` 提权到 root 跑。`sudo -H` 把 HOME 设成 /root,
|
|
24
|
+
// 于是 `openclaw gateway install` 把 unit 文件写进 /root/.config/systemd/user/;
|
|
25
|
+
// 但 openclaw 又据 SUDO_USER 判定"当前用户是 ubuntu",enable 时跑的是
|
|
26
|
+
// `systemctl --machine ubuntu@ --user ...` —— 去 ubuntu 的 systemd 里找 unit,
|
|
27
|
+
// 找不到 → "Unit file does not exist" → install 失败。unset 掉 SUDO_* 让
|
|
28
|
+
// openclaw 当成纯 root 调用,写 unit 与操作 systemd 都对着 root,一致。
|
|
29
|
+
// XDG_RUNTIME_DIR:systemctl --user 需要它;非交互 SSH exec 下通常已由
|
|
30
|
+
// pam_systemd 注入,这里再兜底一次,防个别主机 sshd PAM 配置不注入。
|
|
31
|
+
const SYSTEMD_ENV = 'unset SUDO_USER SUDO_UID SUDO_GID; ' +
|
|
32
|
+
'export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"; ';
|
|
33
|
+
// gateway 没被 systemd 接管时(老主机残留 / 异常)按监听端口兜底杀进程。
|
|
34
|
+
// 覆盖 `openclaw` / `node` 两种进程名;且绝不会误杀正在执行本 CLI 的进程。
|
|
35
|
+
// 用 awk 解析 `pid=NNN` 而不是 `grep -oP` —— grep 的 -P(PCRE,含 \K)是 GNU
|
|
36
|
+
// 扩展,非 GNU 环境(BSD grep 等)会整条命令报错、兜底路径静默退化成 no-op。
|
|
37
|
+
// awk -F'pid=' 把每个 `pid=` 后的字段数值化($i+0 取前导数字),POSIX 通用。
|
|
38
|
+
const KILL_GATEWAY_BY_PORT = `ss -ltnHp 'sport = :${OPENCLAW_GATEWAY_PORT}' 2>/dev/null` +
|
|
39
|
+
` | awk -F'pid=' '{for(i=2;i<=NF;i++){p=$i+0;if(p>0)print p}}'` +
|
|
40
|
+
` | sort -u | xargs -r kill 2>/dev/null || true`;
|
|
41
|
+
/**
|
|
42
|
+
* 确保 gateway 的 systemd 服务已安装且能常驻。
|
|
43
|
+
* - `loginctl enable-linger`:systemd user 服务默认随最后一个登录会话退出而停,
|
|
44
|
+
* 开 linger 后才能在部署 SSH 断开后 / 主机重启后继续运行。
|
|
45
|
+
* - `openclaw gateway install --force`:幂等(重装覆盖),顺带在 openclaw 升级后
|
|
46
|
+
* 刷新 unit 的 ExecStart。
|
|
47
|
+
*/
|
|
48
|
+
export async function installGatewayService() {
|
|
49
|
+
await shell(`loginctl enable-linger root 2>/dev/null || true`).catch(() => { });
|
|
50
|
+
await shell(`${SYSTEMD_ENV}openclaw gateway install --force --port ${OPENCLAW_GATEWAY_PORT}`);
|
|
51
|
+
}
|
|
52
|
+
/** 启动 gateway(先确保 systemd 服务已装)。 */
|
|
53
|
+
export async function startGateway() {
|
|
54
|
+
await installGatewayService();
|
|
55
|
+
await shell(`${SYSTEMD_ENV}openclaw gateway start`);
|
|
56
|
+
}
|
|
57
|
+
/** 重启 gateway(先确保 systemd 服务已装)。 */
|
|
58
|
+
export async function restartGateway() {
|
|
59
|
+
await installGatewayService();
|
|
60
|
+
await shell(`${SYSTEMD_ENV}openclaw gateway restart`);
|
|
61
|
+
}
|
|
62
|
+
// 停掉所有已知的 gateway systemd unit。新版 openclaw 的 unit 名是
|
|
63
|
+
// openclaw-gateway.service;老主机可能是 openclaw.service(早期 cli 用过的
|
|
64
|
+
// unit 名,--user / system 两种 scope 都覆盖)。
|
|
65
|
+
//
|
|
66
|
+
// **必须在按端口 kill 之前先停 unit**:先停 unit,systemd 视为"主动停止"、
|
|
67
|
+
// 不会触发 Restart=;反过来先 kill 进程,systemd 当成异常退出,会按
|
|
68
|
+
// Restart=always/on-failure 立刻把 gateway 拉回来 —— stopDaemonForExclusiveAccess
|
|
69
|
+
// 就拿不到真正的独占窗口,config watcher 写配置的竞争(ConfigMutationConflict)复现。
|
|
70
|
+
// 按端口 kill 只作为非 systemd 托管残留进程的兜底,不能替代停 supervisor。
|
|
71
|
+
const STOP_GATEWAY_UNITS = `${SYSTEMD_ENV}` +
|
|
72
|
+
`openclaw gateway stop 2>/dev/null || true; ` +
|
|
73
|
+
`systemctl --user stop openclaw-gateway.service 2>/dev/null || true; ` +
|
|
74
|
+
`systemctl --user stop openclaw.service 2>/dev/null || true; ` +
|
|
75
|
+
`systemctl stop openclaw.service 2>/dev/null || true`;
|
|
76
|
+
/**
|
|
77
|
+
* 停掉 gateway:先停掉所有已知的 systemd unit(新 + 旧 unit 名),再按监听
|
|
78
|
+
* 端口兜底杀掉非 systemd 托管的残留进程。顺序见 {@link STOP_GATEWAY_UNITS}。
|
|
79
|
+
*/
|
|
80
|
+
export async function stopGateway() {
|
|
81
|
+
await shell(STOP_GATEWAY_UNITS).catch(() => { });
|
|
82
|
+
await shell(KILL_GATEWAY_BY_PORT).catch(() => { });
|
|
83
|
+
}
|
|
84
|
+
// `active 但端口未监听` 的最长等待:覆盖 restart 后进程已 active、端口还没
|
|
85
|
+
// bind 的启动窗口。等满仍未监听就判 starting(配置异常 / 卡住),不再傻等。
|
|
86
|
+
const STATUS_PORT_WAIT_ATTEMPTS = 20;
|
|
87
|
+
async function isPortListening() {
|
|
88
|
+
const r = await shellCapture(`ss -ltnH 'sport = :${OPENCLAW_GATEWAY_PORT}' 2>/dev/null || true`);
|
|
89
|
+
return r.stdout.trim().length > 0;
|
|
90
|
+
}
|
|
91
|
+
async function isServiceActive() {
|
|
92
|
+
const r = await shellCapture(`${SYSTEMD_ENV}systemctl --user is-active openclaw-gateway.service 2>/dev/null || true`);
|
|
93
|
+
return r.stdout.trim() === 'active';
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 探测 gateway 状态。**健康的唯一标准是 18789 端口已监听** —— 进程 active
|
|
97
|
+
* 不等于对外可服务。
|
|
98
|
+
*
|
|
99
|
+
* - `listening`:端口已监听,健康。
|
|
100
|
+
* - `starting` :systemd 服务 active,但端口在 bounded wait 内始终没监听 ——
|
|
101
|
+
* 配置异常 / 启动卡住 / 仍在初始化,**不算健康**。
|
|
102
|
+
* - `down` :systemd 服务非 active 且端口未监听。
|
|
103
|
+
*
|
|
104
|
+
* `openclaw gateway restart` 返回后服务立刻是 active,但 gateway 进程还要几秒
|
|
105
|
+
* 才 bind 端口。所以端口没起来、服务却 active 时给一段 bounded wait 覆盖这个
|
|
106
|
+
* 启动窗口;服务都不 active 则直接 `down`,不等。
|
|
107
|
+
*/
|
|
108
|
+
export async function probeGatewayState() {
|
|
109
|
+
if (await isPortListening())
|
|
110
|
+
return 'listening';
|
|
111
|
+
if (!(await isServiceActive()))
|
|
112
|
+
return 'down';
|
|
113
|
+
for (let i = 0; i < STATUS_PORT_WAIT_ATTEMPTS; i++) {
|
|
114
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
115
|
+
if (await isPortListening())
|
|
116
|
+
return 'listening';
|
|
117
|
+
}
|
|
118
|
+
return 'starting';
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 清掉 systemd user 目录下的 gateway unit 残留。`openclaw gateway uninstall`
|
|
122
|
+
* 只删主 `.service` 文件,残留的 `.service.bak` 备份和 `.service.d/` drop-in
|
|
123
|
+
* 会在下次 install 时被 systemd 自动 merge 进来(注入过时的 env 等),必须一并清。
|
|
124
|
+
*/
|
|
125
|
+
export async function cleanupGatewayServiceFiles() {
|
|
126
|
+
await shell(`${SYSTEMD_ENV}rm -rf /root/.config/systemd/user/openclaw-gateway.service.d` +
|
|
127
|
+
` /root/.config/systemd/user/openclaw-gateway.service.bak;` +
|
|
128
|
+
` systemctl --user daemon-reload 2>/dev/null || true`).catch(() => { });
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Best-effort stop of the openclaw gateway so cli operations have exclusive
|
|
132
|
+
* write access to openclaw.json + extensions/.
|
|
133
|
+
*
|
|
134
|
+
* Why this is needed: the gateway has a config file watcher that writes its
|
|
8
135
|
* own metadata back into openclaw.json on every config change. Concurrent
|
|
9
136
|
* writes during cli's cleanup / `openclaw plugins install` / `openclaw config
|
|
10
137
|
* set` race with that watcher and produce:
|
|
@@ -12,27 +139,16 @@ import { info } from './logger.js';
|
|
|
12
139
|
* - ConfigMutationConflictError: config changed since last load (hash check
|
|
13
140
|
* in openclaw plugins install commit / openclaw config set atomic write)
|
|
14
141
|
*
|
|
15
|
-
* Tries every supervisor we know of, each tolerated if absent. Order matters:
|
|
16
|
-
* ask the supervisor (openclaw cli / systemd) first so it doesn't auto-restart
|
|
17
|
-
* on us, then pkill -9 as the last resort.
|
|
18
|
-
*
|
|
19
142
|
* Bootstrap orchestrator (commands/install.ts) is responsible for restarting
|
|
20
|
-
* the
|
|
143
|
+
* the gateway after the full component install pipeline finishes.
|
|
21
144
|
*
|
|
22
145
|
* @param context A short label for logs, e.g. "dingtalk install" or
|
|
23
146
|
* "openclaw deployment defaults".
|
|
24
147
|
*/
|
|
25
148
|
export async function stopDaemonForExclusiveAccess(context) {
|
|
26
149
|
info(`Stopping openclaw gateway for exclusive access during ${context}...`);
|
|
27
|
-
await
|
|
28
|
-
|
|
29
|
-
await shell(`systemctl stop openclaw 2>/dev/null || true`).catch(() => { });
|
|
30
|
-
// Match `pkill -f 'openclaw-gateway'` exactly the same way as
|
|
31
|
-
// OpenclawInstaller.uninstall — narrow enough that we don't kill the cli
|
|
32
|
-
// process running this code, broad enough to catch the gateway daemon.
|
|
33
|
-
await shell(`pkill -9 -f 'openclaw-gateway' 2>/dev/null || true`).catch(() => { });
|
|
34
|
-
// 1.5s is enough for systemd's default RestartSec (100ms) to fire if it
|
|
35
|
-
// would, and short enough not to drag deploy time noticeably.
|
|
150
|
+
await stopGateway();
|
|
151
|
+
// `systemctl stop` 是显式停,Restart=always 不会把它拉回来;留 1.5s 兜底观察。
|
|
36
152
|
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
37
153
|
}
|
|
38
154
|
//# sourceMappingURL=openclaw-daemon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openclaw-daemon.js","sourceRoot":"","sources":["../../src/utils/openclaw-daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"openclaw-daemon.js","sourceRoot":"","sources":["../../src/utils/openclaw-daemon.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED