@lark-apaas/openclaw-scripts-diagnose-cli 0.1.18-alpha.0 → 0.1.18-alpha.1

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.
Files changed (2) hide show
  1. package/dist/index.cjs +154 -156
  2. 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.18-alpha.0";
55
+ return "0.1.18-alpha.1";
56
56
  }
57
57
  //#endregion
58
58
  //#region src/rule-engine/base.ts
@@ -5206,6 +5206,139 @@ async function installOpenclaw(openclawTag, ossFileMap, opts = {}) {
5206
5206
  }
5207
5207
  console.error(`[install-openclaw] done in ${Date.now() - t0}ms`);
5208
5208
  }
5209
+ //#endregion
5210
+ //#region src/lark-tools-update.ts
5211
+ /**
5212
+ * 共享的飞书插件备份 / 恢复 / `openclaw-lark-tools update` 调用。
5213
+ *
5214
+ * upgrade-lark(场景修复流)与 install-extension(升级触发的兼容性预判路径)都需要
5215
+ * 「备份 → npx 适配升级 → 失败回滚」的同一套处理,此处统一封装,避免两份实现漂移。
5216
+ *
5217
+ * 日志通过可选 `log` 注入:upgrade-lark 传写日志文件的 Logger,install-extension 传
5218
+ * `console.error`,独立调用方不传则静默。
5219
+ */
5220
+ const NOOP_LOG = () => {};
5221
+ /** 升级前需备份的 extensions/ 下的插件目录(含 legacy) */
5222
+ const FEISHU_PLUGIN_DIRS = ["openclaw-lark", "feishu-openclaw-plugin"];
5223
+ /** 读取 package.json 的 version 字段,失败返回 null(仅用于日志) */
5224
+ function readPkgVersion(pkgPath) {
5225
+ try {
5226
+ const pkg = JSON.parse(node_fs.default.readFileSync(pkgPath, "utf-8"));
5227
+ return typeof pkg.version === "string" ? pkg.version : null;
5228
+ } catch {
5229
+ return null;
5230
+ }
5231
+ }
5232
+ /**
5233
+ * 备份 openclaw.json + FEISHU_PLUGIN_DIRS 下存在的插件目录到 backupDir。
5234
+ * 只备份当前存在的文件;不存在的记日志后跳过(恢复时据此判断「升级前是否存在」)。
5235
+ */
5236
+ function backupFeishuPlugins(opts) {
5237
+ const { workspaceDir, configPath, backupDir } = opts;
5238
+ const log = opts.log ?? NOOP_LOG;
5239
+ try {
5240
+ node_fs.default.mkdirSync(backupDir, { recursive: true });
5241
+ log(`backup dir: ${backupDir}`);
5242
+ if (node_fs.default.existsSync(configPath)) {
5243
+ const stat = node_fs.default.statSync(configPath);
5244
+ node_fs.default.copyFileSync(configPath, node_path.default.join(backupDir, "openclaw.json"));
5245
+ log(` backed up: openclaw.json (${stat.size} bytes)`);
5246
+ } else log(` skipped: openclaw.json (not found)`);
5247
+ node_fs.default.mkdirSync(node_path.default.join(backupDir, "extensions"), { recursive: true });
5248
+ const extSrc = node_path.default.join(workspaceDir, "extensions");
5249
+ for (const pluginDir of FEISHU_PLUGIN_DIRS) {
5250
+ const src = node_path.default.join(extSrc, pluginDir);
5251
+ if (node_fs.default.existsSync(src)) {
5252
+ const dst = node_path.default.join(backupDir, "extensions", pluginDir);
5253
+ node_fs.default.cpSync(src, dst, { recursive: true });
5254
+ const version = readPkgVersion(node_path.default.join(src, "package.json"));
5255
+ log(` backed up: extensions/${pluginDir}${version ? ` (version: ${version})` : ""}`);
5256
+ } else log(` skipped: extensions/${pluginDir} (not found)`);
5257
+ }
5258
+ return { ok: true };
5259
+ } catch (e) {
5260
+ const msg = `backup failed: ${e.message}`;
5261
+ log(`ERROR: ${msg}`);
5262
+ return {
5263
+ ok: false,
5264
+ error: msg
5265
+ };
5266
+ }
5267
+ }
5268
+ /**
5269
+ * 回滚到备份快照:先删除当前 openclaw.json + 插件目录,再从备份恢复(仅恢复备份中存在的,
5270
+ * 即升级前确实存在的文件)。这样升级过程中新建的文件会被清理,真正回到 pre-state。
5271
+ */
5272
+ function restoreFeishuPlugins(opts) {
5273
+ const { workspaceDir, configPath, backupDir } = opts;
5274
+ const log = opts.log ?? NOOP_LOG;
5275
+ try {
5276
+ if (node_fs.default.existsSync(configPath)) {
5277
+ node_fs.default.rmSync(configPath, { force: true });
5278
+ log(` deleted: openclaw.json`);
5279
+ }
5280
+ const extDst = node_path.default.join(workspaceDir, "extensions");
5281
+ for (const pluginDir of FEISHU_PLUGIN_DIRS) {
5282
+ const dst = node_path.default.join(extDst, pluginDir);
5283
+ if (node_fs.default.existsSync(dst)) {
5284
+ node_fs.default.rmSync(dst, {
5285
+ recursive: true,
5286
+ force: true
5287
+ });
5288
+ log(` deleted: extensions/${pluginDir}`);
5289
+ }
5290
+ }
5291
+ const configBackup = node_path.default.join(backupDir, "openclaw.json");
5292
+ if (node_fs.default.existsSync(configBackup)) {
5293
+ node_fs.default.copyFileSync(configBackup, configPath);
5294
+ log(` restored: openclaw.json`);
5295
+ } else log(` skipped restore: openclaw.json (not in backup — was not present before upgrade)`);
5296
+ for (const pluginDir of FEISHU_PLUGIN_DIRS) {
5297
+ const backupSrc = node_path.default.join(backupDir, "extensions", pluginDir);
5298
+ if (node_fs.default.existsSync(backupSrc)) {
5299
+ node_fs.default.cpSync(backupSrc, node_path.default.join(extDst, pluginDir), { recursive: true });
5300
+ log(` restored: extensions/${pluginDir}`);
5301
+ } else log(` skipped restore: extensions/${pluginDir} (not in backup — was not present before upgrade)`);
5302
+ }
5303
+ return true;
5304
+ } catch (e) {
5305
+ log(` restore error: ${e.message}`);
5306
+ return false;
5307
+ }
5308
+ }
5309
+ /**
5310
+ * 执行 `npx -y @larksuite/openclaw-lark-tools update`,自动按当前 openclaw 内核选择
5311
+ * 适配的 openclaw-lark 版本。stdout/stderr 已 trim;exitCode 缺失时归一为 1。
5312
+ */
5313
+ function runLarkToolsUpdate(opts) {
5314
+ const log = opts.log ?? NOOP_LOG;
5315
+ const r = (0, node_child_process.spawnSync)("npx", [
5316
+ "-y",
5317
+ "@larksuite/openclaw-lark-tools",
5318
+ "update"
5319
+ ], {
5320
+ cwd: opts.cwd,
5321
+ encoding: "utf-8",
5322
+ stdio: [
5323
+ "ignore",
5324
+ "pipe",
5325
+ "pipe"
5326
+ ],
5327
+ timeout: opts.timeoutMs ?? 6e5
5328
+ });
5329
+ const stdout = r.stdout?.trim() ?? "";
5330
+ const stderr = r.stderr?.trim() ?? "";
5331
+ const exitCode = r.status ?? 1;
5332
+ if (stdout) log(`npx stdout:\n${stdout}`);
5333
+ if (stderr) log(`npx stderr:\n${stderr}`);
5334
+ log(`npx exit: ${exitCode}${r.error ? ` error: ${r.error.message}` : ""}`);
5335
+ return {
5336
+ exitCode,
5337
+ stdout,
5338
+ stderr,
5339
+ spawnError: r.error?.message
5340
+ };
5341
+ }
5209
5342
  async function installExtension(tag, ossFileMap, opts = {}) {
5210
5343
  const homeBase = resolveHomeBase(opts.homeBase);
5211
5344
  const hasAll = !!opts.all;
@@ -5374,40 +5507,29 @@ async function installLarkPluginWithCompatCheck(opts) {
5374
5507
  console.error(`[install-extension] openclaw-lark@${pkg.version ?? "unknown"} compat with openclaw@${ocCur}: ${compatible}`);
5375
5508
  if (compatible) return false;
5376
5509
  console.error(`[install-extension] openclaw-lark@${pkg.version} incompatible with openclaw@${ocCur} — using openclaw-lark-tools update`);
5510
+ const log = (msg) => console.error(`[install-extension] ${msg}`);
5377
5511
  const backupDir = node_path.default.join(homeBase, `.openclaw-lark-backup-${tag}`);
5378
- const backupOk = backupLarkPlugin({
5512
+ const backupOk = backupFeishuPlugins({
5379
5513
  workspaceDir,
5380
5514
  configPath,
5381
- backupDir
5382
- });
5515
+ backupDir,
5516
+ log
5517
+ }).ok;
5383
5518
  if (!backupOk) console.error("[install-extension] WARN: backup failed — proceeding without backup for openclaw-lark-tools path");
5384
5519
  try {
5385
- const npxResult = (0, node_child_process.spawnSync)("npx", [
5386
- "-y",
5387
- "@larksuite/openclaw-lark-tools",
5388
- "update"
5389
- ], {
5520
+ const { exitCode } = runLarkToolsUpdate({
5390
5521
  cwd: workspaceDir,
5391
- encoding: "utf-8",
5392
- stdio: [
5393
- "ignore",
5394
- "pipe",
5395
- "pipe"
5396
- ],
5397
- timeout: 6e5
5522
+ log
5398
5523
  });
5399
- const npxExit = npxResult.status ?? 1;
5400
- if (npxResult.stdout?.trim()) console.error(`[install-extension] openclaw-lark-tools stdout:\n${npxResult.stdout.trim()}`);
5401
- if (npxResult.stderr?.trim()) console.error(`[install-extension] openclaw-lark-tools stderr:\n${npxResult.stderr.trim()}`);
5402
- console.error(`[install-extension] openclaw-lark-tools exit: ${npxExit}`);
5403
- if (npxExit !== 0) {
5524
+ if (exitCode !== 0) {
5404
5525
  console.error("[install-extension] openclaw-lark-tools failed — attempting rollback");
5405
- if (backupOk) restoreLarkPlugin({
5526
+ if (backupOk) restoreFeishuPlugins({
5406
5527
  workspaceDir,
5407
5528
  configPath,
5408
- backupDir
5529
+ backupDir,
5530
+ log
5409
5531
  });
5410
- throw new Error(`openclaw-lark-tools update exited with code ${npxExit}`);
5532
+ throw new Error(`openclaw-lark-tools update exited with code ${exitCode}`);
5411
5533
  }
5412
5534
  const validation = validateLarkPluginInstall({
5413
5535
  homeBase,
@@ -5415,10 +5537,11 @@ async function installLarkPluginWithCompatCheck(opts) {
5415
5537
  });
5416
5538
  if (!validation.ok) {
5417
5539
  console.error(`[install-extension] post-install validation failed: ${validation.error} — rolling back`);
5418
- if (backupOk) restoreLarkPlugin({
5540
+ if (backupOk) restoreFeishuPlugins({
5419
5541
  workspaceDir,
5420
5542
  configPath,
5421
- backupDir
5543
+ backupDir,
5544
+ log
5422
5545
  });
5423
5546
  throw new Error(`openclaw-lark post-install validation failed: ${validation.error}`);
5424
5547
  }
@@ -5433,38 +5556,6 @@ async function installLarkPluginWithCompatCheck(opts) {
5433
5556
  } catch {}
5434
5557
  }
5435
5558
  }
5436
- function backupLarkPlugin(opts) {
5437
- const { workspaceDir, configPath, backupDir } = opts;
5438
- try {
5439
- node_fs.default.mkdirSync(backupDir, { recursive: true });
5440
- if (node_fs.default.existsSync(configPath)) node_fs.default.copyFileSync(configPath, node_path.default.join(backupDir, "openclaw.json"));
5441
- const pluginSrc = node_path.default.join(workspaceDir, "extensions", LARK_PLUGIN_NAME$1);
5442
- if (node_fs.default.existsSync(pluginSrc)) node_fs.default.cpSync(pluginSrc, node_path.default.join(backupDir, LARK_PLUGIN_NAME$1), { recursive: true });
5443
- return true;
5444
- } catch (e) {
5445
- console.error(`[install-extension] backup error: ${e.message}`);
5446
- return false;
5447
- }
5448
- }
5449
- function restoreLarkPlugin(opts) {
5450
- const { workspaceDir, configPath, backupDir } = opts;
5451
- try {
5452
- const configBak = node_path.default.join(backupDir, "openclaw.json");
5453
- if (node_fs.default.existsSync(configBak)) node_fs.default.copyFileSync(configBak, configPath);
5454
- const pluginBak = node_path.default.join(backupDir, LARK_PLUGIN_NAME$1);
5455
- const pluginDst = node_path.default.join(workspaceDir, "extensions", LARK_PLUGIN_NAME$1);
5456
- if (node_fs.default.existsSync(pluginBak)) {
5457
- if (node_fs.default.existsSync(pluginDst)) node_fs.default.rmSync(pluginDst, {
5458
- recursive: true,
5459
- force: true
5460
- });
5461
- node_fs.default.cpSync(pluginBak, pluginDst, { recursive: true });
5462
- }
5463
- console.error("[install-extension] rollback complete");
5464
- } catch (e) {
5465
- console.error(`[install-extension] rollback error: ${e.message}`);
5466
- }
5467
- }
5468
5559
  /**
5469
5560
  * Post-install validation for the tools-based upgrade path.
5470
5561
  * Checks: plugin directory exists + plugin is enabled in openclaw.json.
@@ -11011,7 +11102,7 @@ async function reportCliRun(opts) {
11011
11102
  //#region src/help.ts
11012
11103
  const BIN = "mclaw-diagnose";
11013
11104
  function versionBanner() {
11014
- return `v0.1.18-alpha.0`;
11105
+ return `v0.1.18-alpha.1`;
11015
11106
  }
11016
11107
  const COMMANDS = [
11017
11108
  {
@@ -11697,83 +11788,6 @@ function buildUpgradeLarkResultSummary(result, checkOnly) {
11697
11788
  }
11698
11789
  //#endregion
11699
11790
  //#region src/upgrade-lark.ts
11700
- /** 升级前需备份的 extensions/ 下的插件目录 */
11701
- const FEISHU_PLUGIN_DIRS = ["openclaw-lark", "feishu-openclaw-plugin"];
11702
- function backupFiles(opts) {
11703
- const { workspaceDir, configPath, backupDir, log } = opts;
11704
- try {
11705
- node_fs.default.mkdirSync(backupDir, { recursive: true });
11706
- log(`backup dir: ${backupDir}`);
11707
- if (node_fs.default.existsSync(configPath)) {
11708
- const stat = node_fs.default.statSync(configPath);
11709
- node_fs.default.copyFileSync(configPath, node_path.default.join(backupDir, "openclaw.json"));
11710
- log(` backed up: openclaw.json (${stat.size} bytes)`);
11711
- } else log(` skipped: openclaw.json (not found)`);
11712
- node_fs.default.mkdirSync(node_path.default.join(backupDir, "extensions"), { recursive: true });
11713
- const extSrc = node_path.default.join(workspaceDir, "extensions");
11714
- for (const pluginDir of FEISHU_PLUGIN_DIRS) {
11715
- const src = node_path.default.join(extSrc, pluginDir);
11716
- if (node_fs.default.existsSync(src)) {
11717
- const dst = node_path.default.join(backupDir, "extensions", pluginDir);
11718
- node_fs.default.cpSync(src, dst, { recursive: true });
11719
- const version = readPkgVersion(node_path.default.join(src, "package.json"));
11720
- log(` backed up: extensions/${pluginDir}${version ? ` (version: ${version})` : ""}`);
11721
- } else log(` skipped: extensions/${pluginDir} (not found)`);
11722
- }
11723
- return { ok: true };
11724
- } catch (e) {
11725
- const msg = `backup failed: ${e.message}`;
11726
- log(`ERROR: ${msg}`);
11727
- return {
11728
- ok: false,
11729
- error: msg
11730
- };
11731
- }
11732
- }
11733
- function restoreFiles(opts) {
11734
- const { workspaceDir, configPath, backupDir, log } = opts;
11735
- try {
11736
- if (node_fs.default.existsSync(configPath)) {
11737
- node_fs.default.rmSync(configPath, { force: true });
11738
- log(` deleted: openclaw.json`);
11739
- }
11740
- const extDst = node_path.default.join(workspaceDir, "extensions");
11741
- for (const pluginDir of FEISHU_PLUGIN_DIRS) {
11742
- const dst = node_path.default.join(extDst, pluginDir);
11743
- if (node_fs.default.existsSync(dst)) {
11744
- node_fs.default.rmSync(dst, {
11745
- recursive: true,
11746
- force: true
11747
- });
11748
- log(` deleted: extensions/${pluginDir}`);
11749
- }
11750
- }
11751
- const configBackup = node_path.default.join(backupDir, "openclaw.json");
11752
- if (node_fs.default.existsSync(configBackup)) {
11753
- node_fs.default.copyFileSync(configBackup, configPath);
11754
- log(` restored: openclaw.json`);
11755
- } else log(` skipped restore: openclaw.json (not in backup — was not present before upgrade)`);
11756
- for (const pluginDir of FEISHU_PLUGIN_DIRS) {
11757
- const backupSrc = node_path.default.join(backupDir, "extensions", pluginDir);
11758
- if (node_fs.default.existsSync(backupSrc)) {
11759
- node_fs.default.cpSync(backupSrc, node_path.default.join(extDst, pluginDir), { recursive: true });
11760
- log(` restored: extensions/${pluginDir}`);
11761
- } else log(` skipped restore: extensions/${pluginDir} (not in backup — was not present before upgrade)`);
11762
- }
11763
- return true;
11764
- } catch (e) {
11765
- log(` restore error: ${e.message}`);
11766
- return false;
11767
- }
11768
- }
11769
- function readPkgVersion(pkgPath) {
11770
- try {
11771
- const pkg = JSON.parse(node_fs.default.readFileSync(pkgPath, "utf-8"));
11772
- return typeof pkg.version === "string" ? pkg.version : null;
11773
- } catch {
11774
- return null;
11775
- }
11776
- }
11777
11791
  function snapshotVersions(cwd, log) {
11778
11792
  const ocResult = (0, node_child_process.spawnSync)("openclaw", ["--version"], {
11779
11793
  cwd,
@@ -12029,7 +12043,7 @@ function runUpgradeLark(opts) {
12029
12043
  log("── [1/6] 文件备份 ────────────────────────────────────────");
12030
12044
  log(`before-state: botCount=${countFeishuBots(configPath)}`);
12031
12045
  const t_backupStart = Date.now();
12032
- const backup = backupFiles(fsOpts);
12046
+ const backup = backupFeishuPlugins(fsOpts);
12033
12047
  timing.backupMs = Date.now() - t_backupStart;
12034
12048
  if (!backup.ok) {
12035
12049
  log(`ERROR: ${backup.error}`);
@@ -12056,27 +12070,11 @@ function runUpgradeLark(opts) {
12056
12070
  log("");
12057
12071
  log("── [3/6] npx install (@larksuite/openclaw-lark-tools update) ──");
12058
12072
  const t_npxStart = Date.now();
12059
- const npxResult = (0, node_child_process.spawnSync)("npx", [
12060
- "-y",
12061
- "@larksuite/openclaw-lark-tools",
12062
- "update"
12063
- ], {
12073
+ const { exitCode: npxExitCode, stdout: npxStdout, stderr: npxStderr } = runLarkToolsUpdate({
12064
12074
  cwd,
12065
- encoding: "utf-8",
12066
- stdio: [
12067
- "ignore",
12068
- "pipe",
12069
- "pipe"
12070
- ],
12071
- timeout: 6e5
12075
+ log
12072
12076
  });
12073
12077
  timing.npxInstallMs = Date.now() - t_npxStart;
12074
- const npxStdout = npxResult.stdout?.trim() ?? "";
12075
- const npxStderr = npxResult.stderr?.trim() ?? "";
12076
- const npxExitCode = npxResult.status ?? 1;
12077
- if (npxStdout) log(`npx stdout:\n${npxStdout}`);
12078
- if (npxStderr) log(`npx stderr:\n${npxStderr}`);
12079
- log(`npx exit: ${npxExitCode}${npxResult.error ? ` error: ${npxResult.error.message}` : ""}`);
12080
12078
  if (statusCheckDelayMs > 0) {
12081
12079
  log("");
12082
12080
  log(`── 等待 ${statusCheckDelayMs / 1e3}s(让 openclaw 服务完成重启) ─────────────`);
@@ -12085,7 +12083,7 @@ function runUpgradeLark(opts) {
12085
12083
  }
12086
12084
  const doRollback = (reason) => {
12087
12085
  log(`ERROR: ${reason}`);
12088
- const rollbackOk = restoreFiles(fsOpts);
12086
+ const rollbackOk = restoreFeishuPlugins(fsOpts);
12089
12087
  log(`rollback: ${rollbackOk ? "ok" : "FAILED"}`);
12090
12088
  return finalReturn({
12091
12089
  status: "failed",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/openclaw-scripts-diagnose-cli",
3
- "version": "0.1.18-alpha.0",
3
+ "version": "0.1.18-alpha.1",
4
4
  "description": "CLI for OpenClaw config diagnose and repair with JSON5 support",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {