@getmarrow/install 0.1.7 → 0.1.8

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 (3) hide show
  1. package/README.md +30 -8
  2. package/package.json +1 -1
  3. package/src/installer.js +106 -23
package/README.md CHANGED
@@ -11,13 +11,13 @@ npx @getmarrow/install --repair
11
11
  npx @getmarrow/install doctor
12
12
  ```
13
13
 
14
- ## What's New in v0.1.6
14
+ ## What's New in v0.1.8
15
15
 
16
- - Installer doctor/repair now detects npm token/config path mismatches like `~/.openclaw/.env` versus `~/.npmrc` without printing token values.
17
- - `--repair` can sync the active npm token into `~/.npmrc` when a mismatch is detected, preserving a local backup.
18
- - Generated SDK passive runtime now requires outcome closure by default with `MARROW_REQUIRE_OUTCOME_CLOSURE=true`.
19
- - Self-test still creates a harmless decision, commits the outcome, checks status, calls the one-call runtime, and prints first-value proof.
20
- - Doctor/repair output gives exact safe setup and repair commands without exposing credentials.
16
+ - First-run output now explains the value in agent/user language: your agent is no longer starting from zero.
17
+ - Self-test prints first proof: setup decision captured, outcome closed, runtime gate active, and risky work now gets a pre-action brief.
18
+ - Fresh accounts get a guided prompt to try immediately: "I am about to deploy to production. What should I check first?"
19
+ - Existing accounts/fleets show stronger proof when available: avoided mistakes, reused winning decisions, prevented risky actions, and token/time savings.
20
+ - Generated SDK passive runtime now fails soft if `@getmarrow/sdk` is missing and the installer prints the exact dependency fix.
21
21
 
22
22
  ## Agent Value Proof Quickstart
23
23
 
@@ -32,8 +32,20 @@ Expected result:
32
32
  - Marrow writes the safest detected MCP/SDK/agent config.
33
33
  - A harmless setup decision is created and its outcome is committed.
34
34
  - `/v1/agent/status` confirms capture health and missing hooks.
35
- - `/v1/agent/runtime` returns the first "before you act" lesson or exact next action.
36
- - The installer prints first-value proof such as captured surfaces, reused lessons, prevented risky actions, or estimated time/token savings when enough history exists.
35
+ - `/v1/agent/runtime` verifies the one-call runtime gate.
36
+ - The installer prints: "Your agent is no longer starting from zero."
37
+ - Fresh accounts get a first useful action to try immediately.
38
+ - Accounts with history get proof such as avoided mistakes, reused winning decisions, prevented risky actions, or estimated time/token savings.
39
+
40
+ ## First Five-Minute Proof
41
+
42
+ After install, ask the agent:
43
+
44
+ ```text
45
+ I am about to deploy to production. What should I check first?
46
+ ```
47
+
48
+ Marrow should answer with a pre-action risk gate, required proof, and matching fleet lessons before the agent acts. This is the first product moment: not just "hooks installed", but "the agent is being warned before risky work."
37
49
 
38
50
  ## What It Detects
39
51
 
@@ -91,6 +103,16 @@ Repair missing hooks/config:
91
103
  MARROW_API_KEY=mrw_live_xxx npx @getmarrow/install --repair
92
104
  ```
93
105
 
106
+ ## SDK Dependency
107
+
108
+ When the installer writes `.marrow/passive-runtime.mjs`, the project should have `@getmarrow/sdk` installed:
109
+
110
+ ```bash
111
+ npm install @getmarrow/sdk
112
+ ```
113
+
114
+ The generated runtime now fails soft with an explicit warning if the SDK package is missing, so onboarding does not crash a user process.
115
+
94
116
  ## Trust Model
95
117
 
96
118
  This package is intended to be open source and auditable. It prints every file it will touch, requires `--yes` to write, does not store API keys in project files, and supports MCP-only, SDK-only, both, and markdown-only setups.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getmarrow/install",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Universal installer for Marrow passive agent setup.",
5
5
  "bin": {
6
6
  "marrow-install": "bin/marrow-install.js"
package/src/installer.js CHANGED
@@ -295,27 +295,30 @@ ${MARROW_BLOCK_END}`;
295
295
  }
296
296
 
297
297
  function passiveRuntimeSource() {
298
- return `import { MarrowClient } from '@getmarrow/sdk';
299
-
300
- const apiKey = process.env.MARROW_API_KEY;
298
+ return `const apiKey = process.env.MARROW_API_KEY;
301
299
  if (apiKey && !globalThis.__MARROW_PASSIVE_RUNTIME__) {
302
- const marrow = new MarrowClient(apiKey, {
303
- baseUrl: process.env.MARROW_BASE_URL,
304
- agentId: process.env.MARROW_FLEET_AGENT_ID || process.env.MARROW_AGENT_ID,
305
- sessionId: process.env.MARROW_SESSION_ID,
306
- mode: process.env.MARROW_ENFORCEMENT_MODE || 'auto',
307
- });
300
+ try {
301
+ const { MarrowClient } = await import('@getmarrow/sdk');
302
+ const marrow = new MarrowClient(apiKey, {
303
+ baseUrl: process.env.MARROW_BASE_URL,
304
+ agentId: process.env.MARROW_FLEET_AGENT_ID || process.env.MARROW_AGENT_ID,
305
+ sessionId: process.env.MARROW_SESSION_ID,
306
+ mode: process.env.MARROW_ENFORCEMENT_MODE || 'auto',
307
+ });
308
308
 
309
- const runtime = marrow.createPassiveRuntime({
310
- includeValueReport: process.env.MARROW_PASSIVE_VALUE_REPORT !== 'false',
311
- valueReportPeriod: process.env.MARROW_VALUE_REPORT_PERIOD || '7d',
312
- useAgentRuntime: process.env.MARROW_AGENT_RUNTIME !== 'false',
313
- useWorkflowGate: process.env.MARROW_WORKFLOW_GATE !== 'false',
314
- requireOutcomeClosure: process.env.MARROW_REQUIRE_OUTCOME_CLOSURE !== 'false',
315
- });
309
+ const runtime = marrow.createPassiveRuntime({
310
+ includeValueReport: process.env.MARROW_PASSIVE_VALUE_REPORT !== 'false',
311
+ valueReportPeriod: process.env.MARROW_VALUE_REPORT_PERIOD || '7d',
312
+ useAgentRuntime: process.env.MARROW_AGENT_RUNTIME !== 'false',
313
+ useWorkflowGate: process.env.MARROW_WORKFLOW_GATE !== 'false',
314
+ requireOutcomeClosure: process.env.MARROW_REQUIRE_OUTCOME_CLOSURE !== 'false',
315
+ });
316
316
 
317
- runtime.install();
318
- globalThis.__MARROW_PASSIVE_RUNTIME__ = runtime;
317
+ runtime.install();
318
+ globalThis.__MARROW_PASSIVE_RUNTIME__ = runtime;
319
+ } catch {
320
+ console.warn('[Marrow] passive runtime skipped: install @getmarrow/sdk or verify SDK initialization. Run npm install @getmarrow/sdk, then rerun npx @getmarrow/install --repair.');
321
+ }
319
322
  }
320
323
  `;
321
324
  }
@@ -403,6 +406,38 @@ function upsertMcpServerConfig(filePath) {
403
406
  return JSON.stringify(config, null, 2) + '\n';
404
407
  }
405
408
 
409
+ function inspectSdkDependency(detection) {
410
+ if (!detection.node) {
411
+ return { required: false, present: false, install_command: null };
412
+ }
413
+
414
+ const raw = safeRead(detection.paths.packageJson);
415
+ let packageJson = {};
416
+ try {
417
+ packageJson = raw ? JSON.parse(raw) : {};
418
+ } catch {
419
+ return {
420
+ required: true,
421
+ present: false,
422
+ install_command: 'npm install @getmarrow/sdk',
423
+ warning: 'package.json could not be parsed; verify @getmarrow/sdk manually.',
424
+ };
425
+ }
426
+
427
+ const dependencyBlocks = [
428
+ packageJson.dependencies,
429
+ packageJson.devDependencies,
430
+ packageJson.optionalDependencies,
431
+ packageJson.peerDependencies,
432
+ ];
433
+ const present = dependencyBlocks.some((deps) => deps && Object.prototype.hasOwnProperty.call(deps, '@getmarrow/sdk'));
434
+ return {
435
+ required: true,
436
+ present,
437
+ install_command: present ? null : 'npm install @getmarrow/sdk',
438
+ };
439
+ }
440
+
406
441
  function buildPlan(detection, options) {
407
442
  const mode = options.mode === 'auto'
408
443
  ? detection.node && (detection.claudeCode || detection.cursor || detection.codex || detection.openclaw)
@@ -576,6 +611,7 @@ async function runSelfTest(options) {
576
611
  error: error instanceof Error ? error.message : String(error),
577
612
  }));
578
613
  const firstValueSignal = buildFirstValueSignal(status, runtime, performance);
614
+ const installValueMoment = buildInstallValueMoment(firstValueSignal, status, runtime, performance);
579
615
  return {
580
616
  skipped: false,
581
617
  decision_id: decisionId,
@@ -589,6 +625,7 @@ async function runSelfTest(options) {
589
625
  runtime_exact_next_action: runtime.exact_next_action || null,
590
626
  runtime_before_you_act: runtime.before_you_act || null,
591
627
  first_value_signal: firstValueSignal,
628
+ install_value_moment: installValueMoment,
592
629
  performance_proof: performance && performance.ok !== false ? {
593
630
  avoided_mistakes: performance.avoided_mistakes ?? performance.avoided_repeated_mistakes ?? 0,
594
631
  reused_winning_decisions: performance.reused_winning_decisions ?? 0,
@@ -600,6 +637,31 @@ async function runSelfTest(options) {
600
637
  };
601
638
  }
602
639
 
640
+ function buildInstallValueMoment(firstValueSignal = {}, status = {}, runtime = {}, performance = {}) {
641
+ const proof = firstValueSignal.value_proof || [];
642
+ const hasFleetSignal = proof.length > 0;
643
+ const runtimeLesson = runtime.before_you_act
644
+ || runtime.before_you_act_injection?.message
645
+ || runtime.exact_next_action
646
+ || firstValueSignal.first_lesson;
647
+
648
+ return {
649
+ headline: 'Your agent is no longer starting from zero.',
650
+ proof: [
651
+ 'Captured this setup decision',
652
+ 'Closed the outcome successfully',
653
+ 'Runtime gate is ' + (firstValueSignal.active ? 'active' : 'installed'),
654
+ runtimeLesson ? 'Future risky work now gets a pre-action brief' : 'Future risky work now gets checked before action',
655
+ ],
656
+ fleet_signal: hasFleetSignal
657
+ ? 'Marrow already found signal: ' + proof.join('; ') + '.'
658
+ : 'Fresh account: Marrow will start building fleet memory from this first captured outcome.',
659
+ try_this_now: 'Ask your agent: "I am about to deploy to production. What should I check first?"',
660
+ expected_response: 'Marrow should answer with a risk gate, required proof, and any matching fleet lessons before the agent acts.',
661
+ first_lesson: runtimeLesson || 'Marrow will surface prior lessons before risky or repeated work.',
662
+ };
663
+ }
664
+
603
665
  function buildFirstValueSignal(status, runtime, performance) {
604
666
  const capture = status.capture_coverage || {};
605
667
  const closure = status.auto_outcome_closure || {};
@@ -664,12 +726,22 @@ function printReport(report) {
664
726
  if (report.selfTest.next_action) process.stdout.write(`- next action: ${report.selfTest.next_action}\n`);
665
727
  if (report.selfTest.first_value_signal) {
666
728
  process.stdout.write('\nFirst value:\n');
667
- process.stdout.write(`- ${report.selfTest.first_value_signal.headline}\n`);
668
- process.stdout.write(`- First useful lesson: ${report.selfTest.first_value_signal.first_lesson}\n`);
669
- if (report.selfTest.first_value_signal.value_proof.length) {
670
- process.stdout.write(`- Proof: ${report.selfTest.first_value_signal.value_proof.join('; ')}\n`);
729
+ const valueMoment = report.selfTest.install_value_moment;
730
+ if (valueMoment) {
731
+ process.stdout.write(`- ${valueMoment.headline}\n`);
732
+ process.stdout.write('- First proof:\n');
733
+ for (const proof of valueMoment.proof) process.stdout.write(` - ${proof}\n`);
734
+ process.stdout.write(`- ${valueMoment.fleet_signal}\n`);
735
+ process.stdout.write(`- Try this now: ${valueMoment.try_this_now}\n`);
736
+ process.stdout.write(`- Expected: ${valueMoment.expected_response}\n`);
737
+ } else {
738
+ process.stdout.write(`- ${report.selfTest.first_value_signal.headline}\n`);
739
+ process.stdout.write(`- First useful lesson: ${report.selfTest.first_value_signal.first_lesson}\n`);
740
+ if (report.selfTest.first_value_signal.value_proof.length) {
741
+ process.stdout.write(`- Proof: ${report.selfTest.first_value_signal.value_proof.join('; ')}\n`);
742
+ }
743
+ process.stdout.write(`- Next: ${report.selfTest.first_value_signal.next_action}\n`);
671
744
  }
672
- process.stdout.write(`- Next: ${report.selfTest.first_value_signal.next_action}\n`);
673
745
  }
674
746
  }
675
747
 
@@ -697,6 +769,13 @@ function printReport(report) {
697
769
  }
698
770
  }
699
771
 
772
+ if (report.sdkDependency?.required) {
773
+ process.stdout.write('\nSDK dependency:\n');
774
+ process.stdout.write(`- @getmarrow/sdk: ${report.sdkDependency.present ? 'present' : 'missing'}\n`);
775
+ if (report.sdkDependency.install_command) process.stdout.write(`- exact fix: ${report.sdkDependency.install_command}\n`);
776
+ if (report.sdkDependency.warning) process.stdout.write(`- warning: ${report.sdkDependency.warning}\n`);
777
+ }
778
+
700
779
  if (report.writeMode === 'doctor') {
701
780
  process.stdout.write('\nDoctor:\n');
702
781
  process.stdout.write(`- Marrow active: ${report.doctor.active ? 'yes' : 'no'}\n`);
@@ -724,6 +803,7 @@ async function install(options) {
724
803
  const writeMode = options.doctor ? 'doctor' : options.dryRun ? 'dry-run' : options.repair ? 'repair' : options.yes ? 'write' : 'dry-run';
725
804
  const changes = applyPlan(plan, options);
726
805
  const configInspection = inspectNpmTokenConfig();
806
+ const sdkDependency = inspectSdkDependency(detection);
727
807
  const configDiagnostics = configInspection.safe;
728
808
  const configRepairs = options.repair && !options.dryRun && !options.doctor
729
809
  ? repairConfigDiagnostics(configDiagnostics)
@@ -779,6 +859,7 @@ async function install(options) {
779
859
  remediation,
780
860
  configDiagnostics,
781
861
  configRepairs,
862
+ sdkDependency,
782
863
  selfTest,
783
864
  warnings: options.keyFromArg
784
865
  ? ['Avoid --key in shared shells because command-line arguments can be visible in process listings. Prefer MARROW_API_KEY in your environment or secret manager.']
@@ -810,4 +891,6 @@ module.exports = {
810
891
  runCli,
811
892
  passiveRuntimeSource,
812
893
  inspectNpmTokenConfig,
894
+ inspectSdkDependency,
895
+ buildInstallValueMoment,
813
896
  };