@lark-apaas/openclaw-scripts-diagnose-cli 0.1.15-alpha.12 → 0.1.15-alpha.13
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/index.cjs +144 -30
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,7 +52,7 @@ node_assert = __toESM(node_assert);
|
|
|
52
52
|
* it terse and parseable.
|
|
53
53
|
*/
|
|
54
54
|
function getVersion() {
|
|
55
|
-
return "0.1.15-alpha.
|
|
55
|
+
return "0.1.15-alpha.13";
|
|
56
56
|
}
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/rule-engine/base.ts
|
|
@@ -2634,6 +2634,12 @@ const SECRETS_FILE_PATH = "/home/gem/workspace/.force/openclaw/miaoda-openclaw-s
|
|
|
2634
2634
|
/** Absolute path to the openclaw config JSON. */
|
|
2635
2635
|
const CONFIG_PATH = `${WORKSPACE_DIR}/openclaw.json`;
|
|
2636
2636
|
/**
|
|
2637
|
+
* upgrade-lark 场景专属修复状态的信号文件目录。
|
|
2638
|
+
* fixStatus 有值时在此目录下创建同名文件(如 /tmp/event/PORT_FIX_READY),
|
|
2639
|
+
* 文件内容为完整的 UpgradeLarkResult JSON,供外部进程轮询感知升级结果。
|
|
2640
|
+
*/
|
|
2641
|
+
const FIX_EVENT_DIR = "/tmp/event";
|
|
2642
|
+
/**
|
|
2637
2643
|
* upgrade-lark 每次运行的日志文件路径,含时间戳便于按时间排序定位。
|
|
2638
2644
|
* checkOnly=true 时文件名含 "-check" 后缀,便于与正式安装日志区分。
|
|
2639
2645
|
*/
|
|
@@ -3313,6 +3319,13 @@ function execCaptureErr(cmd) {
|
|
|
3313
3319
|
throw new Error(stderrStr ? `${base}\nstderr: ${stderrStr}` : base);
|
|
3314
3320
|
}
|
|
3315
3321
|
}
|
|
3322
|
+
/**
|
|
3323
|
+
* Synchronous sleep using Atomics.wait on a shared buffer.
|
|
3324
|
+
* Works on the main thread (unlike setTimeout which requires an event loop tick).
|
|
3325
|
+
*/
|
|
3326
|
+
function sleepSync(ms) {
|
|
3327
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
3328
|
+
}
|
|
3316
3329
|
/** POSIX single-quote shell escape. Paths with embedded quotes are rare but
|
|
3317
3330
|
* the token-file path conventions in sandboxes don't guarantee cleanliness. */
|
|
3318
3331
|
function shellQuote(s) {
|
|
@@ -7365,14 +7378,6 @@ function getResetTask(taskId) {
|
|
|
7365
7378
|
progress: "等待中..."
|
|
7366
7379
|
};
|
|
7367
7380
|
}
|
|
7368
|
-
/**
|
|
7369
|
-
* Synchronous sleep using Atomics.wait on a shared buffer.
|
|
7370
|
-
*/
|
|
7371
|
-
function sleepSync(ms) {
|
|
7372
|
-
const buf = new SharedArrayBuffer(4);
|
|
7373
|
-
const arr = new Int32Array(buf);
|
|
7374
|
-
Atomics.wait(arr, 0, 0, ms);
|
|
7375
|
-
}
|
|
7376
7381
|
//#endregion
|
|
7377
7382
|
//#region src/oss/resolveOssFileMap.ts
|
|
7378
7383
|
/**
|
|
@@ -10692,7 +10697,7 @@ async function reportCliRun(opts) {
|
|
|
10692
10697
|
//#region src/help.ts
|
|
10693
10698
|
const BIN = "mclaw-diagnose";
|
|
10694
10699
|
function versionBanner() {
|
|
10695
|
-
return `v0.1.15-alpha.
|
|
10700
|
+
return `v0.1.15-alpha.13`;
|
|
10696
10701
|
}
|
|
10697
10702
|
const COMMANDS = [
|
|
10698
10703
|
{
|
|
@@ -11295,6 +11300,7 @@ function reportDoctorRunToSlardar(opts) {
|
|
|
11295
11300
|
* - rollback_ok:回滚是否成功(对应 UpgradeLarkResult.rollbackOk,未触发回滚时为空)
|
|
11296
11301
|
* - validation_error:安装后校验失败信息(对应 UpgradeLarkResult.validationError)
|
|
11297
11302
|
* - error:命令级错误信息(对应 UpgradeLarkResult.error)
|
|
11303
|
+
* - port_check_ok:端口存活检测结果(对应 UpgradeLarkResult.portCheckOk,未执行时为空)
|
|
11298
11304
|
* - result:执行结果一行摘要(派生字段,见 buildUpgradeLarkResultSummary)
|
|
11299
11305
|
* - log_file:日志文件绝对路径(对应 UpgradeLarkResult.logFile)
|
|
11300
11306
|
*
|
|
@@ -11325,6 +11331,7 @@ function reportUpgradeLarkToSlardar(opts) {
|
|
|
11325
11331
|
rollback_ok: String(opts.rollbackOk ?? ""),
|
|
11326
11332
|
validation_error: opts.validationError ?? "",
|
|
11327
11333
|
error: opts.error ?? "",
|
|
11334
|
+
port_check_ok: String(opts.portCheckOk ?? ""),
|
|
11328
11335
|
result: opts.resultSummary,
|
|
11329
11336
|
log_file: opts.logFile
|
|
11330
11337
|
},
|
|
@@ -11334,7 +11341,8 @@ function reportUpgradeLarkToSlardar(opts) {
|
|
|
11334
11341
|
backup_ms: t.backupMs ?? -1,
|
|
11335
11342
|
npx_install_ms: t.npxInstallMs ?? -1,
|
|
11336
11343
|
post_probe_ms: t.postProbeMs ?? -1,
|
|
11337
|
-
doctor_fix_ms: t.doctorFixMs ?? -1
|
|
11344
|
+
doctor_fix_ms: t.doctorFixMs ?? -1,
|
|
11345
|
+
port_check_ms: t.portCheckMs ?? -1
|
|
11338
11346
|
}
|
|
11339
11347
|
});
|
|
11340
11348
|
}
|
|
@@ -11493,6 +11501,82 @@ function probeChannels(label, log, timeoutMs) {
|
|
|
11493
11501
|
};
|
|
11494
11502
|
}
|
|
11495
11503
|
}
|
|
11504
|
+
/**
|
|
11505
|
+
* 根据 scene、最终状态和端口检测结果,计算场景专属修复状态。
|
|
11506
|
+
* scene 不在已知场景列表时返回 undefined。
|
|
11507
|
+
*/
|
|
11508
|
+
function computeFixStatus(scene, status, portCheckOk = void 0) {
|
|
11509
|
+
if (scene === "FromPreviewFailed") return status === "success" && portCheckOk !== false ? "PORT_FIX_READY" : "PORT_FIX_FAILED";
|
|
11510
|
+
if (scene === "FromChannelFailed") return status === "success" ? "CHANNEL_FIX_READY" : "CHANNEL_FIX_FAILED";
|
|
11511
|
+
}
|
|
11512
|
+
/**
|
|
11513
|
+
* 轮询端口检测脚本,确认 openclaw-gateway 在重启后监听指定端口。
|
|
11514
|
+
*
|
|
11515
|
+
* 逻辑:
|
|
11516
|
+
* 1. 先等待 initialWaitMs(让服务有时间完成重启)
|
|
11517
|
+
* 2. 循环执行 `bash ${BUILTIN_PATH}/tool/port_check.sh <port>`,至多 maxAttempts 次:
|
|
11518
|
+
* - 输出为空 → 服务尚未就绪,等 intervalMs 后重试
|
|
11519
|
+
* - 输出含端口号 → 端口存活,返回 ok=true
|
|
11520
|
+
* - 输出非空但不含端口号 → 端口异常,立即返回 ok=false
|
|
11521
|
+
* 3. 超过 maxAttempts 仍无响应 → 返回 ok=false
|
|
11522
|
+
*
|
|
11523
|
+
* 注意:${BUILTIN_PATH} 是沙箱 shell 环境变量,通过 `bash -c` 让 shell 自行展开,
|
|
11524
|
+
* Node 侧不读取、不拼接该路径。
|
|
11525
|
+
*/
|
|
11526
|
+
function pollPortCheck(opts) {
|
|
11527
|
+
const { port, initialWaitMs, intervalMs, maxAttempts, log } = opts;
|
|
11528
|
+
const portStr = String(port);
|
|
11529
|
+
const cmd = "bash ${BUILTIN_PATH}/tool/port_check.sh " + portStr;
|
|
11530
|
+
log(` waiting ${initialWaitMs / 1e3}s before first port-check poll...`);
|
|
11531
|
+
if (initialWaitMs > 0) sleepSync(initialWaitMs);
|
|
11532
|
+
for (let i = 1; i <= maxAttempts; i++) {
|
|
11533
|
+
const r = (0, node_child_process.spawnSync)("bash", ["-c", cmd], {
|
|
11534
|
+
encoding: "utf-8",
|
|
11535
|
+
stdio: [
|
|
11536
|
+
"ignore",
|
|
11537
|
+
"pipe",
|
|
11538
|
+
"pipe"
|
|
11539
|
+
],
|
|
11540
|
+
timeout: 1e4
|
|
11541
|
+
});
|
|
11542
|
+
const output = (r.stdout ?? "").trim();
|
|
11543
|
+
const errout = (r.stderr ?? "").trim();
|
|
11544
|
+
log(` port-check [${i}/${maxAttempts}]: exit=${r.status ?? "null"} output=${JSON.stringify(output)}${errout ? ` stderr=${JSON.stringify(errout)}` : ""}`);
|
|
11545
|
+
if (!output) {
|
|
11546
|
+
sleepSync(intervalMs);
|
|
11547
|
+
continue;
|
|
11548
|
+
}
|
|
11549
|
+
if (output.includes(portStr)) {
|
|
11550
|
+
log(` port-check: SUCCESS — port ${port} confirmed in output`);
|
|
11551
|
+
return {
|
|
11552
|
+
ok: true,
|
|
11553
|
+
output
|
|
11554
|
+
};
|
|
11555
|
+
}
|
|
11556
|
+
log(` port-check: FAILED — output non-empty but port ${port} not found`);
|
|
11557
|
+
return {
|
|
11558
|
+
ok: false,
|
|
11559
|
+
output
|
|
11560
|
+
};
|
|
11561
|
+
}
|
|
11562
|
+
log(` port-check: FAILED — no response after ${maxAttempts} attempts`);
|
|
11563
|
+
return { ok: false };
|
|
11564
|
+
}
|
|
11565
|
+
/**
|
|
11566
|
+
* 将 fixStatus 信号文件写入 /tmp/event/<fixStatus>,内容为完整的 UpgradeLarkResult JSON。
|
|
11567
|
+
* 外部进程(如服务端诊断流程)通过轮询此文件感知升级结果。
|
|
11568
|
+
* 写入失败只记录日志,不影响主流程返回值。
|
|
11569
|
+
*/
|
|
11570
|
+
function writeFixStatusEvent(fixStatus, result, log) {
|
|
11571
|
+
const filePath = `${FIX_EVENT_DIR}/${fixStatus}`;
|
|
11572
|
+
try {
|
|
11573
|
+
node_fs.default.mkdirSync(FIX_EVENT_DIR, { recursive: true });
|
|
11574
|
+
node_fs.default.writeFileSync(filePath, JSON.stringify(result, null, 2));
|
|
11575
|
+
log(`[fix-event] written: ${filePath}`);
|
|
11576
|
+
} catch (e) {
|
|
11577
|
+
log(`[fix-event] write failed: ${filePath} — ${e.message}`);
|
|
11578
|
+
}
|
|
11579
|
+
}
|
|
11496
11580
|
function runUpgradeLark(opts) {
|
|
11497
11581
|
const cwd = opts.cwd ?? "/home/gem/workspace/agent";
|
|
11498
11582
|
const configPath = opts.configPath ?? CONFIG_PATH;
|
|
@@ -11512,6 +11596,10 @@ function runUpgradeLark(opts) {
|
|
|
11512
11596
|
log(` configPath : ${configPath}`);
|
|
11513
11597
|
log(`${"=".repeat(60)}`);
|
|
11514
11598
|
const timing = {};
|
|
11599
|
+
const finalReturn = (r) => {
|
|
11600
|
+
if (r.fixStatus !== void 0) writeFixStatusEvent(r.fixStatus, r, log);
|
|
11601
|
+
return r;
|
|
11602
|
+
};
|
|
11515
11603
|
log("");
|
|
11516
11604
|
log("── [Pre-check A] channels probe(升级前)────────────────");
|
|
11517
11605
|
const t_preProbeStart = Date.now();
|
|
@@ -11550,13 +11638,14 @@ function runUpgradeLark(opts) {
|
|
|
11550
11638
|
log(`${"=".repeat(60)}`);
|
|
11551
11639
|
log("upgrade-lark skipped (pre-check gate)");
|
|
11552
11640
|
log(`${"=".repeat(60)}`);
|
|
11553
|
-
return {
|
|
11641
|
+
return finalReturn({
|
|
11554
11642
|
status: "skipped",
|
|
11555
11643
|
skipReason: reason,
|
|
11556
11644
|
upgradeNeeded: false,
|
|
11557
11645
|
timing,
|
|
11558
|
-
logFile
|
|
11559
|
-
|
|
11646
|
+
logFile,
|
|
11647
|
+
fixStatus: computeFixStatus(opts.scene, "skipped")
|
|
11648
|
+
});
|
|
11560
11649
|
}
|
|
11561
11650
|
if (beforeChannels.anyAccountWorking) {
|
|
11562
11651
|
const reason = "channels are working — upgrade not needed (issue detected but system is functional)";
|
|
@@ -11564,13 +11653,14 @@ function runUpgradeLark(opts) {
|
|
|
11564
11653
|
log(`${"=".repeat(60)}`);
|
|
11565
11654
|
log("upgrade-lark skipped (pre-check gate)");
|
|
11566
11655
|
log(`${"=".repeat(60)}`);
|
|
11567
|
-
return {
|
|
11656
|
+
return finalReturn({
|
|
11568
11657
|
status: "skipped",
|
|
11569
11658
|
skipReason: reason,
|
|
11570
11659
|
upgradeNeeded: false,
|
|
11571
11660
|
timing,
|
|
11572
|
-
logFile
|
|
11573
|
-
|
|
11661
|
+
logFile,
|
|
11662
|
+
fixStatus: computeFixStatus(opts.scene, "skipped")
|
|
11663
|
+
});
|
|
11574
11664
|
}
|
|
11575
11665
|
log(` PROCEED: requiresLarkUpgrade=true (version=${versionIncompatible}, feishuConfig=${feishuConfigInvalid}) AND channels not working → running upgrade`);
|
|
11576
11666
|
if (opts.checkOnly) {
|
|
@@ -11578,13 +11668,13 @@ function runUpgradeLark(opts) {
|
|
|
11578
11668
|
log(`${"=".repeat(60)}`);
|
|
11579
11669
|
log("upgrade-lark check complete");
|
|
11580
11670
|
log(`${"=".repeat(60)}`);
|
|
11581
|
-
return {
|
|
11671
|
+
return finalReturn({
|
|
11582
11672
|
status: "skipped",
|
|
11583
11673
|
skipReason: "check",
|
|
11584
11674
|
upgradeNeeded: true,
|
|
11585
11675
|
timing,
|
|
11586
11676
|
logFile
|
|
11587
|
-
};
|
|
11677
|
+
});
|
|
11588
11678
|
}
|
|
11589
11679
|
log("");
|
|
11590
11680
|
log("── [1/6] 文件备份 ────────────────────────────────────────");
|
|
@@ -11594,12 +11684,13 @@ function runUpgradeLark(opts) {
|
|
|
11594
11684
|
timing.backupMs = Date.now() - t_backupStart;
|
|
11595
11685
|
if (!backup.ok) {
|
|
11596
11686
|
log(`ERROR: ${backup.error}`);
|
|
11597
|
-
return {
|
|
11687
|
+
return finalReturn({
|
|
11598
11688
|
status: "failed",
|
|
11599
11689
|
error: backup.error,
|
|
11600
11690
|
timing,
|
|
11601
|
-
logFile
|
|
11602
|
-
|
|
11691
|
+
logFile,
|
|
11692
|
+
fixStatus: computeFixStatus(opts.scene, "failed")
|
|
11693
|
+
});
|
|
11603
11694
|
}
|
|
11604
11695
|
log("backup: ok");
|
|
11605
11696
|
logVersionSnapshot("before-versions", snapshotVersions(cwd, log), log);
|
|
@@ -11640,14 +11731,14 @@ function runUpgradeLark(opts) {
|
|
|
11640
11731
|
if (statusCheckDelayMs > 0) {
|
|
11641
11732
|
log("");
|
|
11642
11733
|
log(`── 等待 ${statusCheckDelayMs / 1e3}s(让 openclaw 服务完成重启) ─────────────`);
|
|
11643
|
-
|
|
11734
|
+
sleepSync(statusCheckDelayMs);
|
|
11644
11735
|
log("wait done");
|
|
11645
11736
|
}
|
|
11646
11737
|
const doRollback = (reason) => {
|
|
11647
11738
|
log(`ERROR: ${reason}`);
|
|
11648
11739
|
const rollbackOk = restoreFiles(fsOpts);
|
|
11649
11740
|
log(`rollback: ${rollbackOk ? "ok" : "FAILED"}`);
|
|
11650
|
-
return {
|
|
11741
|
+
return finalReturn({
|
|
11651
11742
|
status: "failed",
|
|
11652
11743
|
error: reason,
|
|
11653
11744
|
validationError: reason,
|
|
@@ -11656,8 +11747,9 @@ function runUpgradeLark(opts) {
|
|
|
11656
11747
|
exitCode: npxExitCode,
|
|
11657
11748
|
rollbackOk,
|
|
11658
11749
|
timing,
|
|
11659
|
-
logFile
|
|
11660
|
-
|
|
11750
|
+
logFile,
|
|
11751
|
+
fixStatus: computeFixStatus(opts.scene, "failed")
|
|
11752
|
+
});
|
|
11661
11753
|
};
|
|
11662
11754
|
log("");
|
|
11663
11755
|
log("── [4/5] 安装后诊断校验 ─────────────────────────────────");
|
|
@@ -11709,8 +11801,9 @@ function runUpgradeLark(opts) {
|
|
|
11709
11801
|
if (fixResult.stderr?.trim()) log(`doctor(fix) stderr:\n${fixResult.stderr.trim()}`);
|
|
11710
11802
|
log(`doctor(fix) exit: ${fixResult.status ?? "null"}${fixResult.error ? ` error: ${fixResult.error.message}` : ""}`);
|
|
11711
11803
|
log("");
|
|
11712
|
-
log("── [7/
|
|
11804
|
+
log("── [7/8] 重启 openclaw 服务 ──────────────────────────────");
|
|
11713
11805
|
const restartScript = "/opt/force/bin/openclaw_scripts/restart.sh";
|
|
11806
|
+
let restartExecuted = false;
|
|
11714
11807
|
if (opts.skipRestart) log(" skipped: --skip-restart");
|
|
11715
11808
|
else if (node_fs.default.existsSync(restartScript)) {
|
|
11716
11809
|
const t_restart = Date.now();
|
|
@@ -11727,19 +11820,39 @@ function runUpgradeLark(opts) {
|
|
|
11727
11820
|
if (restartResult.stdout?.trim()) log(` restart stdout:\n${restartResult.stdout.trim()}`);
|
|
11728
11821
|
if (restartResult.stderr?.trim()) log(` restart stderr:\n${restartResult.stderr.trim()}`);
|
|
11729
11822
|
log(` restart.sh exit: ${restartResult.status ?? "null"} (${restartMs}ms)${restartResult.error ? ` error: ${restartResult.error.message}` : ""}`);
|
|
11823
|
+
restartExecuted = true;
|
|
11730
11824
|
} else log(` skipped: ${restartScript} not found`);
|
|
11731
11825
|
log("");
|
|
11826
|
+
log("── [8/8] 端口存活检测 ────────────────────────────────────");
|
|
11827
|
+
let portCheckOk;
|
|
11828
|
+
if (!restartExecuted) log(" skipped: restart was not executed");
|
|
11829
|
+
else {
|
|
11830
|
+
const t_portCheck = Date.now();
|
|
11831
|
+
const pcResult = pollPortCheck({
|
|
11832
|
+
port: 18789,
|
|
11833
|
+
initialWaitMs: opts.portCheckInitialWaitMs ?? 3e3,
|
|
11834
|
+
intervalMs: opts.portCheckIntervalMs ?? 1e3,
|
|
11835
|
+
maxAttempts: opts.portCheckMaxAttempts ?? 30,
|
|
11836
|
+
log
|
|
11837
|
+
});
|
|
11838
|
+
timing.portCheckMs = Date.now() - t_portCheck;
|
|
11839
|
+
portCheckOk = pcResult.ok;
|
|
11840
|
+
log(` port-check result: ${portCheckOk ? "ok" : "FAILED"} (${timing.portCheckMs}ms)`);
|
|
11841
|
+
}
|
|
11842
|
+
log("");
|
|
11732
11843
|
log(`${"=".repeat(60)}`);
|
|
11733
11844
|
log("upgrade-lark completed successfully");
|
|
11734
11845
|
log(`${"=".repeat(60)}`);
|
|
11735
|
-
return {
|
|
11846
|
+
return finalReturn({
|
|
11736
11847
|
status: "success",
|
|
11737
11848
|
stdout: npxStdout,
|
|
11738
11849
|
stderr: npxStderr,
|
|
11739
11850
|
exitCode: npxExitCode,
|
|
11851
|
+
portCheckOk,
|
|
11740
11852
|
timing,
|
|
11741
|
-
logFile
|
|
11742
|
-
|
|
11853
|
+
logFile,
|
|
11854
|
+
fixStatus: computeFixStatus(opts.scene, "success", portCheckOk)
|
|
11855
|
+
});
|
|
11743
11856
|
}
|
|
11744
11857
|
//#endregion
|
|
11745
11858
|
//#region src/index.ts
|
|
@@ -12255,6 +12368,7 @@ async function main() {
|
|
|
12255
12368
|
rollbackOk: result.rollbackOk,
|
|
12256
12369
|
validationError: result.validationError,
|
|
12257
12370
|
error: result.error,
|
|
12371
|
+
portCheckOk: result.portCheckOk,
|
|
12258
12372
|
timing: result.timing
|
|
12259
12373
|
});
|
|
12260
12374
|
try {
|
package/package.json
CHANGED