@getmarrow/install 0.1.6 → 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.
- package/README.md +30 -8
- package/bin/marrow-install.js +9 -0
- package/package.json +1 -1
- 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.
|
|
14
|
+
## What's New in v0.1.8
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
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`
|
|
36
|
-
- The installer prints
|
|
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.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { runCli } = require('../src/installer');
|
|
4
|
+
|
|
5
|
+
runCli(process.argv.slice(2)).catch((error) => {
|
|
6
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7
|
+
process.stderr.write(`marrow-install failed: ${message}\n`);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
});
|
package/package.json
CHANGED
package/src/installer.js
CHANGED
|
@@ -295,27 +295,30 @@ ${MARROW_BLOCK_END}`;
|
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
function passiveRuntimeSource() {
|
|
298
|
-
return `
|
|
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
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
-
|
|
318
|
-
|
|
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
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
process.stdout.write(
|
|
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
|
};
|