@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.28 → 0.1.1-alpha.29

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 +293 -40
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -32,6 +32,8 @@ node_path = __toESM(node_path);
32
32
  let node_child_process = require("node:child_process");
33
33
  let node_crypto = require("node:crypto");
34
34
  node_crypto = __toESM(node_crypto);
35
+ let node_os = require("node:os");
36
+ node_os = __toESM(node_os);
35
37
  let node_stream = require("node:stream");
36
38
  let node_stream_promises = require("node:stream/promises");
37
39
  let node_assert = require("node:assert");
@@ -684,18 +686,10 @@ FeishuChannelRule = _FeishuChannelRule = __decorate([Rule({
684
686
  //#endregion
685
687
  //#region src/rules/feishu-default-account.ts
686
688
  let FeishuDefaultAccountRule = class FeishuDefaultAccountRule extends DiagnoseRule {
687
- validate(ctx) {
688
- const feishu = getNestedMap(ctx.config, "channels", "feishu");
689
- if (feishu && "defaultAccount" in feishu) return {
690
- pass: false,
691
- message: "channels.feishu.defaultAccount should be removed"
692
- };
689
+ validate(_ctx) {
693
690
  return { pass: true };
694
691
  }
695
- repair(ctx) {
696
- const feishu = getNestedMap(ctx.config, "channels", "feishu");
697
- if (feishu && "defaultAccount" in feishu) delete feishu.defaultAccount;
698
- }
692
+ repair(_ctx) {}
699
693
  };
700
694
  FeishuDefaultAccountRule = __decorate([Rule({
701
695
  key: "feishu_default_account",
@@ -1582,10 +1576,10 @@ async function installOpenclaw(openclawTag, ossFileMap, opts = {}) {
1582
1576
  if (!pkg) throw new Error("install-openclaw: role=cli,name=openclaw not found in manifest");
1583
1577
  const targetDir = opts.targetDir ?? node_path.default.join(homeBase, pkg.installPath);
1584
1578
  const bakDir = targetDir + ".bak";
1585
- const stagingDir = targetDir + ".new";
1579
+ const newDir = targetDir + ".new";
1586
1580
  const tarball = await downloadWithCache(pkg, ossFileMap, opts);
1587
1581
  console.error(`[install-openclaw] tag=${openclawTag} shasum=${pkg.shasum.slice(0, 12)}...`);
1588
- if (node_fs.default.existsSync(stagingDir)) node_fs.default.rmSync(stagingDir, {
1582
+ if (node_fs.default.existsSync(newDir)) node_fs.default.rmSync(newDir, {
1589
1583
  recursive: true,
1590
1584
  force: true
1591
1585
  });
@@ -1594,39 +1588,39 @@ async function installOpenclaw(openclawTag, ossFileMap, opts = {}) {
1594
1588
  force: true
1595
1589
  });
1596
1590
  node_fs.default.mkdirSync(node_path.default.dirname(targetDir), { recursive: true });
1597
- node_fs.default.mkdirSync(stagingDir);
1598
- try {
1599
- execCaptureErr(`tar -xzf '${tarball}' -C '${stagingDir}' --strip-components=1`);
1600
- if (!node_fs.default.existsSync(node_path.default.join(stagingDir, "package.json"))) throw new Error("extracted tarball missing package.json");
1601
- } catch (e) {
1602
- try {
1603
- node_fs.default.rmSync(stagingDir, {
1604
- recursive: true,
1605
- force: true
1606
- });
1607
- } catch {}
1608
- throw e;
1609
- }
1610
- const hadExisting = node_fs.default.existsSync(targetDir);
1591
+ const tmpStage = node_fs.default.mkdtempSync(node_path.default.join(opts.tmpRoot ?? node_os.default.tmpdir(), "openclaw-install-"));
1611
1592
  try {
1612
- if (hadExisting) moveSafe(targetDir, bakDir);
1613
- moveSafe(stagingDir, targetDir);
1614
- } catch (e) {
1615
- if (hadExisting && !node_fs.default.existsSync(targetDir) && node_fs.default.existsSync(bakDir)) try {
1616
- moveSafe(bakDir, targetDir);
1617
- } catch {}
1593
+ execCaptureErr(`tar -xzf '${tarball}' -C '${tmpStage}' --strip-components=1`);
1594
+ if (!node_fs.default.existsSync(node_path.default.join(tmpStage, "package.json"))) throw new Error("extracted tarball missing package.json");
1595
+ moveSafe(tmpStage, newDir);
1596
+ const hadExisting = node_fs.default.existsSync(targetDir);
1618
1597
  try {
1619
- node_fs.default.rmSync(stagingDir, {
1598
+ if (hadExisting) moveSafe(targetDir, bakDir);
1599
+ moveSafe(newDir, targetDir);
1600
+ } catch (e) {
1601
+ if (hadExisting && !node_fs.default.existsSync(targetDir) && node_fs.default.existsSync(bakDir)) try {
1602
+ moveSafe(bakDir, targetDir);
1603
+ } catch {}
1604
+ try {
1605
+ node_fs.default.rmSync(newDir, {
1606
+ recursive: true,
1607
+ force: true
1608
+ });
1609
+ } catch {}
1610
+ throw e;
1611
+ }
1612
+ if (hadExisting && node_fs.default.existsSync(bakDir)) node_fs.default.rmSync(bakDir, {
1613
+ recursive: true,
1614
+ force: true
1615
+ });
1616
+ } finally {
1617
+ if (node_fs.default.existsSync(tmpStage)) try {
1618
+ node_fs.default.rmSync(tmpStage, {
1620
1619
  recursive: true,
1621
1620
  force: true
1622
1621
  });
1623
1622
  } catch {}
1624
- throw e;
1625
1623
  }
1626
- if (hadExisting && node_fs.default.existsSync(bakDir)) node_fs.default.rmSync(bakDir, {
1627
- recursive: true,
1628
- force: true
1629
- });
1630
1624
  console.error(`[install-openclaw] done in ${Date.now() - t0}ms`);
1631
1625
  }
1632
1626
  async function installExtension(tag, ossFileMap, opts = {}) {
@@ -2523,9 +2517,248 @@ async function runDoctor(rawCtx, opts) {
2523
2517
  };
2524
2518
  }
2525
2519
  //#endregion
2520
+ //#region src/help.ts
2521
+ const BIN = "mclaw-diagnose";
2522
+ function versionBanner() {
2523
+ return `v0.1.1-alpha.29`;
2524
+ }
2525
+ const COMMANDS = [
2526
+ {
2527
+ name: "doctor",
2528
+ hidden: false,
2529
+ summary: "Diagnose openclaw config; apply repairs with --fix",
2530
+ help: `USAGE
2531
+ ${BIN} doctor [--fix] [--rule=<key>]...
2532
+
2533
+ DESCRIPTION
2534
+ Fetches DoctorCtx via innerapi, then runs one of three modes depending
2535
+ on the flags. Output is a single JSON object on stdout.
2536
+
2537
+ MODES
2538
+ (no flags) Check-only. Runs the rule engine against the
2539
+ sandbox's current openclaw config and returns
2540
+ { failedRules: { standard, ai, reset } }
2541
+ No files are mutated. Use this when you just
2542
+ want to know what's wrong.
2543
+
2544
+ --fix Check + repair-all. First runs the rule engine,
2545
+ then repairs every failing standard-mode rule.
2546
+ Returns
2547
+ { check: {...}, repair: {...} }
2548
+ Use this as the default "fix everything" action.
2549
+
2550
+ --fix --rule=<key>... Targeted repair. Skips the check pass entirely
2551
+ and runs repair against the listed rule keys
2552
+ only. Unknown keys are silently ignored.
2553
+ Returns { repair: {...} } with only those
2554
+ rules' outcomes. Use this when you already
2555
+ know which rules need fixing.
2556
+
2557
+ OPTIONS
2558
+ --fix Enable repair. See MODES above.
2559
+ --rule=<key> Repair only this rule key. Repeatable. Only
2560
+ meaningful together with --fix.
2561
+
2562
+ EXAMPLES
2563
+ ${BIN} doctor # check only
2564
+ ${BIN} doctor --fix # check then repair all
2565
+ ${BIN} doctor --fix --rule=gateway # repair 'gateway' only
2566
+ ${BIN} doctor --fix --rule=gateway --rule=jwt_token # repair multiple
2567
+
2568
+ EXIT CODES
2569
+ 0 success
2570
+ 1 generic error
2571
+ 77 innerapi authentication failed (sandbox JWT expired/invalid)
2572
+ `
2573
+ },
2574
+ {
2575
+ name: "check",
2576
+ hidden: true,
2577
+ summary: "Run rule-engine check only",
2578
+ help: `USAGE
2579
+ ${BIN} check [--ctx=<base64>]
2580
+
2581
+ DESCRIPTION
2582
+ Runs the rule engine against the sandbox's current openclaw config and
2583
+ returns { failedRules }. Used by sandbox_console's push-style callers
2584
+ that already own the ctx — end-users should prefer \`doctor\`.
2585
+
2586
+ OPTIONS
2587
+ --ctx=<base64> Opaque ctx JSON (base64). When absent, fetched from
2588
+ innerapi (same path as doctor).
2589
+ `
2590
+ },
2591
+ {
2592
+ name: "repair",
2593
+ hidden: true,
2594
+ summary: "Apply standard-mode repairs",
2595
+ help: `USAGE
2596
+ ${BIN} repair [--ctx=<base64>]
2597
+
2598
+ DESCRIPTION
2599
+ Runs repair for the failing rules listed inside the ctx's repairData.
2600
+ Intended for sandbox_console's push path — end-users should use
2601
+ \`doctor --fix\` instead.
2602
+
2603
+ OPTIONS
2604
+ --ctx=<base64> Opaque ctx JSON (base64). When absent, fetched from
2605
+ innerapi.
2606
+ `
2607
+ },
2608
+ {
2609
+ name: "reset",
2610
+ hidden: true,
2611
+ summary: "Re-initialize sandbox via the 9-step reset pipeline",
2612
+ help: `USAGE
2613
+ ${BIN} reset --async [--ctx=<base64>]
2614
+ ${BIN} reset --worker --task-id=<id> [--ctx=<base64>]
2615
+
2616
+ DESCRIPTION
2617
+ Two-phase pipeline driven asynchronously: the --async invocation spawns
2618
+ a detached worker and returns { taskId } immediately; the --worker
2619
+ invocation (spawned by --async) runs the actual 9 steps and writes
2620
+ progress to /tmp/openclaw-diagnose/reset-<taskId>.json.
2621
+
2622
+ Poll progress with \`${BIN} get_reset_task --task-id=<id>\`.
2623
+
2624
+ OPTIONS
2625
+ --async Start a detached worker and return taskId on stdout.
2626
+ --worker Internal — run the 9-step pipeline (launched by --async).
2627
+ --task-id=<id> Required with --worker; identifies the progress file.
2628
+ --ctx=<base64> Opaque ctx JSON; fetched from innerapi when absent.
2629
+ `
2630
+ },
2631
+ {
2632
+ name: "get_reset_task",
2633
+ hidden: true,
2634
+ summary: "Poll progress of an async reset task",
2635
+ help: `USAGE
2636
+ ${BIN} get_reset_task --task-id=<id>
2637
+
2638
+ DESCRIPTION
2639
+ Reads /tmp/openclaw-diagnose/reset-<taskId>.json and prints its content
2640
+ as JSON on stdout. Safe to call repeatedly while reset is in progress.
2641
+
2642
+ OPTIONS
2643
+ --task-id=<id> Required. Matches the id returned by \`reset --async\`.
2644
+ `
2645
+ },
2646
+ {
2647
+ name: "install-openclaw",
2648
+ hidden: true,
2649
+ summary: "Download + install the openclaw tarball",
2650
+ help: `USAGE
2651
+ ${BIN} install-openclaw <tag> [--ctx=<base64> | --oss_file_map=<base64>]
2652
+
2653
+ DESCRIPTION
2654
+ Downloads the openclaw@<tag> tgz via the signed OSS URL found in the
2655
+ ctx's install.ossFileMap, extracts it into a tmpfs staging dir, and
2656
+ atomically swaps it into /home/gem/.npm-global/lib/node_modules/openclaw.
2657
+ Used by step 5 of reset.
2658
+
2659
+ ARGUMENTS
2660
+ <tag> Openclaw version tag, e.g. 2026.4.11.
2661
+
2662
+ OPTIONS
2663
+ --ctx=<base64> Opaque ctx; ossFileMap is extracted from it.
2664
+ --oss_file_map=... Pre-built OSS URL map (base64 JSON); skips innerapi
2665
+ entirely. Wins over --ctx when both provided.
2666
+ `
2667
+ },
2668
+ {
2669
+ name: "install-extension",
2670
+ hidden: true,
2671
+ summary: "Install openclaw extension package(s)",
2672
+ help: `USAGE
2673
+ ${BIN} install-extension <tag> (--all | --extension=<name>...) [options]
2674
+
2675
+ DESCRIPTION
2676
+ Downloads + installs one or more openclaw extension tarballs
2677
+ (feishu, miaoda, etc.) into <home_base>/workspace/agent/extensions/,
2678
+ then splices installMetadata into openclaw.json's plugins.installs
2679
+ unless --skip-config-update is passed.
2680
+
2681
+ ARGUMENTS
2682
+ <tag> Openclaw version tag; extension versions resolved
2683
+ against the matching manifest.
2684
+
2685
+ OPTIONS
2686
+ --all Install every extension in the manifest.
2687
+ --extension=<name> Install a specific extension (repeatable).
2688
+ --home_base=<dir> Override the /home/gem base (tests).
2689
+ --config_path=<p> Override the openclaw.json path (tests).
2690
+ --skip-config-update Leave plugins.installs in openclaw.json untouched.
2691
+ --ctx=<base64> Opaque ctx; see install-openclaw for semantics.
2692
+ --oss_file_map=... Pre-built OSS URL map (base64 JSON).
2693
+ `
2694
+ },
2695
+ {
2696
+ name: "download-resource",
2697
+ hidden: true,
2698
+ summary: "Download + extract a single OSS resource",
2699
+ help: `USAGE
2700
+ ${BIN} download-resource <tag> --role=<role> --name=<name> [--dir=<dir>] [options]
2701
+
2702
+ DESCRIPTION
2703
+ Downloads one resource (template, config asset, etc.) identified by
2704
+ (role, name) from the manifest and extracts/copies it to <dir>.
2705
+
2706
+ ARGUMENTS
2707
+ <tag> Openclaw version tag.
2708
+
2709
+ OPTIONS
2710
+ --role=<role> Package role (e.g. template, config).
2711
+ --name=<name> Package name within the role.
2712
+ --dir=<dir> Target dir (defaults to dirname(pkg.installPath)).
2713
+ --ctx=<base64> Opaque ctx; ossFileMap is extracted from it.
2714
+ --oss_file_map=... Pre-built OSS URL map (base64 JSON).
2715
+ `
2716
+ }
2717
+ ];
2718
+ function parseHelpFlags(args) {
2719
+ return {
2720
+ help: args.includes("--help") || args.includes("-h"),
2721
+ expert: args.includes("-x") || args.includes("--expert")
2722
+ };
2723
+ }
2724
+ /**
2725
+ * Render the top-level help to the given stream. When `expert` is true,
2726
+ * hidden commands are listed alongside the user-facing ones.
2727
+ */
2728
+ function formatTopLevelHelp(expert) {
2729
+ const visible = COMMANDS.filter((c) => !c.hidden);
2730
+ const hidden = COMMANDS.filter((c) => c.hidden);
2731
+ const pad = (s, w) => s + " ".repeat(Math.max(0, w - s.length));
2732
+ const w = Math.max(...COMMANDS.map((c) => c.name.length)) + 2;
2733
+ const lines = [];
2734
+ lines.push(`${BIN} — OpenClaw config diagnose / repair CLI`);
2735
+ lines.push(versionBanner());
2736
+ lines.push("");
2737
+ lines.push("USAGE");
2738
+ lines.push(` ${BIN} <command> [options]`);
2739
+ lines.push(` ${BIN} <command> --help per-command help`);
2740
+ lines.push(` ${BIN} --help this message`);
2741
+ lines.push("");
2742
+ lines.push("COMMANDS");
2743
+ for (const c of visible) lines.push(` ${pad(c.name, w)}${c.summary}`);
2744
+ if (expert && hidden.length > 0) {
2745
+ lines.push("");
2746
+ lines.push("INTERNAL COMMANDS (revealed by -x)");
2747
+ for (const c of hidden) lines.push(` ${pad(c.name, w)}${c.summary}`);
2748
+ }
2749
+ lines.push("");
2750
+ return lines.join("\n");
2751
+ }
2752
+ /** Render per-command help. Returns undefined when the name is unknown. */
2753
+ function formatCommandHelp(name) {
2754
+ const cmd = COMMANDS.find((c) => c.name === name);
2755
+ if (!cmd) return void 0;
2756
+ return cmd.help;
2757
+ }
2758
+ //#endregion
2526
2759
  //#region src/index.ts
2527
2760
  const args = node_process.default.argv.slice(2);
2528
- const mode = args.find((a) => !a.startsWith("--"));
2761
+ const mode = args.find((a) => !a.startsWith("-"));
2529
2762
  /**
2530
2763
  * Decode `--ctx=<base64>` into an opaque JSON object. Returns undefined when
2531
2764
  * the flag isn't present — the caller decides whether to fall back to the
@@ -2558,6 +2791,25 @@ function getMultiFlag(args, name) {
2558
2791
  }
2559
2792
  async function main() {
2560
2793
  installStderrMirror();
2794
+ const helpFlags = parseHelpFlags(args);
2795
+ if (mode && helpFlags.help) {
2796
+ const body = formatCommandHelp(mode);
2797
+ if (body) {
2798
+ node_process.default.stdout.write(body);
2799
+ return;
2800
+ }
2801
+ node_process.default.stderr.write(`Unknown command: ${mode}\n\n`);
2802
+ node_process.default.stderr.write(formatTopLevelHelp(helpFlags.expert));
2803
+ node_process.default.exit(1);
2804
+ }
2805
+ if (!mode) {
2806
+ if (helpFlags.help) {
2807
+ node_process.default.stdout.write(formatTopLevelHelp(helpFlags.expert));
2808
+ return;
2809
+ }
2810
+ node_process.default.stderr.write(formatTopLevelHelp(helpFlags.expert));
2811
+ node_process.default.exit(1);
2812
+ }
2561
2813
  switch (mode) {
2562
2814
  case "check":
2563
2815
  case "repair": {
@@ -2679,7 +2931,8 @@ async function main() {
2679
2931
  break;
2680
2932
  }
2681
2933
  default:
2682
- console.error("Usage: mclaw-diagnose <check|repair|doctor|reset|get_reset_task|install-openclaw|install-extension|download-resource> [options]");
2934
+ node_process.default.stderr.write(`Unknown command: ${mode}\n\n`);
2935
+ node_process.default.stderr.write(formatTopLevelHelp(helpFlags.expert));
2683
2936
  node_process.default.exit(1);
2684
2937
  }
2685
2938
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/openclaw-scripts-diagnose-cli",
3
- "version": "0.1.1-alpha.28",
3
+ "version": "0.1.1-alpha.29",
4
4
  "description": "CLI for OpenClaw config diagnose and repair with JSON5 support",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {