@openclawbrain/cli 0.4.10 → 0.4.12

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/README.md CHANGED
@@ -1,31 +1,32 @@
1
1
  # @openclawbrain/cli
2
2
 
3
- `@openclawbrain/cli@0.4.10` is the published operator CLI package for OpenClawBrain.
3
+ Operator CLI for OpenClawBrain. Use it with `@openclawbrain/openclaw`.
4
4
 
5
- Primary public flow:
5
+ The public install story is three commands to install or update, one command to verify, and one official proof command when you need a durable operator bundle.
6
6
 
7
7
  ```bash
8
- openclaw plugins install @openclawbrain/openclaw@0.4.0
9
- npx @openclawbrain/cli@0.4.10 install --openclaw-home ~/.openclaw
8
+ openclaw plugins install @openclawbrain/openclaw
9
+ npx @openclawbrain/cli install --openclaw-home ~/.openclaw
10
10
  openclaw gateway restart
11
- npx @openclawbrain/cli@0.4.10 status --openclaw-home ~/.openclaw --detailed
11
+ npx @openclawbrain/cli status --openclaw-home ~/.openclaw --detailed
12
+ npx @openclawbrain/cli proof --openclaw-home ~/.openclaw --skip-install --skip-restart
12
13
  ```
13
14
 
14
- Patch note for `0.4.4`: the CLI now normalizes `plugins.allow` / `plugins.entries.openclawbrain` correctly on reinstall and reports the canonical `openclawbrain` install identity in status output.
15
+ The first three commands install or update OpenClawBrain. `status --detailed` is the quick verify surface. `proof` writes `summary.md`, `steps.json`, `verdict.json`, raw step logs, and proof pointers under one bundle directory.
15
16
 
16
- Host release note: patched OpenClaw host builds no longer emit the old `openclaw` vs `openclawbrain` mismatch warning. Older host builds may still show that warning until the host-side alias fix is released there.
17
-
18
- This package carries the `openclawbrain` CLI, daemon controls, import/export helpers, and install/status/operator management code. `@openclawbrain/openclaw` is the plugin/runtime payload.
19
-
20
- ## Commands
17
+ ## Common commands
21
18
 
22
19
  ```bash
23
- npx @openclawbrain/cli@0.4.10 install --openclaw-home ~/.openclaw
24
- npx @openclawbrain/cli@0.4.10 status --openclaw-home ~/.openclaw --detailed
25
- npx @openclawbrain/cli@0.4.10 rollback --activation-root /var/openclawbrain/activation --dry-run
26
- npx @openclawbrain/cli@0.4.10 daemon status --activation-root /var/openclawbrain/activation
20
+ npx @openclawbrain/cli rollback --openclaw-home ~/.openclaw --dry-run
21
+ npx @openclawbrain/cli detach --openclaw-home ~/.openclaw
22
+ npx @openclawbrain/cli uninstall --openclaw-home ~/.openclaw --keep-data
23
+ npx @openclawbrain/cli learn --openclaw-home ~/.openclaw --json
24
+ npx @openclawbrain/cli daemon status --activation-root ~/.openclawbrain/activation
27
25
  ```
28
26
 
29
- If the CLI is already on your `PATH`, `openclawbrain ...` is the same command surface. The docs lead with `npx` because that is the clean-host public-registry lane that already passed on `redogfood`.
27
+ ## Docs
30
28
 
31
- The old `openclawbrain-ops` alias stays wired to the same entrypoint for compatibility.
29
+ - [Repo README](../../README.md)
30
+ - [Quick start](../../docs/getting-started/quick-start.md)
31
+ - [Lifecycle](../../docs/lifecycle.md)
32
+ - [Troubleshooting](../../docs/operating/troubleshooting.md)
package/dist/src/cli.js CHANGED
@@ -23,6 +23,8 @@ import { summarizePackVectorEmbeddingState } from "./embedding-status.js";
23
23
  import { buildTracedLearningBridgePayloadFromRuntime, buildTracedLearningStatusSurface, persistTracedLearningBridgeState } from "./traced-learning-bridge.js";
24
24
  import { discoverOpenClawSessionStores, loadOpenClawSessionIndex, readOpenClawSessionFile } from "./session-store.js";
25
25
  import { readOpenClawBrainProviderDefaults, readOpenClawBrainProviderConfig, readOpenClawBrainProviderConfigFromSources, resolveOpenClawBrainProviderDefaultsPath } from "./provider-config.js";
26
+ import { formatOperatorLearningPathSummary } from "./status-learning-path.js";
27
+ import { buildProofCommandForOpenClawHome, buildProofCommandHelpSection, captureOperatorProofBundle, formatOperatorProofResult, parseProofCliArgs } from "./proof-command.js";
26
28
  const OPENCLAWBRAIN_EMBEDDER_BASE_URL_ENV = "OPENCLAWBRAIN_EMBEDDER_BASE_URL";
27
29
  const OPENCLAWBRAIN_EMBEDDER_PROVIDER_ENV = "OPENCLAWBRAIN_EMBEDDER_PROVIDER";
28
30
  const OPENCLAWBRAIN_EMBEDDER_MODEL_ENV = "OPENCLAWBRAIN_EMBEDDER_MODEL";
@@ -465,6 +467,7 @@ function buildSetupDeletedMessage() {
465
467
  ].join(" ");
466
468
  }
467
469
  function operatorCliHelp() {
470
+ const proofHelp = buildProofCommandHelpSection();
468
471
  return [
469
472
  "Usage:",
470
473
  " openclawbrain install [--openclaw-home <path>] [options]",
@@ -479,6 +482,7 @@ function operatorCliHelp() {
479
482
  " openclawbrain scan --session <trace.json> --root <path> [options]",
480
483
  " openclawbrain scan --live <event-export-path> --workspace <workspace.json> [options]",
481
484
  " openclawbrain learn [--activation-root <path>|--openclaw-home <path>] [--json]",
485
+ proofHelp.usage,
482
486
  " openclawbrain-ops <status|rollback> [--activation-root <path>|--openclaw-home <path>] [options] # compatibility alias",
483
487
  " openclawbrain-ops scan --session <trace.json> --root <path> [options] # compatibility alias",
484
488
  "",
@@ -507,6 +511,7 @@ function operatorCliHelp() {
507
511
  " --limit <N> Maximum number of history entries to show (default: 20, history only).",
508
512
  " --scan-root <path> Event-export scan root for watch mode (defaults to <activation-root>/event-exports).",
509
513
  " --interval <seconds> Polling interval for watch mode (default: 30).",
514
+ ...proofHelp.optionLines,
510
515
  " --json Emit machine-readable JSON instead of text.",
511
516
  " --help Show this help.",
512
517
  "",
@@ -515,17 +520,19 @@ function operatorCliHelp() {
515
520
  " 2. attach openclawbrain attach --openclaw-home <path> [--activation-root <path>] — explicit reattach/manual hook path for known brain data; use install first",
516
521
  " 3. status openclawbrain status --activation-root <path> — answer \"How's the brain?\" for that boundary",
517
522
  " 4. status --detailed openclawbrain status --activation-root <path> --detailed — explain serve path, freshness, backlog, and failure mode",
518
- " 5. watch openclawbrain watch --activation-root <path> — run the foreground learning/watch loop",
519
- " 6. daemon start openclawbrain daemon start --activation-root <path> — keep watch running in the background on macOS",
520
- " 7. daemon status openclawbrain daemon status --activation-root <path> — inspect the background watch state",
521
- " 8. detach openclawbrain detach --openclaw-home <path> — remove the profile hookup only and keep brain data",
522
- " 9. uninstall openclawbrain uninstall --openclaw-home <path> --keep-data|--purge-data — remove the hookup and choose the data outcome explicitly",
523
+ proofHelp.lifecycle,
524
+ " 6. watch openclawbrain watch --activation-root <path> — run the foreground learning/watch loop",
525
+ " 7. daemon start openclawbrain daemon start --activation-root <path> — keep watch running in the background on macOS",
526
+ " 8. daemon status openclawbrain daemon status --activation-root <path> — inspect the background watch state",
527
+ " 9. detach openclawbrain detach --openclaw-home <path> — remove the profile hookup only and keep brain data",
528
+ " 10. uninstall openclawbrain uninstall --openclaw-home <path> --keep-data|--purge-data — remove the hookup and choose the data outcome explicitly",
523
529
  "",
524
530
  "Advanced/operator surfaces:",
525
531
  " context preview the brain context that would be injected for a message",
526
532
  " rollback preview or apply active <- previous, active -> candidate pointer movement",
527
533
  " scan inspect one recorded session or live event export without claiming a daemon is running",
528
534
  " learn one-shot local-session learning pass against the resolved activation root",
535
+ proofHelp.advanced,
529
536
  " status --teacher-snapshot keeps the current live-first / principal-priority / passive-backfill learner order visible when that snapshot exists",
530
537
  " native package installs still need the openclawbrain CLI available because install/attach pin the activation root for that package copy",
531
538
  " watch/daemon persist their operator snapshot at <activation-root>/watch/teacher-snapshot.json; --teacher-snapshot overrides the default path",
@@ -538,7 +545,8 @@ function operatorCliHelp() {
538
545
  " attach: 0 on successful profile hookup/bootstrap, 1 on input/read failure.",
539
546
  " detach: 0 on successful unhook, 1 on input/read failure.",
540
547
  " uninstall: 0 on successful unhook/cleanup, 1 on input/read failure.",
541
- " scan: 0 on successful replay/scan, 1 on input/read failure."
548
+ " scan: 0 on successful replay/scan, 1 on input/read failure.",
549
+ " proof: 0 on successful bundle capture, 1 on input/read failure."
542
550
  ].join("\n");
543
551
  }
544
552
  function yesNo(value) {
@@ -1396,7 +1404,11 @@ function formatCurrentProfileStatusSummary(status, report, targetInspection, opt
1396
1404
  `scanner flowing=${yesNo(report.supervision.flowing)} scan=${report.supervision.scanPolicy ?? "none"} surfaces=${formatScannerSurfaces(report)} labels=${report.supervision.humanLabelCount ?? "none"}/${report.supervision.selfLabelCount ?? "none"} attributable=${report.supervision.attributedEventCount ?? "none"}/${report.supervision.totalEventCount ?? "none"} digests=${report.supervision.selectionDigestCount ?? "none"}`,
1397
1405
  `labels ${formatLabelFlowSummary(report.labelFlow)}`,
1398
1406
  `graph source=${report.graph.runtimePlasticitySource ?? "none"} blocks=${report.graph.blockCount ?? "none"} strongest=${report.graph.strongestBlockId ?? "none"} ops=${formatStructuralOps(report)} latest=${report.graph.latestMaterialization.packId ?? "none"} latestChanged=${yesNo(report.graph.latestMaterialization.changed)} connect=${formatGraphConnectDiagnostics(report.graph.latestMaterialization.connectDiagnostics ?? report.graph.connectDiagnostics)} summary=${formatGraphSummary(report)}`,
1399
- `path ${formatLearningPathSummary(report.learningPath)}`,
1407
+ `path ${formatOperatorLearningPathSummary({
1408
+ status,
1409
+ learningPath: report.learningPath,
1410
+ tracedLearning
1411
+ })}`,
1400
1412
  `learning state=${report.learning.backlogState} bootstrapped=${yesNo(report.learning.bootstrapped)} mode=${report.learning.mode} next=${report.learning.nextPriorityLane} priority=${report.learning.nextPriorityBucket} pending=${report.learning.pendingLive ?? "none"}/${report.learning.pendingBackfill ?? "none"} buckets=${formatLearningBuckets(report)} warn=${formatLearningWarnings(report)} lastPack=${report.learning.lastMaterializedPackId ?? "none"} detail=${report.learning.detail}`,
1401
1413
  `traced ${formatTracedLearningSurface(tracedLearning)}`,
1402
1414
  `teacherProof ${formatTeacherLoopSummary(report)}`,
@@ -1875,7 +1887,7 @@ function buildStatusNextStep(status, report, options) {
1875
1887
  return "Repair the runtime-load proof file before trusting attach truth again; status now knows the exact file that broke.";
1876
1888
  }
1877
1889
  if (options.installHook.state === "installed" && status.brainStatus.serveState === "serving_active_pack") {
1878
- return "Check the OpenClaw startup log for the `[openclawbrain] BRAIN LOADED` breadcrumb when you need live hook-load proof.";
1890
+ return `Capture a durable proof bundle: \`${buildProofCommandForOpenClawHome(options.openclawHome)}\`.`;
1879
1891
  }
1880
1892
  if (report.learning.warningStates.includes("principal_live_backlog") ||
1881
1893
  report.learning.warningStates.includes("active_pack_behind_latest_principal")) {
@@ -2002,9 +2014,12 @@ export function parseOperatorCliArgs(argv) {
2002
2014
  args.shift();
2003
2015
  return parseDaemonArgs(args);
2004
2016
  }
2005
- if (args[0] === "status" || args[0] === "rollback" || args[0] === "scan" || args[0] === "attach" || args[0] === "install" || args[0] === "detach" || args[0] === "uninstall" || args[0] === "context" || args[0] === "history" || args[0] === "learn" || args[0] === "watch" || args[0] === "export" || args[0] === "import" || args[0] === "reset") {
2017
+ if (args[0] === "status" || args[0] === "rollback" || args[0] === "scan" || args[0] === "attach" || args[0] === "install" || args[0] === "detach" || args[0] === "uninstall" || args[0] === "context" || args[0] === "history" || args[0] === "learn" || args[0] === "watch" || args[0] === "export" || args[0] === "import" || args[0] === "reset" || args[0] === "proof") {
2006
2018
  command = args.shift();
2007
2019
  }
2020
+ if (command === "proof") {
2021
+ return parseProofCliArgs(args);
2022
+ }
2008
2023
  if (command === "learn") {
2009
2024
  for (let index = 0; index < args.length; index += 1) {
2010
2025
  const arg = args[index];
@@ -3384,6 +3399,7 @@ function runProfileHookAttachCommand(parsed) {
3384
3399
  ? null
3385
3400
  : `Confirm gateway after restart: ${brainFeedback.restart.gatewayStatusCommand}`,
3386
3401
  `Check status: ${buildInstallStatusCommand(parsed.activationRoot)}`,
3402
+ `Capture proof: ${buildProofCommandForOpenClawHome(parsed.openclawHome)}`,
3387
3403
  `Check learner service: ${buildLearnerServiceStatusCommand(parsed.activationRoot)}`,
3388
3404
  embedderProvision !== null && embedderProvision.state === "skipped"
3389
3405
  ? `Provision default embedder later: ${buildInstallEmbedderProvisionCommand(embedderProvision.baseUrl, embedderProvision.model)}`
@@ -3532,6 +3548,7 @@ function runProfileHookAttachCommand(parsed) {
3532
3548
  console.log(`Gateway: Confirm OpenClaw after restart: ${brainFeedback.restart.gatewayStatusCommand}`);
3533
3549
  }
3534
3550
  console.log(`Check: ${buildInstallStatusCommand(parsed.activationRoot)}`);
3551
+ console.log(`Proof: ${buildProofCommandForOpenClawHome(parsed.openclawHome)}`);
3535
3552
  console.log(`Learner: ${buildLearnerServiceStatusCommand(parsed.activationRoot)}`);
3536
3553
  if (embedderProvision !== null && embedderProvision.state === "skipped") {
3537
3554
  console.log(`Embedder: ${buildInstallEmbedderProvisionCommand(embedderProvision.baseUrl, embedderProvision.model)}`);
@@ -4238,7 +4255,8 @@ function runLearnCommand(parsed) {
4238
4255
  maxCycles: 16,
4239
4256
  pgVersion: serveTimeLearning.pgVersion,
4240
4257
  ...(serveTimeLearning.decisionLogCount > 0 ? { serveTimeDecisions: serveTimeLearning.serveTimeDecisions } : {}),
4241
- ...(serveTimeLearning.baselineState !== undefined ? { baselineState: serveTimeLearning.baselineState } : {})
4258
+ ...(serveTimeLearning.baselineState !== undefined ? { baselineState: serveTimeLearning.baselineState } : {}),
4259
+ activationRoot
4242
4260
  });
4243
4261
  const lastMaterialization = learnerResult.materializations.at(-1) ?? null;
4244
4262
  const plan = describeAlwaysOnLearningRuntimeState(learnerResult.state, lastMaterialization);
@@ -5542,6 +5560,28 @@ function runResetCommand(parsed) {
5542
5560
  }
5543
5561
  return 0;
5544
5562
  }
5563
+ function runProofCommand(parsed) {
5564
+ if (parsed.help) {
5565
+ console.log(operatorCliHelp());
5566
+ return 0;
5567
+ }
5568
+ const result = captureOperatorProofBundle({
5569
+ openclawHome: parsed.openclawHome,
5570
+ activationRoot: parsed.activationRoot,
5571
+ outputDir: parsed.outputDir,
5572
+ skipInstall: parsed.skipInstall,
5573
+ skipRestart: parsed.skipRestart,
5574
+ pluginId: parsed.pluginId,
5575
+ timeoutMs: parsed.timeoutMs,
5576
+ });
5577
+ if (parsed.json) {
5578
+ console.log(JSON.stringify(result, null, 2));
5579
+ }
5580
+ else {
5581
+ console.log(formatOperatorProofResult(result));
5582
+ }
5583
+ return 0;
5584
+ }
5545
5585
  export function runOperatorCli(argv = process.argv.slice(2)) {
5546
5586
  const parsed = parseOperatorCliArgs(argv);
5547
5587
  if (parsed.command === "context") {
@@ -5550,6 +5590,9 @@ export function runOperatorCli(argv = process.argv.slice(2)) {
5550
5590
  if (parsed.command === "reset") {
5551
5591
  return runResetCommand(parsed);
5552
5592
  }
5593
+ if (parsed.command === "proof") {
5594
+ return runProofCommand(parsed);
5595
+ }
5553
5596
  if (parsed.help) {
5554
5597
  console.log(operatorCliHelp());
5555
5598
  return 0;
@@ -8,7 +8,7 @@
8
8
  * Commands:
9
9
  * daemon start — generate and load a launchd plist
10
10
  * daemon stop — unload the plist
11
- * daemon status — show running/stopped + PID + last log lines
11
+ * daemon status — show running/stopped + PID + launch command + last log lines
12
12
  * daemon logs — tail the daemon log file
13
13
  */
14
14
  type DaemonCommandRunner = (command: string) => string;
@@ -42,6 +42,11 @@ export interface ManagedLearnerServiceInspection {
42
42
  running: boolean;
43
43
  pid: number | null;
44
44
  configuredActivationRoot: string | null;
45
+ configuredProgramArguments: string[] | null;
46
+ configuredCommand: string | null;
47
+ configuredRuntimePath: string | null;
48
+ configuredRuntimePackageSpec: string | null;
49
+ configuredRuntimeLooksEphemeral: boolean | null;
45
50
  matchesRequestedActivationRoot: boolean | null;
46
51
  launchctlAvailable: boolean;
47
52
  }