@lark-apaas/openclaw-scripts-diagnose-cli 0.1.15-alpha.2 → 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 +89 -27
- 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] [--scene=<scene>] [--caller=<n>] [--trace-id=<id>]
|
|
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:
|
|
@@ -10908,8 +10933,9 @@ DESCRIPTION
|
|
|
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.
|
|
@@ -11162,18 +11188,19 @@ function reportDoctorRunToSlardar(opts) {
|
|
|
11162
11188
|
}
|
|
11163
11189
|
});
|
|
11164
11190
|
}
|
|
11191
|
+
const LOG_PREFIX_RE = /^\[\d{4}-\d{2}-\d{2}T[\d:.]+Z\](?:\s+\[run=[^\]]+\])?\s*/;
|
|
11165
11192
|
/**
|
|
11166
|
-
* 读取日志文件末尾最多 maxBytes
|
|
11167
|
-
*
|
|
11168
|
-
*
|
|
11193
|
+
* 读取日志文件末尾最多 maxBytes 字节,过滤噪音后返回纯内容。
|
|
11194
|
+
* - 剥除每行的时间戳 + run tag 前缀
|
|
11195
|
+
* - 过滤纯分隔符行(全为 '=')
|
|
11196
|
+
* 日志头部为固定 banner,有价值的内容集中在末尾,从尾部截取。
|
|
11169
11197
|
*/
|
|
11170
11198
|
function readLogFileTail(filePath, maxBytes = 4e3) {
|
|
11171
11199
|
try {
|
|
11172
11200
|
const buf = node_fs.default.readFileSync(filePath);
|
|
11173
|
-
|
|
11174
|
-
let start = buf.length - maxBytes;
|
|
11201
|
+
let start = buf.length > maxBytes ? buf.length - maxBytes : 0;
|
|
11175
11202
|
while (start < buf.length && buf[start] !== 10) start++;
|
|
11176
|
-
return buf.subarray(start + 1).toString("utf-8");
|
|
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();
|
|
11177
11204
|
} catch {
|
|
11178
11205
|
return "";
|
|
11179
11206
|
}
|
|
@@ -11228,6 +11255,7 @@ function backupFiles(opts) {
|
|
|
11228
11255
|
node_fs.default.copyFileSync(configPath, node_path.default.join(backupDir, "openclaw.json"));
|
|
11229
11256
|
log(` backed up: openclaw.json (${stat.size} bytes)`);
|
|
11230
11257
|
} else log(` skipped: openclaw.json (not found)`);
|
|
11258
|
+
node_fs.default.mkdirSync(node_path.default.join(backupDir, "extensions"), { recursive: true });
|
|
11231
11259
|
const extSrc = node_path.default.join(workspaceDir, "extensions");
|
|
11232
11260
|
for (const pluginDir of FEISHU_PLUGIN_DIRS) {
|
|
11233
11261
|
const src = node_path.default.join(extSrc, pluginDir);
|
|
@@ -11249,23 +11277,32 @@ function backupFiles(opts) {
|
|
|
11249
11277
|
function restoreFiles(opts) {
|
|
11250
11278
|
const { workspaceDir, configPath, backupDir, log } = opts;
|
|
11251
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
|
+
}
|
|
11252
11295
|
const configBackup = node_path.default.join(backupDir, "openclaw.json");
|
|
11253
11296
|
if (node_fs.default.existsSync(configBackup)) {
|
|
11254
11297
|
node_fs.default.copyFileSync(configBackup, configPath);
|
|
11255
11298
|
log(` restored: openclaw.json`);
|
|
11256
|
-
}
|
|
11257
|
-
const extDst = node_path.default.join(workspaceDir, "extensions");
|
|
11299
|
+
} else log(` skipped restore: openclaw.json (not in backup — was not present before upgrade)`);
|
|
11258
11300
|
for (const pluginDir of FEISHU_PLUGIN_DIRS) {
|
|
11259
11301
|
const backupSrc = node_path.default.join(backupDir, "extensions", pluginDir);
|
|
11260
11302
|
if (node_fs.default.existsSync(backupSrc)) {
|
|
11261
|
-
|
|
11262
|
-
if (node_fs.default.existsSync(dst)) node_fs.default.rmSync(dst, {
|
|
11263
|
-
recursive: true,
|
|
11264
|
-
force: true
|
|
11265
|
-
});
|
|
11266
|
-
node_fs.default.cpSync(backupSrc, dst, { recursive: true });
|
|
11303
|
+
node_fs.default.cpSync(backupSrc, node_path.default.join(extDst, pluginDir), { recursive: true });
|
|
11267
11304
|
log(` restored: extensions/${pluginDir}`);
|
|
11268
|
-
}
|
|
11305
|
+
} else log(` skipped restore: extensions/${pluginDir} (not in backup — was not present before upgrade)`);
|
|
11269
11306
|
}
|
|
11270
11307
|
return true;
|
|
11271
11308
|
} catch (e) {
|
|
@@ -11327,6 +11364,7 @@ function probeChannels(label, log, timeoutMs) {
|
|
|
11327
11364
|
if (r.error) log(` ${label} error: ${r.error}`);
|
|
11328
11365
|
if (r.gatewayReachable != null) log(` ${label} gatewayReachable: ${r.gatewayReachable}`);
|
|
11329
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}`);
|
|
11330
11368
|
return r;
|
|
11331
11369
|
} catch (e) {
|
|
11332
11370
|
log(` ${label} channels probe threw: ${e.message}`);
|
|
@@ -11342,7 +11380,7 @@ function probeChannels(label, log, timeoutMs) {
|
|
|
11342
11380
|
function runUpgradeLark(opts) {
|
|
11343
11381
|
const cwd = opts.cwd ?? "/home/gem/workspace/agent";
|
|
11344
11382
|
const configPath = opts.configPath ?? CONFIG_PATH;
|
|
11345
|
-
const logFile = upgradeLarkLogFile(opts.runId);
|
|
11383
|
+
const logFile = upgradeLarkLogFile(opts.runId, opts.checkOnly);
|
|
11346
11384
|
const log = makeLogger(logFile);
|
|
11347
11385
|
const fsOpts = {
|
|
11348
11386
|
workspaceDir: cwd,
|
|
@@ -11532,9 +11570,11 @@ function runUpgradeLark(opts) {
|
|
|
11532
11570
|
timing.postProbeMs = Date.now() - t_postProbeStart;
|
|
11533
11571
|
log(` feishu config invalid after: ${afterChannels.feishuConfigInvalid}`);
|
|
11534
11572
|
const stillNeedsUpgrade = (afterVersionIncompatible || afterChannels.feishuConfigInvalid) && !afterChannels.anyAccountWorking;
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
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)");
|
|
11538
11578
|
log("");
|
|
11539
11579
|
log("── [6/6] doctor --fix ────────────────────────────────────");
|
|
11540
11580
|
const fixArgs = ["doctor", "--fix"];
|
|
@@ -11556,6 +11596,26 @@ function runUpgradeLark(opts) {
|
|
|
11556
11596
|
if (fixResult.stderr?.trim()) log(`doctor(fix) stderr:\n${fixResult.stderr.trim()}`);
|
|
11557
11597
|
log(`doctor(fix) exit: ${fixResult.status ?? "null"}${fixResult.error ? ` error: ${fixResult.error.message}` : ""}`);
|
|
11558
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("");
|
|
11559
11619
|
log(`${"=".repeat(60)}`);
|
|
11560
11620
|
log("upgrade-lark completed successfully");
|
|
11561
11621
|
log(`${"=".repeat(60)}`);
|
|
@@ -12060,10 +12120,12 @@ async function main() {
|
|
|
12060
12120
|
}
|
|
12061
12121
|
case "upgrade-lark": {
|
|
12062
12122
|
const checkOnly = args.includes("--check");
|
|
12123
|
+
const skipRestart = args.includes("--skip-restart");
|
|
12063
12124
|
const result = runUpgradeLark({
|
|
12064
12125
|
runId: rc.runId,
|
|
12065
12126
|
scene,
|
|
12066
|
-
checkOnly
|
|
12127
|
+
checkOnly,
|
|
12128
|
+
skipRestart
|
|
12067
12129
|
});
|
|
12068
12130
|
const upgradeDurationMs = Date.now() - t0;
|
|
12069
12131
|
console.log(JSON.stringify(result));
|
package/package.json
CHANGED