@getmarrow/install 0.1.24 → 0.1.25

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,40 +1,97 @@
1
1
  # @getmarrow/install
2
2
 
3
- Universal installer for Marrow agent governance, proof, and passive control setup.
3
+ Universal installer for Marrow passive agent setup.
4
4
 
5
- Use it when you want Marrow to detect the local agent/runtime environment and wire the safest passive governance integration automatically.
5
+ Use it when you want Marrow to detect the local agent/runtime environment and wire the safest passive integration automatically.
6
6
 
7
7
  ```bash
8
8
  npx @getmarrow/install --dry-run
9
9
  npx @getmarrow/install --yes
10
10
  npx @getmarrow/install --repair
11
11
  npx @getmarrow/install doctor
12
+ npx @getmarrow/install fleet
13
+ npx @getmarrow/install integrations
14
+ npx @getmarrow/install hermes
15
+ npx @getmarrow/install openclaw
12
16
  ```
13
17
 
14
- ## What's New in v0.1.24
18
+ ## What's New in v0.1.25
15
19
 
16
- v0.1.24 aligns the installer docs with Marrow's control-plane direction.
20
+ v0.1.25 adds first-class harness add-on paths for Hermes Agent and OpenClaw.
17
21
 
18
- - Marrow is positioned as an agent governance, proof, and intelligence layer, not a single-agent memory app.
19
- - The recommended setup path remains passive by default: install once, then let agents call runtime gates, completion contracts, and outcome closure as they work.
20
- - Hermes Agent is a supported client label and integration target; Marrow maps Hermes goals, verification evidence, learning, journey, and subagent outcomes into fleet governance proof.
21
- - New backend surfaces include governance control-plane proof, completion-contract evaluation, fleet governance timeline, and buyer-grade value proof.
22
+ - `npx @getmarrow/install integrations` lists Marrow-supported harness add-ons.
23
+ - `npx @getmarrow/install hermes` shows the Hermes attachment path and, when `MARROW_API_KEY` is present, verifies the backend integration contract.
24
+ - `npx @getmarrow/install openclaw` shows the OpenClaw attachment path and verifies the backend integration contract.
25
+ - `npx @getmarrow/install govern` now detects Hermes config files alongside Codex, Claude Code, Cursor, OpenCode, OpenClaw, CI scripts, and custom commands.
26
+ - Hermes `/goal`, verification evidence, `/learn`, `/journey`, and background subagents map into Marrow runtime gates, proof packs, fleet lessons, governance timeline, and outcome closure.
27
+ - OpenClaw sessions, handoff/result files, watchdog checkpoints, silent exits, and release supervisor results map into Marrow workflow sessions, proof packs, stale-outcome detection, and reusable handoff lessons.
22
28
 
23
- ## What's New in v0.1.23
29
+ This is the intended positioning: keep the harness your team already uses, and add Marrow as the governance, proof, and fleet-intelligence layer around it.
24
30
 
25
- v0.1.23 improves attribution quality so Marrow can produce cleaner per-agent, per-harness, and per-workflow value reports.
31
+ Examples:
26
32
 
27
- - Installer self-tests and governed runner calls attach `source_meta.channel`, `source_meta.client`, and inferred workflow intent by default.
28
- - Generated passive runtime keeps using SDK defaults for `agent_id`, harness/client, source channel, and user intent attribution.
29
- - Set `MARROW_CLIENT`, `MARROW_HARNESS`, or `MARROW_AGENT_CLIENT` to labels such as `codex`, `claude-code`, `cursor`, `gemini`, `qwen`, `opencode`, `hermes`, `openclaw`, or `custom`.
30
- - Invalid or unknown client labels fall back to `custom` instead of breaking onboarding.
31
- - Marrow still does not store prompts, completions, tool stdout/stderr, plaintext API keys, or raw model output for this feature.
33
+ ```bash
34
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install hermes
35
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install openclaw
36
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install integrations --json
37
+ ```
38
+
39
+ ## What's New in v0.1.20
40
+
41
+ v0.1.20 adds the Fleet Operator TUI for teams running multiple agents under one Marrow account.
42
+
43
+ - `npx @getmarrow/install fleet` opens a terminal operator view when run in a real TTY.
44
+ - CI/headless agents can use `npx @getmarrow/install fleet --no-interactive` for a stable text snapshot or `--json` for machine-readable status.
45
+ - The view shows live agents, active workflows, risky actions waiting for proof, failed/stale outcomes, backpressure/capacity status, recent decisions, degraded hooks, and deploy/publish/merge gate posture.
46
+ - Operators can press Enter to inspect an agent and print the exact fix command when hooks, outcome closure, or status coverage is degraded.
47
+ - The command reads existing Marrow account endpoints and degrades gracefully when a route is unavailable, so it is safe to use during incidents.
48
+
49
+ Example:
50
+
51
+ ```bash
52
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet
53
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --no-interactive
54
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --json
55
+ ```
56
+
57
+ ## What's New in v0.1.14
58
+
59
+ v0.1.14 adds adaptive governance mode recommendations without silent auto-switching.
60
+
61
+ - `npx @getmarrow/install govern` now detects project signals such as `package.json`, deploy/publish scripts, `wrangler` config, GitHub workflows, migrations, Cursor/Codex/Claude files, and MCP config.
62
+ - When `MARROW_API_KEY` is present, the TUI asks Marrow for a recommended mode: `passive`, `pilot`, or `enforce`.
63
+ - The TUI shows the exact reasons, confidence, and selected command before the user applies anything.
64
+ - User choice is explicit. Marrow logs whether the recommendation was accepted or overridden, but it does not silently switch modes.
65
+ - Policy profiles are supported by the backend/SDK/MCP so businesses can define rules like local=passive, staging=pilot, production deploys=enforce.
66
+
67
+ Example recommendation:
68
+
69
+ ```text
70
+ Recommended mode: pilot
71
+ Reason:
72
+ - Node project detected
73
+ - Cloudflare Worker detected
74
+ - GitHub workflow detected
75
+ - No owner approval policy configured yet
76
+ ```
77
+
78
+ ## What's New in v0.1.13
79
+
80
+ v0.1.13 turns `npx @getmarrow/install govern` into an interactive terminal setup flow when run in a real TTY.
32
81
 
33
- Business value: dashboards and reports can show which agents, harnesses, and workflow types are improving instead of grouping too much work into "unknown."
82
+ - Select Codex, Claude Code, Cursor, OpenCode, OpenClaw, CI scripts, or a custom command with arrow keys.
83
+ - Choose passive setup, governed pilot mode, or governed enforce mode.
84
+ - Run passive setup + self-test from the TUI after explicit confirmation.
85
+ - Check Marrow status and test the before-action gate from the same screen.
86
+ - Print the exact command for the selected harness/mode so users know what to run next.
87
+ - Exit cleanly with `q`, `Esc`, or `Ctrl+C`.
88
+ - CI/non-TTY usage remains stable with `npx @getmarrow/install govern --no-interactive`.
34
89
 
35
- ## Governed Runner
90
+ This keeps Marrow passive-first: install once, verify Marrow is active, then let agents use the runtime/gate path automatically for risky work.
36
91
 
37
- The Marrow governed runner is for businesses that want agent governance without replacing their existing harness.
92
+ ## What's New in v0.1.12
93
+
94
+ v0.1.12 adds the Marrow governed runner for businesses that want agent governance without replacing their existing harness.
38
95
 
39
96
  - `npx @getmarrow/install govern` prints a setup panel for detected harnesses and recommended protected commands.
40
97
  - `npx @getmarrow/install run --agent <agent-id> -- <command>` wraps existing agent, deploy, merge, publish, migration, and verification commands with Marrow's pre-action runtime gate.
@@ -53,6 +110,12 @@ Preview the detected harnesses and protected command examples:
53
110
  npx @getmarrow/install govern
54
111
  ```
55
112
 
113
+ In a real terminal, this opens the interactive setup flow. In CI or scripts, use:
114
+
115
+ ```bash
116
+ npx @getmarrow/install govern --no-interactive
117
+ ```
118
+
56
119
  Run a harmless command through Marrow:
57
120
 
58
121
  ```bash
@@ -78,6 +141,15 @@ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run \
78
141
 
79
142
  Use `--policy warn` for pilot mode and `--fail-open` only for non-production local workflows where Marrow should never block execution.
80
143
 
144
+ ## What's New in v0.1.10
145
+
146
+ - First-run output now explains the value in agent/user language: your agent is no longer starting from zero.
147
+ - Self-test prints first proof: setup decision captured, outcome closed, runtime gate active, and risky work now gets a pre-action brief.
148
+ - Fresh accounts get a guided prompt to try immediately: "I am about to deploy to production. What should I check first?"
149
+ - Existing accounts/fleets show stronger proof when available: avoided mistakes, reused winning decisions, prevented risky actions, and token/time savings.
150
+ - Generated SDK passive runtime now fails soft if `@getmarrow/sdk` is missing and the installer prints the exact dependency fix.
151
+ - Docs now make the universal installer the default path; SDK and MCP are advanced/manual integration paths.
152
+
81
153
  ## Which Install Path Should I Use?
82
154
 
83
155
  Start here unless you already know you need a lower-level integration:
@@ -95,14 +167,6 @@ Use the lower-level packages only when you need direct control:
95
167
 
96
168
  The three packages are not three competing onboarding paths. `@getmarrow/install` is the front door; SDK and MCP are the implementation paths underneath it.
97
169
 
98
- For cleaner attribution, set an agent id and optional client label before install:
99
-
100
- ```bash
101
- export MARROW_FLEET_AGENT_ID=codex-deploy-agent
102
- export MARROW_CLIENT=codex
103
- npx @getmarrow/install --yes
104
- ```
105
-
106
170
  ## Agent Value Proof Quickstart
107
171
 
108
172
  One command should prove Marrow is active and useful:
@@ -118,9 +182,7 @@ Expected result:
118
182
  - `/v1/agent/status` confirms capture health and missing hooks.
119
183
  - `/v1/agent/runtime` verifies the one-call runtime gate and returns the before-action intervention contract.
120
184
  - `/v1/agent/first-value` returns the five-minute proof payload used by installer, SDK, and MCP clients.
121
- - `/v1/agent/value/proof` returns token value proof from passive model-usage capture.
122
185
  - The installer prints: "Your agent is no longer starting from zero."
123
- - The installer prints: "Token value proof" with capture status, observed model calls, token totals, estimated savings, confidence, and exact next action.
124
186
  - Fresh accounts get a first useful action to try immediately.
125
187
  - Accounts with history get proof such as avoided mistakes, reused winning decisions, prevented risky actions, or estimated time/token savings.
126
188
 
@@ -134,9 +196,43 @@ I am about to deploy to production. What should I check first?
134
196
 
135
197
  Marrow should answer with `proceed`, `warn`, `block`, or `owner_approval_required`, plus required proof and matching fleet lessons/playbooks before the agent acts. This is the first product moment: not just "hooks installed", but "the agent is being warned before risky work."
136
198
 
199
+ ## Fleet Scale Startup Guidance
200
+
201
+ For business fleets, agents can read `GET /v1/agent/scale/capacity-contract` after install or during startup. The capacity contract tells the agent whether the account is under backpressure, when low-risk runtime guidance can be reused, when high-risk actions must still call Marrow, and how to batch low-risk telemetry through `/v1/agent/ingest/batch`.
202
+
203
+ This keeps Marrow passive without making it chatty. The current contract models the common `50 businesses x 50 agents = 2,500 agents` rollout shape and gives agents an exact next action: cache low-risk runtime guidance briefly, batch command/tool telemetry, and preserve proof-gated checks for deploys, publishes, merges, migrations, secrets, billing, and destructive work.
204
+
205
+ ## Fleet Operator TUI
206
+
207
+ Use the operator TUI when a human owner or orchestrator agent needs to understand fleet health before acting:
208
+
209
+ ```bash
210
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet
211
+ ```
212
+
213
+ It shows:
214
+
215
+ - live agents and selected agent inspection
216
+ - active workflows
217
+ - risky actions waiting for proof
218
+ - failed or stale outcomes
219
+ - backpressure and capacity guidance
220
+ - recent decisions
221
+ - degraded hooks
222
+ - deploy, publish, and merge gate status
223
+ - exact fix commands for common degraded states
224
+
225
+ For automated reports or headless agents:
226
+
227
+ ```bash
228
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --no-interactive
229
+ MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install fleet --json
230
+ ```
231
+
137
232
  ## What It Detects
138
233
 
139
234
  - OpenClaw-style workspaces
235
+ - Hermes Agent config files
140
236
  - Codex/agent instruction files such as `AGENTS.md`
141
237
  - Claude Code settings and hooks
142
238
  - Cursor project folders
@@ -166,7 +262,7 @@ npx @getmarrow/install --md --dry-run
166
262
 
167
263
  ## Self-Test
168
264
 
169
- When `MARROW_API_KEY` is present, the installer creates a harmless test decision, commits the outcome, reads `/v1/agent/status`, calls the one-call runtime, reads `/v1/agent/value/proof`, and prints the first useful Marrow signal plus token value proof.
265
+ When `MARROW_API_KEY` is present, the installer creates a harmless test decision, commits the outcome, reads `/v1/agent/status`, calls the one-call runtime, and prints the first useful Marrow signal.
170
266
 
171
267
  ```bash
172
268
  MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install --yes
@@ -200,34 +296,6 @@ npm install @getmarrow/sdk
200
296
 
201
297
  The generated runtime now fails soft with an explicit warning if the SDK package is missing, so onboarding does not crash a user process.
202
298
 
203
- ## Passive Token Value Proof
204
-
205
- Token value proof is default-on when the installer writes `.marrow/passive-runtime.mjs`.
206
-
207
- In supported Node/TypeScript agents, the SDK passive runtime wraps outbound model-provider `fetch` responses and captures compact `usage` blocks when providers return them. MCP and harness integrations can also attach `model_usage` to `marrow_commit` or call `marrow_model_usage` when the harness exposes usage metadata.
208
-
209
- Captured fields are intentionally narrow:
210
-
211
- - provider and model
212
- - input, output, cached, and total token counts
213
- - optional cost and latency estimates
214
- - agent, workflow, session, and decision linkage
215
- - Marrow intervention type, such as `runtime_gate`, `proof_pack`, or `before_you_act`
216
-
217
- Marrow does not capture prompt text, completion text, raw tool output, command output, full environment values, or plaintext secrets for token value proof.
218
-
219
- Disable capture only when a project requires it:
220
-
221
- ```bash
222
- MARROW_PASSIVE_TOKEN_USAGE=false
223
- ```
224
-
225
- Day-one behavior:
226
-
227
- - Fresh install: `Token usage capture is ready; no model calls have been reported yet.`
228
- - After observed usage: Marrow reports model calls, total tokens, estimated tokens saved, confidence, trend, and next action.
229
- - After workflows complete: agents should show the returned `token_value_signal` or value proof in owner updates so users see savings without opening a dashboard.
230
-
231
299
 
232
300
  ## Trust and Data Boundaries
233
301
 
@@ -4,7 +4,7 @@ const installer = require('../src/installer');
4
4
  const governedRunner = require('../src/governed-runner');
5
5
 
6
6
  const argv = process.argv.slice(2);
7
- const governedCommands = new Set(['run', 'gate', 'proof', 'status', 'govern', 'fleet']);
7
+ const governedCommands = new Set(['run', 'gate', 'proof', 'status', 'govern', 'fleet', 'hermes', 'openclaw', 'integrations']);
8
8
  const runCli = governedCommands.has(argv[0]) ? governedRunner.runCli : installer.runCli;
9
9
 
10
10
  runCli(argv).catch((error) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@getmarrow/install",
3
- "version": "0.1.24",
4
- "description": "Universal installer for Marrow agent governance, proof, and passive control setup.",
3
+ "version": "0.1.25",
4
+ "description": "Universal installer for Marrow passive agent setup.",
5
5
  "bin": {
6
6
  "marrow-install": "bin/marrow-install.js"
7
7
  },
@@ -15,10 +15,9 @@
15
15
  "marrow",
16
16
  "mcp",
17
17
  "installer",
18
- "passive-runtime",
19
18
  "governance",
20
- "proof-packs",
21
- "agent-control-plane"
19
+ "runner",
20
+ "passive-runtime"
22
21
  ],
23
22
  "repository": {
24
23
  "type": "git",
@@ -9,36 +9,6 @@ const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
9
9
  const HIGH_RISK_TERMS = /\b(deploy|prod|production|publish|release|merge|migration|migrate|secret|token|key|cloudflare|wrangler|npm publish|gh pr merge|git push|terraform apply|kubectl apply|delete|destroy|drop)\b/i;
10
10
  const GOVERN_TUI_ROW_COUNT = 7;
11
11
  const FLEET_TUI_ROW_COUNT = 11;
12
- const SOURCE_CLIENTS = new Set(['claude-code', 'cursor', 'windsurf', 'openclaw', 'codex', 'gemini', 'grok', 'deepseek', 'qwen', 'kimi', 'minimax', 'cline', 'opencode', 'hermes', 'glm', 'custom', 'unknown']);
13
-
14
- function sourceClient() {
15
- const raw = String(process.env.MARROW_CLIENT || process.env.MARROW_HARNESS || process.env.MARROW_AGENT_CLIENT || '').trim().toLowerCase().replace(/\s+/g, '-').replace(/^@/, '');
16
- const aliases = {
17
- claude: 'claude-code',
18
- claude_code: 'claude-code',
19
- 'claude-code': 'claude-code',
20
- cursor: 'cursor',
21
- windsurf: 'windsurf',
22
- openclaw: 'openclaw',
23
- codex: 'codex',
24
- 'openai-codex': 'codex',
25
- gemini: 'gemini',
26
- google: 'gemini',
27
- grok: 'grok',
28
- deepseek: 'deepseek',
29
- qwen: 'qwen',
30
- kimi: 'kimi',
31
- minimax: 'minimax',
32
- cline: 'cline',
33
- opencode: 'opencode',
34
- 'open-code': 'opencode',
35
- hermes: 'hermes',
36
- 'hermes-agent': 'hermes',
37
- glm: 'glm',
38
- };
39
- return aliases[raw] || (SOURCE_CLIENTS.has(raw) ? raw : 'custom');
40
- }
41
-
42
12
  function usage() {
43
13
  return `Usage:
44
14
  npx @getmarrow/install run --agent deploy-agent -- npm test
@@ -49,6 +19,9 @@ function usage() {
49
19
  npx @getmarrow/install govern
50
20
  npx @getmarrow/install govern --no-interactive
51
21
  npx @getmarrow/install fleet
22
+ npx @getmarrow/install integrations
23
+ npx @getmarrow/install hermes
24
+ npx @getmarrow/install openclaw
52
25
 
53
26
  Commands:
54
27
  run Run a command through Marrow pre-action gate and automatic outcome closure
@@ -57,6 +30,9 @@ Commands:
57
30
  status Read /v1/agent/status
58
31
  govern Interactive setup TUI when run in a terminal; text panel in CI/non-TTY
59
32
  fleet Fleet operator TUI for live agents, workflows, gates, proof debt, and exact fixes
33
+ integrations List Marrow-supported harness add-ons
34
+ hermes Show and verify the Marrow add-on path for Hermes Agent
35
+ openclaw Show and verify the Marrow add-on path for OpenClaw
60
36
 
61
37
  Options:
62
38
  --agent <id> Agent identity. Defaults to MARROW_FLEET_AGENT_ID, MARROW_AGENT_ID, or local user
@@ -185,6 +161,12 @@ function detectProjectSignals(cwd = process.cwd()) {
185
161
  addFile('CLAUDE.md', 'agent_instructions');
186
162
  addFile('.mcp.json', 'mcp_config');
187
163
  addFile('.cursor', 'cursor_project');
164
+ addFile('hermes.json', 'hermes_config');
165
+ addFile('hermes.yaml', 'hermes_config');
166
+ addFile('hermes.yml', 'hermes_config');
167
+ addFile('.hermes', 'hermes_config');
168
+ addFile('openclaw.json', 'openclaw_config');
169
+ addFile('.openclaw', 'openclaw_config');
188
170
 
189
171
  for (const script of packageScripts) {
190
172
  if (/\b(deploy|publish|release|migrate|migration|smoke|check|test)\b/i.test(script)) {
@@ -298,7 +280,7 @@ function parseArgs(argv) {
298
280
  return { command, options };
299
281
  }
300
282
 
301
- if (command === 'status' || command === 'govern' || command === 'fleet') {
283
+ if (command === 'status' || command === 'govern' || command === 'fleet' || command === 'hermes' || command === 'openclaw' || command === 'integrations') {
302
284
  const parsed = parseBaseOptions(argv, 1);
303
285
  if (parsed.options.help) return { command: 'help' };
304
286
  return { command, options: parsed.options };
@@ -313,7 +295,6 @@ function headers(options) {
313
295
  'Content-Type': 'application/json',
314
296
  'X-Marrow-Agent-Id': options.agentId,
315
297
  'X-Marrow-Session-Id': options.sessionId,
316
- 'X-Marrow-Client': sourceClient(),
317
298
  'User-Agent': '@getmarrow/install governed-runner',
318
299
  };
319
300
  return h;
@@ -480,11 +461,6 @@ async function createDecision(options, action, type) {
480
461
  profile: options.profile,
481
462
  governed: true,
482
463
  },
483
- source_meta: {
484
- channel: 'cli',
485
- client: sourceClient(),
486
- user_intent: type === 'deploy' ? 'deploy' : 'operate',
487
- },
488
464
  });
489
465
  }
490
466
 
@@ -724,13 +700,10 @@ function normalizeFixCommands(status, capacity) {
724
700
  add(status.route_contract?.exact_fix);
725
701
  add(status.auto_outcome_closure?.exact_fix);
726
702
  add(status.capture_coverage?.exact_fix);
727
- add(status.token_capture?.exact_fix);
728
- add(status.token_capture?.fix_command, true);
729
703
  add(capacity.exact_next_action, true);
730
704
  add(capacity.next_action, true);
731
705
  if (listValue(status.missed_hooks, status.degraded_hooks).length) add('npx @getmarrow/install --repair');
732
706
  if (status.auto_outcome_closure?.status === 'degraded') add('npx @getmarrow/install --repair');
733
- if (status.token_capture?.detected === false) add('npx @getmarrow/install --repair');
734
707
  return commands.slice(0, 6);
735
708
  }
736
709
 
@@ -884,6 +857,7 @@ function detectHarnesses(cwd = process.cwd()) {
884
857
  { name: 'Claude Code', command: 'claude -p', detected: fs.existsSync(path.join(cwd, 'CLAUDE.md')) || fs.existsSync(path.join(os.homedir(), '.claude.json')) },
885
858
  { name: 'Cursor', command: 'cursor', detected: fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(os.homedir(), '.cursor')) },
886
859
  { name: 'OpenCode', command: 'opencode', detected: fs.existsSync(path.join(cwd, 'opencode.json')) || fs.existsSync(path.join(os.homedir(), '.opencode')) },
860
+ { name: 'Hermes Agent', command: 'hermes', detected: fs.existsSync(path.join(cwd, 'hermes.json')) || fs.existsSync(path.join(cwd, '.hermes')) || fs.existsSync(path.join(os.homedir(), '.hermes')) || fs.existsSync(path.join(os.homedir(), '.hermes-agent')) },
887
861
  { name: 'OpenClaw', command: 'openclaw agent', detected: fs.existsSync(path.join(os.homedir(), '.openclaw')) },
888
862
  { name: 'CI script', command: 'npm test', detected: fs.existsSync(path.join(cwd, 'package.json')) },
889
863
  { name: 'Custom command', command: '<your-agent-command>', detected: true },
@@ -891,6 +865,140 @@ function detectHarnesses(cwd = process.cwd()) {
891
865
  return candidates;
892
866
  }
893
867
 
868
+ function localIntegrationManifest(name) {
869
+ const key = String(name || '').toLowerCase().replace(/\s+/g, '-');
870
+ if (key === 'hermes' || key === 'hermes-agent') {
871
+ return {
872
+ integration: 'hermes-agent',
873
+ title: 'Marrow + Hermes Agent',
874
+ client_label: 'hermes',
875
+ command: 'hermes',
876
+ install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install hermes',
877
+ governed_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent hermes-prod --profile production --policy enforce -- hermes',
878
+ capture_points: [
879
+ '/goal -> Marrow completion contract',
880
+ 'verification evidence -> Marrow proof pack',
881
+ '/learn -> outcome-ranked fleet lesson',
882
+ '/journey -> governance timeline',
883
+ 'background subagents -> agent_id + source_meta.client=hermes',
884
+ ],
885
+ exact_next_action: 'Run the Hermes add-on, then call Marrow runtime before deploy, merge, publish, migration, credential, or customer-facing work.',
886
+ };
887
+ }
888
+ if (key === 'openclaw' || key === 'open-claw') {
889
+ return {
890
+ integration: 'openclaw',
891
+ title: 'Marrow + OpenClaw',
892
+ client_label: 'openclaw',
893
+ command: 'openclaw agent',
894
+ install_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install openclaw',
895
+ governed_command: 'MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install run --agent openclaw-release --profile production --policy enforce -- openclaw agent',
896
+ capture_points: [
897
+ 'agent sessions -> workflow sessions',
898
+ 'handoff/result files -> proof packs',
899
+ 'timeouts/silent quits -> failed or stale outcomes',
900
+ 'release supervisor results -> deploy proof',
901
+ 'watchdog checkpoints -> fleet handoff lessons',
902
+ ],
903
+ exact_next_action: 'Run the OpenClaw add-on, then wrap release and handoff commands with the Marrow governed runner.',
904
+ };
905
+ }
906
+ return null;
907
+ }
908
+
909
+ async function integrationManifest(options, name) {
910
+ const local = localIntegrationManifest(name);
911
+ if (!local) throw new Error(`Unsupported integration: ${name}`);
912
+ if (!options.apiKey) return { source: 'local', manifest: local };
913
+ const route = name === 'openclaw' ? '/v1/agent/integrations/openclaw' : '/v1/agent/integrations/hermes';
914
+ try {
915
+ const remote = await requestJson(options, 'GET', route);
916
+ return { source: 'api', manifest: remote };
917
+ } catch (error) {
918
+ return { source: 'local', manifest: { ...local, api_warning: error instanceof Error ? error.message : String(error) } };
919
+ }
920
+ }
921
+
922
+ function renderIntegrationPanel(name, manifest, source = 'local', detectedHarnesses = detectHarnesses()) {
923
+ const title = manifest.title || (manifest.integration === 'openclaw' ? 'Marrow + OpenClaw' : 'Marrow + Hermes Agent');
924
+ const capturePoints = Array.isArray(manifest.capture_points)
925
+ ? manifest.capture_points.map((point) => {
926
+ if (typeof point === 'string') return point;
927
+ return `${point.harness_surface || point.hermes_surface || 'harness event'} -> ${point.marrow_mapping || 'Marrow event'}`;
928
+ })
929
+ : [];
930
+ const installCommands = Array.isArray(manifest.install_commands)
931
+ ? manifest.install_commands
932
+ : [manifest.install_command, manifest.governed_command].filter(Boolean);
933
+ const detected = detectedHarnesses.find((harness) => harness.name.toLowerCase().includes(name === 'openclaw' ? 'openclaw' : 'hermes'))?.detected;
934
+ const lines = [
935
+ title,
936
+ '',
937
+ `Status: ${manifest.status || 'supported'} (${source})`,
938
+ `Detected locally: ${detected ? 'yes' : 'not yet'}`,
939
+ `Client label: ${manifest.client_label}`,
940
+ '',
941
+ 'What Marrow captures:',
942
+ ...capturePoints.map((point) => ` - ${displayText(point, 110)}`),
943
+ '',
944
+ 'Install / run:',
945
+ ...installCommands.map((command) => ` ${displayText(command, 140)}`),
946
+ '',
947
+ 'Why this matters:',
948
+ ` ${displayText(manifest.marrow_positioning || 'Keep the harness. Add Marrow governance, proof packs, outcomes, and buyer-grade fleet value.', 140)}`,
949
+ '',
950
+ `Next: ${displayText(manifest.exact_next_action, 140)}`,
951
+ ];
952
+ if (manifest.api_warning) lines.push('', `API warning: ${displayText(manifest.api_warning, 120)}`);
953
+ return lines.join('\n');
954
+ }
955
+
956
+ async function integrationOnly(parsed, name) {
957
+ const result = await integrationManifest(parsed.options, name);
958
+ const panel = renderIntegrationPanel(name, result.manifest, result.source);
959
+ if (parsed.options.json) {
960
+ return {
961
+ ok: true,
962
+ source: result.source,
963
+ integration: result.manifest,
964
+ panel,
965
+ };
966
+ }
967
+ process.stdout.write(`${panel}\n`);
968
+ return { ok: true, source: result.source, integration: result.manifest };
969
+ }
970
+
971
+ async function integrationsOnly(parsed) {
972
+ const local = {
973
+ integration_registry_version: 'local.harness-addons-v1',
974
+ supported_harnesses: ['hermes', 'openclaw'].map((name) => localIntegrationManifest(name)),
975
+ exact_next_action: 'Run npx @getmarrow/install hermes or npx @getmarrow/install openclaw for a harness-specific setup path.',
976
+ };
977
+ let registry = local;
978
+ let source = 'local';
979
+ if (parsed.options.apiKey) {
980
+ try {
981
+ registry = await requestJson(parsed.options, 'GET', '/v1/agent/integrations');
982
+ source = 'api';
983
+ } catch (error) {
984
+ registry = { ...local, api_warning: error instanceof Error ? error.message : String(error) };
985
+ }
986
+ }
987
+ if (parsed.options.json) return { ok: true, source, registry };
988
+ const harnesses = Array.isArray(registry.supported_harnesses) ? registry.supported_harnesses : [];
989
+ process.stdout.write([
990
+ 'Marrow Harness Integrations',
991
+ '',
992
+ `Source: ${source}`,
993
+ 'Supported add-ons:',
994
+ ...harnesses.map((harness) => ` - ${displayText(harness.client_label || harness.integration || harness.title, 40)} ${displayText(harness.install_command || harness.install_commands?.[0] || '', 120)}`),
995
+ '',
996
+ `Next: ${displayText(registry.exact_next_action, 140)}`,
997
+ registry.api_warning ? `API warning: ${displayText(registry.api_warning, 120)}` : '',
998
+ ].filter(Boolean).join('\n') + '\n');
999
+ return { ok: true, source, registry };
1000
+ }
1001
+
894
1002
  function governPanel(options) {
895
1003
  const rows = detectHarnesses();
896
1004
  const project = detectProjectSignals();
@@ -1495,11 +1603,17 @@ async function runCli(argv) {
1495
1603
  return;
1496
1604
  } else if (parsed.command === 'fleet') {
1497
1605
  result = await runFleetInteractive(parsed.options);
1606
+ } else if (parsed.command === 'hermes') {
1607
+ result = await integrationOnly(parsed, 'hermes');
1608
+ } else if (parsed.command === 'openclaw') {
1609
+ result = await integrationOnly(parsed, 'openclaw');
1610
+ } else if (parsed.command === 'integrations') {
1611
+ result = await integrationsOnly(parsed);
1498
1612
  }
1499
1613
 
1500
1614
  if (parsed.options?.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
1501
1615
  else if (result?.blocked) process.stderr.write(`BLOCKED: ${result.message || 'Marrow blocked this action.'}\n`);
1502
- else if (parsed.command !== 'run' && parsed.command !== 'fleet') process.stdout.write('Marrow command completed.\n');
1616
+ else if (!['run', 'fleet', 'hermes', 'openclaw', 'integrations'].includes(parsed.command)) process.stdout.write('Marrow command completed.\n');
1503
1617
 
1504
1618
  if (parsed.command === 'run' || result?.blocked) process.exitCode = result?.exitCode ?? (result?.ok === false ? 1 : 0);
1505
1619
  }
@@ -1534,5 +1648,9 @@ module.exports = {
1534
1648
  buildFleetState,
1535
1649
  renderFleetTui,
1536
1650
  runFleetInteractive,
1651
+ localIntegrationManifest,
1652
+ renderIntegrationPanel,
1653
+ integrationOnly,
1654
+ integrationsOnly,
1537
1655
  runCli,
1538
1656
  };
package/src/installer.js CHANGED
@@ -6,35 +6,6 @@ const crypto = require('node:crypto');
6
6
  const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
7
7
  const MARROW_BLOCK_START = '<!-- marrow:passive-start -->';
8
8
  const MARROW_BLOCK_END = '<!-- marrow:passive-end -->';
9
- const SOURCE_CLIENTS = new Set(['claude-code', 'cursor', 'windsurf', 'openclaw', 'codex', 'gemini', 'grok', 'deepseek', 'qwen', 'kimi', 'minimax', 'cline', 'opencode', 'hermes', 'glm', 'custom', 'unknown']);
10
-
11
- function sourceClient() {
12
- const raw = String(process.env.MARROW_CLIENT || process.env.MARROW_HARNESS || process.env.MARROW_AGENT_CLIENT || '').trim().toLowerCase().replace(/\s+/g, '-').replace(/^@/, '');
13
- const aliases = {
14
- claude: 'claude-code',
15
- claude_code: 'claude-code',
16
- 'claude-code': 'claude-code',
17
- cursor: 'cursor',
18
- windsurf: 'windsurf',
19
- openclaw: 'openclaw',
20
- codex: 'codex',
21
- 'openai-codex': 'codex',
22
- gemini: 'gemini',
23
- google: 'gemini',
24
- grok: 'grok',
25
- deepseek: 'deepseek',
26
- qwen: 'qwen',
27
- kimi: 'kimi',
28
- minimax: 'minimax',
29
- cline: 'cline',
30
- opencode: 'opencode',
31
- 'open-code': 'opencode',
32
- hermes: 'hermes',
33
- 'hermes-agent': 'hermes',
34
- glm: 'glm',
35
- };
36
- return aliases[raw] || (SOURCE_CLIENTS.has(raw) ? raw : 'custom');
37
- }
38
9
 
39
10
  function parseArgs(argv) {
40
11
  const options = {
@@ -134,6 +105,12 @@ function findUp(startDir, names, maxDepth = 8) {
134
105
  }
135
106
 
136
107
  function projectRoot(startDir) {
108
+ const resolved = path.resolve(startDir);
109
+ if (path.basename(resolved) === '.marrow') return path.dirname(resolved);
110
+ if (path.basename(resolved) === 'env' && path.basename(path.dirname(resolved)) === '.marrow') {
111
+ return path.dirname(path.dirname(resolved));
112
+ }
113
+ if (exists(path.join(resolved, '.marrow'))) return resolved;
137
114
  const marker = findUp(startDir, ['package.json', 'pyproject.toml', 'requirements.txt', '.git', 'AGENTS.md', 'CLAUDE.md']);
138
115
  return marker ? path.dirname(marker) : path.resolve(startDir);
139
116
  }
@@ -312,16 +289,14 @@ Marrow should run passively after install:
312
289
 
313
290
  - Use MCP hooks when available: \`npx -y @getmarrow/mcp setup\`.
314
291
  - Use SDK passive runtime in owned Node processes: \`createPassiveRuntime().install()\`.
315
- - Keep passive token/model usage proof enabled so Marrow can show token, cost, latency, and workflow savings after real work completes.
316
- - Before risky work, use Marrow's decision brief or passive prompt hook.
292
+ - Before risky work, use Marrow's before-action intervention from \`GET /v1/agent/status\` or \`POST /v1/agent/runtime\`.
317
293
  - After meaningful work, record the outcome so future agents learn from it.
318
294
  - Check health with \`marrow_agent_status\` or \`GET /v1/agent/status\`.
319
295
 
320
296
  Required environment:
321
297
 
322
298
  - \`MARROW_API_KEY\`
323
- - Optional: \`MARROW_BASE_URL\`, \`MARROW_FLEET_AGENT_ID\`, \`MARROW_CLIENT\`
324
- - Optional: \`MARROW_PASSIVE_TOKEN_USAGE=false\` disables compact provider usage capture when needed.
299
+ - Optional: \`MARROW_BASE_URL\`, \`MARROW_FLEET_AGENT_ID\`
325
300
  ${MARROW_BLOCK_END}`;
326
301
  }
327
302
 
@@ -343,7 +318,6 @@ if (apiKey && !globalThis.__MARROW_PASSIVE_RUNTIME__) {
343
318
  useAgentRuntime: process.env.MARROW_AGENT_RUNTIME !== 'false',
344
319
  useWorkflowGate: process.env.MARROW_WORKFLOW_GATE !== 'false',
345
320
  requireOutcomeClosure: process.env.MARROW_REQUIRE_OUTCOME_CLOSURE !== 'false',
346
- captureModelUsage: process.env.MARROW_PASSIVE_TOKEN_USAGE !== 'false',
347
321
  });
348
322
 
349
323
  runtime.install();
@@ -359,14 +333,12 @@ function envExample() {
359
333
  return `MARROW_API_KEY=mrw_live_replace_me
360
334
  MARROW_BASE_URL=${DEFAULT_BASE_URL}
361
335
  MARROW_FLEET_AGENT_ID=agent-or-fleet-id
362
- MARROW_CLIENT=codex
363
336
  MARROW_ENFORCEMENT_MODE=auto
364
337
  MARROW_PASSIVE_BRIEF=auto
365
338
  MARROW_PASSIVE_VALUE_REPORT=true
366
339
  MARROW_AGENT_RUNTIME=true
367
340
  MARROW_WORKFLOW_GATE=true
368
341
  MARROW_REQUIRE_OUTCOME_CLOSURE=true
369
- MARROW_PASSIVE_TOKEN_USAGE=true
370
342
  `;
371
343
  }
372
344
 
@@ -595,7 +567,6 @@ async function runSelfTest(options) {
595
567
  authorization: `Bearer ${options.apiKey}`,
596
568
  'content-type': 'application/json',
597
569
  'x-marrow-session-id': `install-${Date.now()}`,
598
- 'x-marrow-client': sourceClient(),
599
570
  };
600
571
  if (options.agentId) headers['x-marrow-agent-id'] = options.agentId;
601
572
 
@@ -606,11 +577,6 @@ async function runSelfTest(options) {
606
577
  body: JSON.stringify({
607
578
  type: 'process',
608
579
  action: 'Marrow passive install self-test: verify SDK/MCP hooks can record a harmless setup event',
609
- source_meta: {
610
- channel: 'cli',
611
- client: sourceClient(),
612
- user_intent: 'operate',
613
- },
614
580
  }),
615
581
  });
616
582
 
@@ -667,14 +633,8 @@ async function runSelfTest(options) {
667
633
  ok: false,
668
634
  error: error instanceof Error ? error.message : String(error),
669
635
  }));
670
- const valueProof = await requestJson(`${baseUrl}/v1/agent/value/proof?period_days=30`, { headers })
671
- .catch((error) => ({
672
- ok: false,
673
- error: error instanceof Error ? error.message : String(error),
674
- }));
675
- const tokenValueProof = buildTokenValueProof(valueProof);
676
- const firstValueSignal = buildFirstValueSignal(status, runtime, performance, firstValue, tokenValueProof);
677
- const installValueMoment = buildInstallValueMoment(firstValueSignal, status, runtime, performance, firstValue, tokenValueProof);
636
+ const firstValueSignal = buildFirstValueSignal(status, runtime, performance, firstValue);
637
+ const installValueMoment = buildInstallValueMoment(firstValueSignal, status, runtime, performance, firstValue);
678
638
  return {
679
639
  skipped: false,
680
640
  decision_id: decisionId,
@@ -686,11 +646,11 @@ async function runSelfTest(options) {
686
646
  auto_outcome_closure: status.auto_outcome_closure || null,
687
647
  runtime_active: Boolean(runtime && runtime.ok !== false),
688
648
  runtime_exact_next_action: runtime.exact_next_action || null,
689
- runtime_before_you_act: runtime.before_you_act || null,
649
+ runtime_before_you_act: runtime.intervention?.agent_copy || runtime.intervention?.before_action || runtime.before_you_act || null,
650
+ runtime_intervention: runtime.intervention || null,
690
651
  first_value: firstValue && firstValue.ok !== false ? firstValue : null,
691
652
  first_value_signal: firstValueSignal,
692
653
  install_value_moment: installValueMoment,
693
- token_value_proof: tokenValueProof,
694
654
  performance_proof: performance && performance.ok !== false ? {
695
655
  avoided_mistakes: performance.avoided_mistakes ?? performance.avoided_repeated_mistakes ?? 0,
696
656
  reused_winning_decisions: performance.reused_winning_decisions ?? 0,
@@ -702,30 +662,11 @@ async function runSelfTest(options) {
702
662
  };
703
663
  }
704
664
 
705
- function buildTokenValueProof(valueProof = {}) {
706
- const modelUsage = valueProof && valueProof.ok !== false
707
- ? valueProof.model_usage || valueProof.token_value_signal || valueProof
708
- : null;
709
- if (!modelUsage || typeof modelUsage !== 'object') {
710
- return {
711
- enabled: true,
712
- capture_default: 'on_when_sdk_mcp_or_installer_hooks_available',
713
- observed: { model_calls: 0, tokens: { total: 0 } },
714
- savings: { estimated_tokens_saved: 0, estimated_minutes_saved: 0, confidence: 'none', method: 'warming_up' },
715
- proof_line: 'Token usage capture is ready; no model calls have been reported yet.',
716
- exact_next_action: 'Keep passive token capture enabled so Marrow can attach usage proof after real model calls complete.',
717
- };
718
- }
719
- return modelUsage;
720
- }
721
-
722
- function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {}, performance = {}, firstValue = {}, tokenValueProof = null) {
665
+ function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {}, performance = {}, firstValue = {}) {
723
666
  if (firstValue && firstValue.ok !== false && firstValue.first_value) {
724
- const proof = Array.isArray(firstValue.first_value.proof) ? [...firstValue.first_value.proof] : [];
725
- if (tokenValueProof?.proof_line && !proof.includes(tokenValueProof.proof_line)) proof.push(tokenValueProof.proof_line);
726
667
  return {
727
668
  headline: firstValue.headline || firstValue.first_value.headline || 'Your agent is no longer starting from zero.',
728
- proof,
669
+ proof: Array.isArray(firstValue.first_value.proof) ? firstValue.first_value.proof : [],
729
670
  fleet_signal: firstValue.history_signal?.summary || 'Fresh account: Marrow will build fleet memory from this first captured outcome.',
730
671
  try_this_now: firstValue.first_value.try_this_now || 'Ask your agent: "I am about to deploy to production. What should I check first?"',
731
672
  expected_response: firstValue.first_value.expected_response || 'Marrow should answer with a risk gate, required proof, and any matching fleet lessons before the agent acts.',
@@ -735,7 +676,9 @@ function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {
735
676
 
736
677
  const proof = firstValueSignal.value_proof || [];
737
678
  const hasFleetSignal = proof.length > 0;
738
- const runtimeLesson = runtime.before_you_act
679
+ const runtimeLesson = runtime.intervention?.agent_copy
680
+ || runtime.intervention?.before_action
681
+ || runtime.before_you_act
739
682
  || runtime.before_you_act_injection?.message
740
683
  || runtime.exact_next_action
741
684
  || firstValueSignal.first_lesson;
@@ -746,19 +689,18 @@ function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {
746
689
  'Captured this setup decision',
747
690
  'Closed the outcome successfully',
748
691
  'Runtime gate is ' + (firstValueSignal.active ? 'active' : 'installed'),
749
- runtimeLesson ? 'Future risky work now gets a pre-action brief' : 'Future risky work now gets checked before action',
750
- tokenValueProof?.proof_line || 'Token usage proof is active and warming up after the first model call',
692
+ runtime.intervention?.must_use_before_action ? 'Before-action intervention is active for risky work' : runtimeLesson ? 'Future risky work now gets a pre-action brief' : 'Future risky work now gets checked before action',
751
693
  ],
752
694
  fleet_signal: hasFleetSignal
753
695
  ? 'Marrow already found signal: ' + proof.join('; ') + '.'
754
696
  : 'Fresh account: Marrow will start building fleet memory from this first captured outcome.',
755
697
  try_this_now: 'Ask your agent: "I am about to deploy to production. What should I check first?"',
756
- expected_response: 'Marrow should answer with a risk gate, required proof, and any matching fleet lessons before the agent acts.',
757
- first_lesson: runtimeLesson || 'Marrow will surface prior lessons before risky or repeated work.',
698
+ expected_response: 'Marrow should answer with proceed/warn/block, required proof, and any matching prior lesson/playbook before the agent acts.',
699
+ first_lesson: runtimeLesson || 'Marrow will stop agents before risky or repeated work and surface the prior lesson/playbook.',
758
700
  };
759
701
  }
760
702
 
761
- function buildFirstValueSignal(status, runtime, performance, firstValue = {}, tokenValueProof = null) {
703
+ function buildFirstValueSignal(status, runtime, performance, firstValue = {}) {
762
704
  if (firstValue && firstValue.ok !== false && firstValue.first_value) {
763
705
  const capture = firstValue.capture || {};
764
706
  const proof = firstValue.value_proof || {};
@@ -767,13 +709,11 @@ function buildFirstValueSignal(status, runtime, performance, firstValue = {}, to
767
709
  if (Number(proof.reused_winning_decisions || 0) > 0) proofBits.push(`${proof.reused_winning_decisions} reused winning decision(s)`);
768
710
  if (Number(proof.prevented_bad_actions || 0) > 0) proofBits.push(`${proof.prevented_bad_actions} prevented risky action(s)`);
769
711
  if (Number(proof.estimated_tokens_saved || 0) > 0) proofBits.push(`~${proof.estimated_tokens_saved} tokens saved`);
770
- if (Number(tokenValueProof?.savings?.estimated_tokens_saved || 0) > 0) proofBits.push(`~${tokenValueProof.savings.estimated_tokens_saved} measured model tokens saved`);
771
- else if (tokenValueProof?.proof_line) proofBits.push(tokenValueProof.proof_line);
772
712
  return {
773
713
  active: Boolean(firstValue.active),
774
714
  headline: `Marrow active: ${(capture.surfaces || ['decisions']).join(', ')} captured.`,
775
715
  captured: capture.surfaces || ['decisions'],
776
- first_lesson: firstValue.first_value.first_lesson,
716
+ first_lesson: firstValue.first_value.first_lesson || runtime?.intervention?.agent_copy,
777
717
  value_proof: proofBits,
778
718
  next_action: firstValue.next_action?.reason || 'Keep working; Marrow will capture outcomes and reuse lessons automatically.',
779
719
  };
@@ -796,8 +736,6 @@ function buildFirstValueSignal(status, runtime, performance, firstValue = {}, to
796
736
  if (Number(proof.prevented_bad_actions || 0) > 0) proofBits.push(`${proof.prevented_bad_actions} prevented risky action(s)`);
797
737
  const tokens = proof.token_time_saved_estimate?.estimated_tokens_saved || 0;
798
738
  if (tokens > 0) proofBits.push(`~${tokens} tokens saved`);
799
- if (Number(tokenValueProof?.savings?.estimated_tokens_saved || 0) > 0) proofBits.push(`~${tokenValueProof.savings.estimated_tokens_saved} measured model tokens saved`);
800
- else if (tokenValueProof?.proof_line) proofBits.push(tokenValueProof.proof_line);
801
739
 
802
740
  const firstLesson = runtime.before_you_act
803
741
  || runtime.before_you_act_injection?.message
@@ -861,20 +799,6 @@ function printReport(report) {
861
799
  process.stdout.write(`- Next: ${report.selfTest.first_value_signal.next_action}\n`);
862
800
  }
863
801
  }
864
- if (report.selfTest.token_value_proof) {
865
- const proof = report.selfTest.token_value_proof;
866
- const observed = proof.observed || {};
867
- const savings = proof.savings || {};
868
- const tokens = observed.tokens || {};
869
- process.stdout.write('\nToken value proof:\n');
870
- process.stdout.write(`- passive capture: ${proof.enabled ? 'on' : 'unknown'}\n`);
871
- process.stdout.write(`- model calls observed: ${observed.model_calls || 0}\n`);
872
- process.stdout.write(`- tokens observed: ${tokens.total || 0}\n`);
873
- process.stdout.write(`- estimated tokens saved: ${savings.estimated_tokens_saved || 0}\n`);
874
- if (savings.confidence) process.stdout.write(`- confidence: ${savings.confidence}\n`);
875
- if (proof.proof_line) process.stdout.write(`- proof: ${proof.proof_line}\n`);
876
- if (proof.exact_next_action) process.stdout.write(`- next: ${proof.exact_next_action}\n`);
877
- }
878
802
  }
879
803
 
880
804
  if (report.remediation) {
@@ -1025,5 +949,4 @@ module.exports = {
1025
949
  inspectNpmTokenConfig,
1026
950
  inspectSdkDependency,
1027
951
  buildInstallValueMoment,
1028
- buildTokenValueProof,
1029
952
  };