@xerg/cli 0.1.9 → 0.1.10

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.js CHANGED
@@ -4,6 +4,112 @@
4
4
  import { readFileSync as readFileSync7 } from "fs";
5
5
  import { styleText as styleText2 } from "util";
6
6
 
7
+ // src/command-display.ts
8
+ var PACKAGE_NAME = "@xerg/cli";
9
+ var DEFAULT_COMMAND_PREFIX = "xerg";
10
+ function resolveCommandDisplay(context) {
11
+ const runner = detectPackageExecutor(context);
12
+ if (!runner) {
13
+ return {
14
+ prefix: DEFAULT_COMMAND_PREFIX,
15
+ name: DEFAULT_COMMAND_PREFIX
16
+ };
17
+ }
18
+ return {
19
+ prefix: `${runner} ${PACKAGE_NAME}`,
20
+ name: PACKAGE_NAME
21
+ };
22
+ }
23
+ function formatCommand(command2, commandPrefix = resolveCommandDisplay().prefix) {
24
+ const suffix = Array.isArray(command2) ? command2.join(" ") : command2;
25
+ return suffix ? `${commandPrefix} ${suffix}` : commandPrefix;
26
+ }
27
+ function detectPackageExecutor(context) {
28
+ const env = context?.env ?? process.env;
29
+ const argv2 = context?.argv ?? process.argv;
30
+ const userAgent = normalizeSignal(env.npm_config_user_agent);
31
+ const execPath = normalizeSignal(env.npm_execpath);
32
+ const argvPath = normalizeSignal(argv2[1]);
33
+ const fromArgvPath = detectRunnerFromArgvPath(argvPath);
34
+ if (fromArgvPath) {
35
+ return fromArgvPath;
36
+ }
37
+ if (looksLikeInstalledCli(argvPath)) {
38
+ return null;
39
+ }
40
+ const fromUserAgent = detectRunnerFromSignal(userAgent);
41
+ if (fromUserAgent) {
42
+ return fromUserAgent;
43
+ }
44
+ const fromExecPath = detectRunnerFromSignal(execPath);
45
+ if (fromExecPath) {
46
+ return fromExecPath;
47
+ }
48
+ if (argvPath.includes("/_npx/") || argvPath.includes("\\_npx\\")) {
49
+ return "npx";
50
+ }
51
+ if (argvPath.includes("/.yarn/") && argvPath.includes("/dlx/")) {
52
+ return "yarn dlx";
53
+ }
54
+ if (argvPath.includes("/bunx/") || argvPath.includes("\\bunx\\")) {
55
+ return "bunx";
56
+ }
57
+ if (argvPath.includes("/dlx-") || argvPath.includes("\\dlx-")) {
58
+ return "pnpm dlx";
59
+ }
60
+ if (userAgent || execPath) {
61
+ return "npx";
62
+ }
63
+ return null;
64
+ }
65
+ function detectRunnerFromArgvPath(argvPath) {
66
+ if (!argvPath) {
67
+ return null;
68
+ }
69
+ if (argvPath.includes("/_npx/") || argvPath.includes("\\_npx\\")) {
70
+ return "npx";
71
+ }
72
+ if (argvPath.includes("/.yarn/") && argvPath.includes("/dlx/")) {
73
+ return "yarn dlx";
74
+ }
75
+ if (argvPath.includes("/bunx/") || argvPath.includes("\\bunx\\")) {
76
+ return "bunx";
77
+ }
78
+ if (argvPath.includes("/dlx-") || argvPath.includes("\\dlx-")) {
79
+ return "pnpm dlx";
80
+ }
81
+ return null;
82
+ }
83
+ function looksLikeInstalledCli(argvPath) {
84
+ if (!argvPath) {
85
+ return false;
86
+ }
87
+ const normalized = argvPath.replaceAll("\\", "/");
88
+ return normalized.endsWith("/node_modules/.bin/xerg") || normalized.includes("/node_modules/@xerg/cli/dist/index.js") || normalized.endsWith("/bin/xerg");
89
+ }
90
+ function detectRunnerFromSignal(signal) {
91
+ if (!signal) {
92
+ return null;
93
+ }
94
+ const tokens = signal.split(/[^a-z0-9]+/).filter(Boolean);
95
+ if (tokens.includes("pnpm")) {
96
+ return "pnpm dlx";
97
+ }
98
+ if (tokens.includes("yarn")) {
99
+ return "yarn dlx";
100
+ }
101
+ if (tokens.includes("bun")) {
102
+ return "bunx";
103
+ }
104
+ if (tokens.includes("npm")) {
105
+ return "npx";
106
+ }
107
+ return null;
108
+ }
109
+ function normalizeSignal(value) {
110
+ return value?.trim().toLowerCase() ?? "";
111
+ }
112
+
7
113
  // src/commands/audit.ts
8
114
  import { readFileSync as readFileSync5 } from "fs";
9
115
  import { rmSync as rmSync4 } from "fs";
@@ -1400,7 +1506,7 @@ async function auditOpenClaw(options) {
1400
1506
  if (sources.length === 0) {
1401
1507
  options.onProgress?.("No OpenClaw source files were detected.");
1402
1508
  throw new Error(
1403
- "No OpenClaw sources were detected. Run `xerg doctor` or provide --log-file / --sessions-dir."
1509
+ `No OpenClaw sources were detected. Run \`${options.commandPrefix ?? "xerg"} doctor\` or provide --log-file / --sessions-dir.`
1404
1510
  );
1405
1511
  }
1406
1512
  options.onProgress?.(`Detected ${sources.length} source file${sources.length === 1 ? "" : "s"}.`);
@@ -1657,13 +1763,14 @@ function renderCompareBlock(summary) {
1657
1763
  ...findingChanges.length > 0 ? findingChanges : ["- High-confidence waste changes: none"]
1658
1764
  ];
1659
1765
  }
1660
- function renderDoctorReport(report) {
1766
+ function renderDoctorReport(report, options) {
1767
+ const commandPrefix = options?.commandPrefix ?? "xerg";
1661
1768
  const nextSteps = report.canAudit ? [] : [
1662
1769
  "",
1663
1770
  "## Next steps",
1664
- "- Try explicit local paths: xerg doctor --log-file /path/to/openclaw.log --sessions-dir /path/to/sessions",
1665
- "- Inspect an SSH host: xerg doctor --remote user@host",
1666
- "- Inspect a Railway service: xerg doctor --railway",
1771
+ `- Try explicit local paths: ${commandPrefix} doctor --log-file /path/to/openclaw.log --sessions-dir /path/to/sessions`,
1772
+ `- Inspect an SSH host: ${commandPrefix} doctor --remote user@host`,
1773
+ `- Inspect a Railway service: ${commandPrefix} doctor --railway`,
1667
1774
  "- Remote audits still analyze locally after Xerg pulls the source files to your machine."
1668
1775
  ];
1669
1776
  const sections = [
@@ -1961,7 +2068,7 @@ function loadPushConfig() {
1961
2068
  };
1962
2069
  }
1963
2070
  throw new Error(
1964
- `No API key configured. Set XERG_API_KEY, add "apiKey" to ${CONFIG_PATH}, or run \`xerg login\`.
2071
+ `No API key configured. Set XERG_API_KEY, add "apiKey" to ${CONFIG_PATH}, or run \`${formatCommand("login")}\`.
1965
2072
  Get your key at https://xerg.ai/dashboard/settings`
1966
2073
  );
1967
2074
  }
@@ -2522,7 +2629,7 @@ async function pullRemoteFilesRailway(opts) {
2522
2629
  const { status } = railwayExec("echo ok", target);
2523
2630
  if (status !== 0) {
2524
2631
  throw new Error(
2525
- `Cannot reach Railway service${target ? ` (project: ${target.projectId})` : " (linked project)"}. Check railway CLI auth and service configuration.`
2632
+ target ? `Cannot reach Railway service ${target.serviceId} (project: ${target.projectId}). Check the provided --project / --environment / --service values and confirm the Railway CLI can reach that service.` : "Cannot reach the Railway service linked to this directory. Run `railway link` here and choose the OpenClaw app service, or pass --project / --environment / --service explicitly."
2526
2633
  );
2527
2634
  }
2528
2635
  onProgress?.("Railway service reachable.");
@@ -2535,7 +2642,7 @@ async function pullRemoteFilesRailway(opts) {
2535
2642
  const resolvedSessionsPath = findSessionsPath(target, source.sessionsDir);
2536
2643
  let pulledLog = false;
2537
2644
  let pulledSessions = false;
2538
- if (logCheck.exists) {
2645
+ if (logCheck.fileCount > 0) {
2539
2646
  onProgress?.(`Pulling gateway logs from ${remoteLogPath}...`);
2540
2647
  const { stdout: isFile } = railwayExec(`test -f ${remoteLogPath} && echo file`, target);
2541
2648
  if (isFile === "file") {
@@ -2571,8 +2678,9 @@ async function pullRemoteFilesRailway(opts) {
2571
2678
  const checkedPaths = [remoteLogPath, DEFAULT_SESSIONS_DIR2, ...ALTERNATE_SESSION_PATHS].join(
2572
2679
  ", "
2573
2680
  );
2681
+ const wrongServiceHint = target ? " Verify that the selected service is the OpenClaw app, or use --remote-log-file / --remote-sessions-dir for custom paths." : " If this directory is linked to a database or sidecar instead of the OpenClaw app, run `railway link` again and choose the app service.";
2574
2682
  throw new Error(
2575
- `No OpenClaw data found on Railway service. Checked: ${checkedPaths}. Use --remote-log-file or --remote-sessions-dir to specify custom paths.`
2683
+ `No OpenClaw data found on Railway service. Checked: ${checkedPaths}. Use --remote-log-file or --remote-sessions-dir to specify custom paths.${wrongServiceHint}`
2576
2684
  );
2577
2685
  }
2578
2686
  const result = {
@@ -2635,12 +2743,12 @@ async function runRailwayDoctor(opts) {
2635
2743
  railwayAuthenticated: true,
2636
2744
  railwayAuthUser,
2637
2745
  serviceReachable: false,
2638
- serviceError: target ? `Cannot reach service ${target.serviceId}` : "Cannot reach linked service. Run: railway link",
2746
+ serviceError: target ? `Cannot reach service ${target.serviceId} in project ${target.projectId}` : "Current directory is not linked to a reachable Railway service. Run `railway link` here and choose the OpenClaw app service, or pass --project / --environment / --service.",
2639
2747
  defaultPaths: emptyDefaultPaths(),
2640
2748
  alternateSessionPaths: [],
2641
2749
  notes: [
2642
2750
  ...notes,
2643
- target ? `Service unreachable (project: ${target.projectId}, service: ${target.serviceId})` : "Service unreachable. Ensure a project is linked with: railway link"
2751
+ target ? `Service unreachable (project: ${target.projectId}, service: ${target.serviceId}). Verify the provided Railway IDs point at the OpenClaw app service.` : "Service unreachable for the current directory. Run `railway link` here and choose the OpenClaw app service, or pass explicit Railway IDs."
2644
2752
  ]
2645
2753
  };
2646
2754
  }
@@ -2700,9 +2808,11 @@ async function runRailwayDoctor(opts) {
2700
2808
  alternateSessionPaths,
2701
2809
  notes
2702
2810
  };
2811
+ let logCheck = null;
2812
+ let sessCheck = null;
2703
2813
  if (source.logFile || source.sessionsDir) {
2704
- const logCheck = source.logFile ? checkRemotePath(source.logFile, target) : null;
2705
- const sessCheck = source.sessionsDir ? checkRemotePath(source.sessionsDir, target) : null;
2814
+ logCheck = source.logFile ? checkRemotePath(source.logFile, target) : null;
2815
+ sessCheck = source.sessionsDir ? checkRemotePath(source.sessionsDir, target) : null;
2706
2816
  report.customPaths = {
2707
2817
  logFileExists: logCheck?.exists ?? false,
2708
2818
  logFilePath: source.logFile ?? "",
@@ -2725,6 +2835,12 @@ async function runRailwayDoctor(opts) {
2725
2835
  notes.push(`Custom sessions path ${source.sessionsDir}: not found`);
2726
2836
  }
2727
2837
  }
2838
+ const foundOpenClawData = gateway.fileCount > 0 || sessions.fileCount > 0 || alternateSessionPaths.some((path) => path.fileCount > 0) || (logCheck?.fileCount ?? 0) > 0 || (sessCheck?.fileCount ?? 0) > 0;
2839
+ if (!foundOpenClawData) {
2840
+ notes.push(
2841
+ target ? "No OpenClaw data was found on this Railway service. Verify that the selected service is the OpenClaw app, or use --remote-log-file / --remote-sessions-dir for custom paths." : "No OpenClaw data was found on the linked Railway service. If this directory is linked to a database or sidecar instead of the OpenClaw app, run `railway link` again and choose the app service."
2842
+ );
2843
+ }
2728
2844
  return report;
2729
2845
  }
2730
2846
  function emptyDefaultPaths() {
@@ -2900,6 +3016,7 @@ async function runLocalAudit(options, logger) {
2900
3016
  compare: options.compare,
2901
3017
  dbPath: options.db,
2902
3018
  noDb: options.noDb,
3019
+ commandPrefix: options.commandPrefix,
2903
3020
  onProgress: logger.verbose
2904
3021
  });
2905
3022
  renderOutput(summary, options);
@@ -2949,6 +3066,7 @@ async function runSingleRemoteAudit(source, options, logger) {
2949
3066
  dbPath: options.db,
2950
3067
  noDb: options.noDb,
2951
3068
  comparisonKeyOverride,
3069
+ commandPrefix: options.commandPrefix,
2952
3070
  onProgress: logger.verbose
2953
3071
  });
2954
3072
  renderOutput(summary, options);
@@ -3002,6 +3120,7 @@ ${errorMessages}`);
3002
3120
  dbPath: options.db,
3003
3121
  noDb: options.noDb,
3004
3122
  comparisonKeyOverride,
3123
+ commandPrefix: options.commandPrefix,
3005
3124
  onProgress: logger.verbose
3006
3125
  });
3007
3126
  summaries.push({ name: source.name, source, summary });
@@ -3184,7 +3303,7 @@ async function runDoctorCommand(options) {
3184
3303
  sessionsDir: options.sessionsDir,
3185
3304
  onProgress: logger.verbose
3186
3305
  });
3187
- process.stdout.write(`${renderDoctorReport(report)}
3306
+ process.stdout.write(`${renderDoctorReport(report, { commandPrefix: options.commandPrefix })}
3188
3307
  `);
3189
3308
  }
3190
3309
  function buildRailwayTarget2(options) {
@@ -3308,7 +3427,7 @@ async function runLoginCommand() {
3308
3427
  if (existing) {
3309
3428
  process.stderr.write(
3310
3429
  `Already logged in. Credentials stored at ${getCredentialsPath()}.
3311
- Run ${colorBold("xerg logout")} first to re-authenticate.
3430
+ Run ${colorBold(formatCommand("logout"))} first to re-authenticate.
3312
3431
  `
3313
3432
  );
3314
3433
  return;
@@ -3374,7 +3493,7 @@ Credentials saved to ${getCredentialsPath()}.
3374
3493
  continue;
3375
3494
  }
3376
3495
  if (res.status === 410) {
3377
- throw new Error("Device code expired. Please run `xerg login` again.");
3496
+ throw new Error(`Device code expired. Please run \`${formatCommand("login")}\` again.`);
3378
3497
  }
3379
3498
  const body = await res.json().catch(() => ({}));
3380
3499
  throw new Error(body.error || `Unexpected response: HTTP ${res.status}`);
@@ -3384,7 +3503,7 @@ Credentials saved to ${getCredentialsPath()}.
3384
3503
  }
3385
3504
  }
3386
3505
  }
3387
- throw new Error("Authentication timed out. Please run `xerg login` again.");
3506
+ throw new Error(`Authentication timed out. Please run \`${formatCommand("login")}\` again.`);
3388
3507
  }
3389
3508
  async function openBrowser(url) {
3390
3509
  const { exec } = await import("child_process");
@@ -3472,12 +3591,12 @@ function loadPayloadFromCache() {
3472
3591
  summaries = listStoredAuditSummaries(dbPath);
3473
3592
  } catch {
3474
3593
  throw new NoDataError(
3475
- "No local audit database found. Run `xerg audit` first, or use `xerg push --file <path>`."
3594
+ `No local audit database found. Run \`${formatCommand("audit")}\` first, or use \`${formatCommand("push --file <path>")}\`.`
3476
3595
  );
3477
3596
  }
3478
3597
  if (summaries.length === 0) {
3479
3598
  throw new NoDataError(
3480
- "No cached audit snapshots found. Run `xerg audit` first, or use `xerg push --file <path>`."
3599
+ `No cached audit snapshots found. Run \`${formatCommand("audit")}\` first, or use \`${formatCommand("push --file <path>")}\`.`
3481
3600
  );
3482
3601
  }
3483
3602
  const latest = summaries[0];
@@ -3509,9 +3628,10 @@ function buildMeta2() {
3509
3628
  // src/index.ts
3510
3629
  var VERSION = readVersion();
3511
3630
  var argv = process.argv.slice(2);
3631
+ var commandDisplay = resolveCommandDisplay();
3512
3632
  var command = argv[0];
3513
3633
  if (!command || command === "--help" || command === "-h" || command === "help") {
3514
- process.stdout.write(renderRootHelp());
3634
+ process.stdout.write(renderRootHelp(commandDisplay));
3515
3635
  process.exit(0);
3516
3636
  }
3517
3637
  if (command === "--version" || command === "-v" || command === "version") {
@@ -3521,7 +3641,7 @@ if (command === "--version" || command === "-v" || command === "version") {
3521
3641
  }
3522
3642
  run().catch((error) => {
3523
3643
  const message = error instanceof Error ? error.message : "Unknown error";
3524
- process.stderr.write(`${colorError(`xerg failed: ${message}`)}
3644
+ process.stderr.write(`${colorError(`${commandDisplay.name} failed: ${message}`)}
3525
3645
  `);
3526
3646
  process.exitCode = error instanceof NoDataError ? 2 : 1;
3527
3647
  });
@@ -3531,12 +3651,18 @@ async function run() {
3531
3651
  if (options.json && options.markdown) {
3532
3652
  throw new Error("Use either --json or --markdown, not both.");
3533
3653
  }
3534
- await runAuditCommand(options);
3654
+ await runAuditCommand({
3655
+ ...options,
3656
+ commandPrefix: commandDisplay.prefix
3657
+ });
3535
3658
  return;
3536
3659
  }
3537
3660
  if (command === "doctor") {
3538
3661
  const options = parseDoctorOptions(argv.slice(1));
3539
- await runDoctorCommand(options);
3662
+ await runDoctorCommand({
3663
+ ...options,
3664
+ commandPrefix: commandDisplay.prefix
3665
+ });
3540
3666
  return;
3541
3667
  }
3542
3668
  if (command === "push") {
@@ -3552,7 +3678,9 @@ async function run() {
3552
3678
  runLogoutCommand();
3553
3679
  return;
3554
3680
  }
3555
- throw new Error(`Unknown command "${command}". Run \`xerg --help\` to see available commands.`);
3681
+ throw new Error(
3682
+ `Unknown command "${command}". Run \`${formatCommand("--help", commandDisplay.prefix)}\` to see available commands.`
3683
+ );
3556
3684
  }
3557
3685
  function parseAuditOptions(raw) {
3558
3686
  const argv2 = expandEqualsArgs(raw);
@@ -3562,7 +3690,7 @@ function parseAuditOptions(raw) {
3562
3690
  switch (arg) {
3563
3691
  case "--help":
3564
3692
  case "-h":
3565
- process.stdout.write(renderAuditHelp());
3693
+ process.stdout.write(renderAuditHelp(commandDisplay.prefix));
3566
3694
  process.exit(0);
3567
3695
  break;
3568
3696
  case "--log-file":
@@ -3645,7 +3773,9 @@ function parseAuditOptions(raw) {
3645
3773
  index += 1;
3646
3774
  break;
3647
3775
  default:
3648
- throw new Error(`Unknown audit option "${arg}". Run \`xerg audit --help\` for usage.`);
3776
+ throw new Error(
3777
+ `Unknown audit option "${arg}". Run \`${formatCommand(["audit", "--help"], commandDisplay.prefix)}\` for usage.`
3778
+ );
3649
3779
  }
3650
3780
  }
3651
3781
  return options;
@@ -3658,7 +3788,7 @@ function parsePushOptions(raw) {
3658
3788
  switch (arg) {
3659
3789
  case "--help":
3660
3790
  case "-h":
3661
- process.stdout.write(renderPushHelp());
3791
+ process.stdout.write(renderPushHelp(commandDisplay.prefix));
3662
3792
  process.exit(0);
3663
3793
  break;
3664
3794
  case "--file":
@@ -3669,7 +3799,9 @@ function parsePushOptions(raw) {
3669
3799
  options.dryRun = true;
3670
3800
  break;
3671
3801
  default:
3672
- throw new Error(`Unknown push option "${arg}". Run \`xerg push --help\` for usage.`);
3802
+ throw new Error(
3803
+ `Unknown push option "${arg}". Run \`${formatCommand(["push", "--help"], commandDisplay.prefix)}\` for usage.`
3804
+ );
3673
3805
  }
3674
3806
  }
3675
3807
  return options;
@@ -3682,7 +3814,7 @@ function parseDoctorOptions(raw) {
3682
3814
  switch (arg) {
3683
3815
  case "--help":
3684
3816
  case "-h":
3685
- process.stdout.write(renderDoctorHelp());
3817
+ process.stdout.write(renderDoctorHelp(commandDisplay.prefix));
3686
3818
  process.exit(0);
3687
3819
  break;
3688
3820
  case "--log-file":
@@ -3724,7 +3856,9 @@ function parseDoctorOptions(raw) {
3724
3856
  options.verbose = true;
3725
3857
  break;
3726
3858
  default:
3727
- throw new Error(`Unknown doctor option "${arg}". Run \`xerg doctor --help\` for usage.`);
3859
+ throw new Error(
3860
+ `Unknown doctor option "${arg}". Run \`${formatCommand(["doctor", "--help"], commandDisplay.prefix)}\` for usage.`
3861
+ );
3728
3862
  }
3729
3863
  }
3730
3864
  return options;
@@ -3755,13 +3889,13 @@ function readFloat(flag, value) {
3755
3889
  }
3756
3890
  return num;
3757
3891
  }
3758
- function renderRootHelp() {
3759
- return `xerg ${VERSION}
3892
+ function renderRootHelp(display = commandDisplay) {
3893
+ return `${display.name} ${VERSION}
3760
3894
 
3761
3895
  Waste intelligence for OpenClaw workflows.
3762
3896
 
3763
3897
  Usage:
3764
- xerg <command> [options]
3898
+ ${formatCommand("<command> [options]", display.prefix)}
3765
3899
 
3766
3900
  Commands:
3767
3901
  audit Analyze OpenClaw logs and produce a waste intelligence report.
@@ -3775,13 +3909,13 @@ Global options:
3775
3909
  -v, --version Show version
3776
3910
  `;
3777
3911
  }
3778
- function renderAuditHelp() {
3779
- return `xerg audit
3912
+ function renderAuditHelp(commandPrefix = commandDisplay.prefix) {
3913
+ return `${formatCommand("audit", commandPrefix)}
3780
3914
 
3781
3915
  Analyze OpenClaw logs and produce a waste intelligence report.
3782
3916
 
3783
3917
  Usage:
3784
- xerg audit [options]
3918
+ ${formatCommand("audit [options]", commandPrefix)}
3785
3919
 
3786
3920
  Options:
3787
3921
  --log-file <path> Explicit OpenClaw gateway log file to analyze
@@ -3823,13 +3957,13 @@ Threshold options:
3823
3957
  -h, --help Show help
3824
3958
  `;
3825
3959
  }
3826
- function renderPushHelp() {
3827
- return `xerg push
3960
+ function renderPushHelp(commandPrefix = commandDisplay.prefix) {
3961
+ return `${formatCommand("push", commandPrefix)}
3828
3962
 
3829
3963
  Push a cached audit snapshot to the Xerg API.
3830
3964
 
3831
3965
  Usage:
3832
- xerg push [options]
3966
+ ${formatCommand("push [options]", commandPrefix)}
3833
3967
 
3834
3968
  Options:
3835
3969
  --file <path> Push a specific snapshot file instead of the most recent cached audit
@@ -3839,17 +3973,17 @@ Options:
3839
3973
 
3840
3974
  Authentication:
3841
3975
  Set XERG_API_KEY in your environment, add "apiKey" to ~/.xerg/config.json,
3842
- or run \`xerg login\` to authenticate via browser.
3976
+ or run \`${formatCommand("login", commandPrefix)}\` to authenticate via browser.
3843
3977
  Browser login stores a token at ~/.config/xerg/credentials.json by default.
3844
3978
  `;
3845
3979
  }
3846
- function renderDoctorHelp() {
3847
- return `xerg doctor
3980
+ function renderDoctorHelp(commandPrefix = commandDisplay.prefix) {
3981
+ return `${formatCommand("doctor", commandPrefix)}
3848
3982
 
3849
3983
  Inspect your machine for OpenClaw sources and audit readiness.
3850
3984
 
3851
3985
  Usage:
3852
- xerg doctor [options]
3986
+ ${formatCommand("doctor [options]", commandPrefix)}
3853
3987
 
3854
3988
  Options:
3855
3989
  --log-file <path> Explicit OpenClaw gateway log file to inspect