@lark-apaas/openclaw-scripts-diagnose-cli 0.1.15-alpha.1 → 0.1.15-alpha.3
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 +105 -33
- 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.3";
|
|
56
56
|
}
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/rule-engine/base.ts
|
|
@@ -2543,9 +2543,13 @@ const PROVIDER_FILE_PATH = "/home/gem/workspace/.force/openclaw/miaoda-provider-
|
|
|
2543
2543
|
const SECRETS_FILE_PATH = "/home/gem/workspace/.force/openclaw/miaoda-openclaw-secrets.json";
|
|
2544
2544
|
/** Absolute path to the openclaw config JSON. */
|
|
2545
2545
|
const CONFIG_PATH = `${WORKSPACE_DIR}/openclaw.json`;
|
|
2546
|
-
/**
|
|
2547
|
-
|
|
2548
|
-
|
|
2546
|
+
/**
|
|
2547
|
+
* upgrade-lark 每次运行的日志文件路径,含时间戳便于按时间排序定位。
|
|
2548
|
+
* checkOnly=true 时文件名含 "-check" 后缀,便于与正式安装日志区分。
|
|
2549
|
+
*/
|
|
2550
|
+
function upgradeLarkLogFile(runId, checkOnly = false) {
|
|
2551
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace(/:/g, "-");
|
|
2552
|
+
return `${DIAGNOSE_DIR}/upgrade-lark${checkOnly ? "-check" : ""}-${ts}-${runId.slice(0, 8)}.log`;
|
|
2549
2553
|
}
|
|
2550
2554
|
//#endregion
|
|
2551
2555
|
//#region src/lark-cli-init.ts
|
|
@@ -10490,6 +10494,7 @@ function runChannelsProbe(timeoutMs = 6e4, { ignoreProbeFailed = true } = {}) {
|
|
|
10490
10494
|
}
|
|
10491
10495
|
if (stdout.trim()) return {
|
|
10492
10496
|
available: true,
|
|
10497
|
+
rawOutput: stdout.trim(),
|
|
10493
10498
|
...parseChannelsProbeOutput(stdout, { ignoreProbeFailed })
|
|
10494
10499
|
};
|
|
10495
10500
|
return {
|
|
@@ -10501,6 +10506,22 @@ function runChannelsProbe(timeoutMs = 6e4, { ignoreProbeFailed = true } = {}) {
|
|
|
10501
10506
|
error: execError ?? "no output from openclaw channels status --probe"
|
|
10502
10507
|
};
|
|
10503
10508
|
}
|
|
10509
|
+
/**
|
|
10510
|
+
* 判断 channels probe 结果是否处于"仅一个 Feishu 默认账号、enabled 但未配置"的状态。
|
|
10511
|
+
*
|
|
10512
|
+
* 这是插件全新安装后的初始状态:npx 工具创建了一个默认账号占位,但用户尚未
|
|
10513
|
+
* 填写 AppID / Secret,因此账号显示为 enabled 但 not configured。
|
|
10514
|
+
* 此时 anyAccountWorking=false(configured 缺失),但安装本身是成功的。
|
|
10515
|
+
*
|
|
10516
|
+
* 用于安装后校验的补充分支:当安装前 channels 不可用,且安装后恰好处于此状态时,
|
|
10517
|
+
* 视为安装成功,不触发回滚。
|
|
10518
|
+
*/
|
|
10519
|
+
function isDefaultOnlyState(result) {
|
|
10520
|
+
if (result.accounts.length !== 1) return false;
|
|
10521
|
+
const acct = result.accounts[0];
|
|
10522
|
+
const bitTokens = new Set(acct.bits.map((b) => b.trim().split(":")[0]));
|
|
10523
|
+
return bitTokens.has("enabled") && !bitTokens.has("configured");
|
|
10524
|
+
}
|
|
10504
10525
|
//#endregion
|
|
10505
10526
|
//#region src/innerapi/reportCliRun.ts
|
|
10506
10527
|
/**
|
|
@@ -10581,7 +10602,7 @@ async function reportCliRun(opts) {
|
|
|
10581
10602
|
//#region src/help.ts
|
|
10582
10603
|
const BIN = "mclaw-diagnose";
|
|
10583
10604
|
function versionBanner() {
|
|
10584
|
-
return `v0.1.15-alpha.
|
|
10605
|
+
return `v0.1.15-alpha.3`;
|
|
10585
10606
|
}
|
|
10586
10607
|
const COMMANDS = [
|
|
10587
10608
|
{
|
|
@@ -10875,7 +10896,7 @@ EXIT CODES
|
|
|
10875
10896
|
hidden: false,
|
|
10876
10897
|
summary: "Upgrade the Feishu/Lark plugin via @larksuite/openclaw-lark-tools",
|
|
10877
10898
|
help: `USAGE
|
|
10878
|
-
${BIN} upgrade-lark [--check-
|
|
10899
|
+
${BIN} upgrade-lark [--check] [--skip-restart] [--scene=<scene>] [--caller=<n>] [--trace-id=<id>]
|
|
10879
10900
|
|
|
10880
10901
|
DESCRIPTION
|
|
10881
10902
|
Upgrades the Feishu/Lark plugin by running:
|
|
@@ -10896,6 +10917,10 @@ DESCRIPTION
|
|
|
10896
10917
|
If the upgrade command fails, or validation fails, the backed-up files are
|
|
10897
10918
|
restored to roll back the changes.
|
|
10898
10919
|
|
|
10920
|
+
After a successful upgrade, the openclaw service is restarted via
|
|
10921
|
+
/opt/force/bin/openclaw_scripts/restart.sh
|
|
10922
|
+
Pass --skip-restart to skip this step (e.g. when restart is handled externally).
|
|
10923
|
+
|
|
10899
10924
|
Execution is logged to /tmp/openclaw-diagnose/upgrade-lark-<runId>.log.
|
|
10900
10925
|
|
|
10901
10926
|
Output is a single JSON object on stdout:
|
|
@@ -10903,13 +10928,14 @@ DESCRIPTION
|
|
|
10903
10928
|
{ "ok": false, "error": "...", "stderr": "...", "exitCode": 1,
|
|
10904
10929
|
"rollbackOk": true, "validationError": "...", "logFile": "..." }
|
|
10905
10930
|
|
|
10906
|
-
With --check
|
|
10931
|
+
With --check:
|
|
10907
10932
|
{ "ok": true, "skipped": true, "upgradeNeeded": false, "logFile": "..." }
|
|
10908
10933
|
{ "ok": true, "skipped": true, "upgradeNeeded": true, "logFile": "..." } ← exit 1
|
|
10909
10934
|
|
|
10910
10935
|
OPTIONS
|
|
10911
|
-
--check
|
|
10936
|
+
--check Diagnose only: run the pre-check gate and report whether
|
|
10912
10937
|
upgrade is needed without installing. Exit 1 if needed.
|
|
10938
|
+
--skip-restart Skip the post-install service restart (default: restart).
|
|
10913
10939
|
--scene=<scene> Telemetry label forwarded to Slardar only.
|
|
10914
10940
|
Known values: PageUpgradeLark, etc. Custom strings accepted.
|
|
10915
10941
|
--caller=<name> Optional metadata passed to innerapi.
|
|
@@ -10919,7 +10945,7 @@ EXIT CODES
|
|
|
10919
10945
|
0 Success: upgrade ran and all validations passed; or gate skipped upgrade.
|
|
10920
10946
|
1 Failure: npx error, validation failed, or git commit failed.
|
|
10921
10947
|
File rollback was attempted (see rollbackOk in the JSON output).
|
|
10922
|
-
With --check
|
|
10948
|
+
With --check: exit 1 means upgrade IS needed.
|
|
10923
10949
|
`
|
|
10924
10950
|
},
|
|
10925
10951
|
{
|
|
@@ -11162,10 +11188,19 @@ function reportDoctorRunToSlardar(opts) {
|
|
|
11162
11188
|
}
|
|
11163
11189
|
});
|
|
11164
11190
|
}
|
|
11165
|
-
|
|
11166
|
-
|
|
11191
|
+
const LOG_PREFIX_RE = /^\[\d{4}-\d{2}-\d{2}T[\d:.]+Z\](?:\s+\[run=[^\]]+\])?\s*/;
|
|
11192
|
+
/**
|
|
11193
|
+
* 读取日志文件末尾最多 maxBytes 字节,过滤噪音后返回纯内容。
|
|
11194
|
+
* - 剥除每行的时间戳 + run tag 前缀
|
|
11195
|
+
* - 过滤纯分隔符行(全为 '=')
|
|
11196
|
+
* 日志头部为固定 banner,有价值的内容集中在末尾,从尾部截取。
|
|
11197
|
+
*/
|
|
11198
|
+
function readLogFileTail(filePath, maxBytes = 4e3) {
|
|
11167
11199
|
try {
|
|
11168
|
-
|
|
11200
|
+
const buf = node_fs.default.readFileSync(filePath);
|
|
11201
|
+
let start = buf.length > maxBytes ? buf.length - maxBytes : 0;
|
|
11202
|
+
while (start < buf.length && buf[start] !== 10) start++;
|
|
11203
|
+
return buf.subarray(start > 0 ? start + 1 : 0).toString("utf-8").split("\n").map((line) => line.replace(LOG_PREFIX_RE, "")).filter((line) => !/^=+$/.test(line.trim())).join("\n").trim();
|
|
11169
11204
|
} catch {
|
|
11170
11205
|
return "";
|
|
11171
11206
|
}
|
|
@@ -11174,21 +11209,22 @@ function readLogFile(filePath) {
|
|
|
11174
11209
|
* 向 Slardar 上报 upgrade-lark 运行结果(upgrade_lark_run 事件)。
|
|
11175
11210
|
*
|
|
11176
11211
|
* extraCategories 记录字符串维度:scene、exit_code、rollback_ok、
|
|
11177
|
-
* validation_error、error_msg、log_content
|
|
11212
|
+
* validation_error、error_msg、log_content(日志文件末尾 4000 字节,含关键结果)。
|
|
11178
11213
|
*
|
|
11179
11214
|
* extraMetrics 记录各阶段耗时(毫秒);未执行的阶段上报 -1 作为哨兵值,
|
|
11180
11215
|
* 便于在 Slardar 查询时区分"未运行"和"运行了 0ms"。
|
|
11181
11216
|
*/
|
|
11182
11217
|
function reportUpgradeLarkToSlardar(opts) {
|
|
11183
|
-
console.error(`[slardar] upgrade_lark_run scene=${opts.scene ?? ""} success=${opts.success} exitCode=${opts.exitCode ?? ""} rollbackOk=${opts.rollbackOk ?? ""}`);
|
|
11218
|
+
console.error(`[slardar] upgrade_lark_run scene=${opts.scene ?? ""} checkOnly=${opts.checkOnly} success=${opts.success} exitCode=${opts.exitCode ?? ""} rollbackOk=${opts.rollbackOk ?? ""}`);
|
|
11184
11219
|
const t = opts.timing ?? {};
|
|
11185
|
-
const logContent =
|
|
11220
|
+
const logContent = readLogFileTail(opts.logFile);
|
|
11186
11221
|
reportTask({
|
|
11187
11222
|
eventName: "upgrade_lark_run",
|
|
11188
11223
|
durationMs: opts.durationMs,
|
|
11189
11224
|
status: opts.success ? "success" : "failed",
|
|
11190
11225
|
extraCategories: {
|
|
11191
11226
|
scene: opts.scene ?? "",
|
|
11227
|
+
check_only: String(opts.checkOnly),
|
|
11192
11228
|
exit_code: String(opts.exitCode ?? ""),
|
|
11193
11229
|
rollback_ok: opts.rollbackOk != null ? String(opts.rollbackOk) : "",
|
|
11194
11230
|
validation_error: opts.validationError ?? "",
|
|
@@ -11219,6 +11255,7 @@ function backupFiles(opts) {
|
|
|
11219
11255
|
node_fs.default.copyFileSync(configPath, node_path.default.join(backupDir, "openclaw.json"));
|
|
11220
11256
|
log(` backed up: openclaw.json (${stat.size} bytes)`);
|
|
11221
11257
|
} else log(` skipped: openclaw.json (not found)`);
|
|
11258
|
+
node_fs.default.mkdirSync(node_path.default.join(backupDir, "extensions"), { recursive: true });
|
|
11222
11259
|
const extSrc = node_path.default.join(workspaceDir, "extensions");
|
|
11223
11260
|
for (const pluginDir of FEISHU_PLUGIN_DIRS) {
|
|
11224
11261
|
const src = node_path.default.join(extSrc, pluginDir);
|
|
@@ -11240,23 +11277,32 @@ function backupFiles(opts) {
|
|
|
11240
11277
|
function restoreFiles(opts) {
|
|
11241
11278
|
const { workspaceDir, configPath, backupDir, log } = opts;
|
|
11242
11279
|
try {
|
|
11280
|
+
if (node_fs.default.existsSync(configPath)) {
|
|
11281
|
+
node_fs.default.rmSync(configPath, { force: true });
|
|
11282
|
+
log(` deleted: openclaw.json`);
|
|
11283
|
+
}
|
|
11284
|
+
const extDst = node_path.default.join(workspaceDir, "extensions");
|
|
11285
|
+
for (const pluginDir of FEISHU_PLUGIN_DIRS) {
|
|
11286
|
+
const dst = node_path.default.join(extDst, pluginDir);
|
|
11287
|
+
if (node_fs.default.existsSync(dst)) {
|
|
11288
|
+
node_fs.default.rmSync(dst, {
|
|
11289
|
+
recursive: true,
|
|
11290
|
+
force: true
|
|
11291
|
+
});
|
|
11292
|
+
log(` deleted: extensions/${pluginDir}`);
|
|
11293
|
+
}
|
|
11294
|
+
}
|
|
11243
11295
|
const configBackup = node_path.default.join(backupDir, "openclaw.json");
|
|
11244
11296
|
if (node_fs.default.existsSync(configBackup)) {
|
|
11245
11297
|
node_fs.default.copyFileSync(configBackup, configPath);
|
|
11246
11298
|
log(` restored: openclaw.json`);
|
|
11247
|
-
}
|
|
11248
|
-
const extDst = node_path.default.join(workspaceDir, "extensions");
|
|
11299
|
+
} else log(` skipped restore: openclaw.json (not in backup — was not present before upgrade)`);
|
|
11249
11300
|
for (const pluginDir of FEISHU_PLUGIN_DIRS) {
|
|
11250
11301
|
const backupSrc = node_path.default.join(backupDir, "extensions", pluginDir);
|
|
11251
11302
|
if (node_fs.default.existsSync(backupSrc)) {
|
|
11252
|
-
|
|
11253
|
-
if (node_fs.default.existsSync(dst)) node_fs.default.rmSync(dst, {
|
|
11254
|
-
recursive: true,
|
|
11255
|
-
force: true
|
|
11256
|
-
});
|
|
11257
|
-
node_fs.default.cpSync(backupSrc, dst, { recursive: true });
|
|
11303
|
+
node_fs.default.cpSync(backupSrc, node_path.default.join(extDst, pluginDir), { recursive: true });
|
|
11258
11304
|
log(` restored: extensions/${pluginDir}`);
|
|
11259
|
-
}
|
|
11305
|
+
} else log(` skipped restore: extensions/${pluginDir} (not in backup — was not present before upgrade)`);
|
|
11260
11306
|
}
|
|
11261
11307
|
return true;
|
|
11262
11308
|
} catch (e) {
|
|
@@ -11318,6 +11364,7 @@ function probeChannels(label, log, timeoutMs) {
|
|
|
11318
11364
|
if (r.error) log(` ${label} error: ${r.error}`);
|
|
11319
11365
|
if (r.gatewayReachable != null) log(` ${label} gatewayReachable: ${r.gatewayReachable}`);
|
|
11320
11366
|
for (const acct of r.accounts ?? []) log(` ${label} account ${acct.id}: isWorking=${acct.isWorking} bits=[${acct.bits.join(",")}]`);
|
|
11367
|
+
if (r.rawOutput) log(` ${label} raw output:\n${r.rawOutput}`);
|
|
11321
11368
|
return r;
|
|
11322
11369
|
} catch (e) {
|
|
11323
11370
|
log(` ${label} channels probe threw: ${e.message}`);
|
|
@@ -11333,7 +11380,7 @@ function probeChannels(label, log, timeoutMs) {
|
|
|
11333
11380
|
function runUpgradeLark(opts) {
|
|
11334
11381
|
const cwd = opts.cwd ?? "/home/gem/workspace/agent";
|
|
11335
11382
|
const configPath = opts.configPath ?? CONFIG_PATH;
|
|
11336
|
-
const logFile = upgradeLarkLogFile(opts.runId);
|
|
11383
|
+
const logFile = upgradeLarkLogFile(opts.runId, opts.checkOnly);
|
|
11337
11384
|
const log = makeLogger(logFile);
|
|
11338
11385
|
const fsOpts = {
|
|
11339
11386
|
workspaceDir: cwd,
|
|
@@ -11413,14 +11460,14 @@ function runUpgradeLark(opts) {
|
|
|
11413
11460
|
}
|
|
11414
11461
|
log(` PROCEED: requiresLarkUpgrade=true (version=${versionIncompatible}, feishuConfig=${feishuConfigInvalid}) AND channels not working → running upgrade`);
|
|
11415
11462
|
if (opts.checkOnly) {
|
|
11416
|
-
log(` check
|
|
11463
|
+
log(` --check 模式:需要升级 — 不执行安装,直接返回`);
|
|
11417
11464
|
log(`${"=".repeat(60)}`);
|
|
11418
|
-
log("upgrade-lark check
|
|
11465
|
+
log("upgrade-lark check complete");
|
|
11419
11466
|
log(`${"=".repeat(60)}`);
|
|
11420
11467
|
return {
|
|
11421
11468
|
ok: true,
|
|
11422
11469
|
skipped: true,
|
|
11423
|
-
skipReason: "check
|
|
11470
|
+
skipReason: "check",
|
|
11424
11471
|
upgradeNeeded: true,
|
|
11425
11472
|
timing,
|
|
11426
11473
|
logFile
|
|
@@ -11523,9 +11570,11 @@ function runUpgradeLark(opts) {
|
|
|
11523
11570
|
timing.postProbeMs = Date.now() - t_postProbeStart;
|
|
11524
11571
|
log(` feishu config invalid after: ${afterChannels.feishuConfigInvalid}`);
|
|
11525
11572
|
const stillNeedsUpgrade = (afterVersionIncompatible || afterChannels.feishuConfigInvalid) && !afterChannels.anyAccountWorking;
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11573
|
+
const isNewDefaultOnly = !beforeChannels.anyAccountWorking && isDefaultOnlyState(afterChannels);
|
|
11574
|
+
log(` post-check: stillNeedsUpgrade=${stillNeedsUpgrade} (version=${afterVersionIncompatible}, feishuConfig=${afterChannels.feishuConfigInvalid}, channelsWorking=${afterChannels.anyAccountWorking}) isNewDefaultOnly=${isNewDefaultOnly}`);
|
|
11575
|
+
if (stillNeedsUpgrade && !isNewDefaultOnly) return doRollback(`post-install diagnosis still shows anomaly: versionIncompatible=${afterVersionIncompatible}, feishuConfigInvalid=${afterChannels.feishuConfigInvalid}, anyAccountWorking=${afterChannels.anyAccountWorking}`);
|
|
11576
|
+
if (isNewDefaultOnly) log(" post-install diagnosis: ok (new default account — plugin installed, awaiting configuration)");
|
|
11577
|
+
else log(" post-install diagnosis: ok (upgrade conditions resolved)");
|
|
11529
11578
|
log("");
|
|
11530
11579
|
log("── [6/6] doctor --fix ────────────────────────────────────");
|
|
11531
11580
|
const fixArgs = ["doctor", "--fix"];
|
|
@@ -11547,6 +11596,26 @@ function runUpgradeLark(opts) {
|
|
|
11547
11596
|
if (fixResult.stderr?.trim()) log(`doctor(fix) stderr:\n${fixResult.stderr.trim()}`);
|
|
11548
11597
|
log(`doctor(fix) exit: ${fixResult.status ?? "null"}${fixResult.error ? ` error: ${fixResult.error.message}` : ""}`);
|
|
11549
11598
|
log("");
|
|
11599
|
+
log("── [7/7] 重启 openclaw 服务 ──────────────────────────────");
|
|
11600
|
+
const restartScript = "/opt/force/bin/openclaw_scripts/restart.sh";
|
|
11601
|
+
if (opts.skipRestart) log(" skipped: --skip-restart");
|
|
11602
|
+
else if (node_fs.default.existsSync(restartScript)) {
|
|
11603
|
+
const t_restart = Date.now();
|
|
11604
|
+
const restartResult = (0, node_child_process.spawnSync)("bash", [restartScript], {
|
|
11605
|
+
encoding: "utf-8",
|
|
11606
|
+
stdio: [
|
|
11607
|
+
"ignore",
|
|
11608
|
+
"pipe",
|
|
11609
|
+
"pipe"
|
|
11610
|
+
],
|
|
11611
|
+
timeout: 3e4
|
|
11612
|
+
});
|
|
11613
|
+
const restartMs = Date.now() - t_restart;
|
|
11614
|
+
if (restartResult.stdout?.trim()) log(` restart stdout:\n${restartResult.stdout.trim()}`);
|
|
11615
|
+
if (restartResult.stderr?.trim()) log(` restart stderr:\n${restartResult.stderr.trim()}`);
|
|
11616
|
+
log(` restart.sh exit: ${restartResult.status ?? "null"} (${restartMs}ms)${restartResult.error ? ` error: ${restartResult.error.message}` : ""}`);
|
|
11617
|
+
} else log(` skipped: ${restartScript} not found`);
|
|
11618
|
+
log("");
|
|
11550
11619
|
log(`${"=".repeat(60)}`);
|
|
11551
11620
|
log("upgrade-lark completed successfully");
|
|
11552
11621
|
log(`${"=".repeat(60)}`);
|
|
@@ -12050,16 +12119,19 @@ async function main() {
|
|
|
12050
12119
|
break;
|
|
12051
12120
|
}
|
|
12052
12121
|
case "upgrade-lark": {
|
|
12053
|
-
const checkOnly = args.includes("--check
|
|
12122
|
+
const checkOnly = args.includes("--check");
|
|
12123
|
+
const skipRestart = args.includes("--skip-restart");
|
|
12054
12124
|
const result = runUpgradeLark({
|
|
12055
12125
|
runId: rc.runId,
|
|
12056
12126
|
scene,
|
|
12057
|
-
checkOnly
|
|
12127
|
+
checkOnly,
|
|
12128
|
+
skipRestart
|
|
12058
12129
|
});
|
|
12059
12130
|
const upgradeDurationMs = Date.now() - t0;
|
|
12060
12131
|
console.log(JSON.stringify(result));
|
|
12061
12132
|
reportUpgradeLarkToSlardar({
|
|
12062
12133
|
scene,
|
|
12134
|
+
checkOnly,
|
|
12063
12135
|
durationMs: upgradeDurationMs,
|
|
12064
12136
|
success: result.ok,
|
|
12065
12137
|
logFile: result.logFile,
|
package/package.json
CHANGED