@getmarrow/install 0.1.45 → 0.1.47
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 +22 -1
- package/package.json +1 -1
- package/src/first-hour.js +73 -0
- package/src/installer.js +76 -13
package/README.md
CHANGED
|
@@ -91,7 +91,28 @@ npx @getmarrow/install controller stop
|
|
|
91
91
|
|
|
92
92
|
Persistent controller lifecycle is currently Linux-only. On macOS or Windows, activation still installs and verifies the supported hooks without starting or signaling a background process; run `npx @getmarrow/install sidecar` under an owner-managed service and pass `--no-controller`. The controller does not silently upgrade packages, change governance policy, rotate credentials, or modify unrelated project configuration.
|
|
93
93
|
|
|
94
|
-
## What's New in v0.1.
|
|
94
|
+
## What's New in v0.1.47
|
|
95
|
+
|
|
96
|
+
v0.1.47 makes activate honest about reload and the first capture path:
|
|
97
|
+
|
|
98
|
+
- after writing MCP or hooks, activate reports that this process is not live until harness restart and `doctor --self-test`;
|
|
99
|
+
- first capture is Claude native hooks, Cursor on-demand `marrow_agent_runtime`, or the Codex/Grok governed runner;
|
|
100
|
+
- generated MCP setup, launch, and certified hook commands pin current MCP `3.9.65` from source `a314794b606c30cd750f01c672eab9b2c42e9862`;
|
|
101
|
+
- SDK detection and operator-approved upgrade rules pin exact public `3.7.60`;
|
|
102
|
+
- empty token savings stay zero until observed model usage lands.
|
|
103
|
+
|
|
104
|
+
## Previous: v0.1.46
|
|
105
|
+
|
|
106
|
+
v0.1.46 makes default install cover every workspace honestly:
|
|
107
|
+
|
|
108
|
+
- auto mode now writes MCP plus agent instructions in every project, and the SDK passive runtime whenever Node is present;
|
|
109
|
+
- Claude native hooks still install only when `.claude` is present; detected Cursor workspaces also get `.cursor/mcp.json`;
|
|
110
|
+
- Hermes, OpenClaw, and custom hosts stay event-contract only and are not claimed as native interception;
|
|
111
|
+
- generated MCP setup, launch, and certified hook commands pin current MCP `3.9.64` from source `ed8293165247e89161045c7fbf68aeee4d51c6da`;
|
|
112
|
+
- SDK detection and operator-approved upgrade rules pin exact public `3.7.59`;
|
|
113
|
+
- empty token savings stay zero until observed model usage lands.
|
|
114
|
+
|
|
115
|
+
## Previous: v0.1.45
|
|
95
116
|
|
|
96
117
|
v0.1.45 pins the one-command setup path to the published receipt-safe MCP release:
|
|
97
118
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function wroteHarnessConfig(changes = []) {
|
|
2
|
+
return (changes || []).some((change) => {
|
|
3
|
+
if (!change || !(change.applied || change.changed)) return false;
|
|
4
|
+
return /MCP|hook|Claude|Cursor|Agent instructions|SDK passive/i.test(String(change.label || ''));
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function harnessReloadPlan(detection = {}, changes = []) {
|
|
9
|
+
const clients = [];
|
|
10
|
+
if (detection.claudeCode) {
|
|
11
|
+
clients.push({
|
|
12
|
+
client: 'claude-code',
|
|
13
|
+
restart: 'Restart Claude Code so native hooks and MCP load.',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
if (detection.cursor) {
|
|
17
|
+
clients.push({
|
|
18
|
+
client: 'cursor',
|
|
19
|
+
restart: 'Restart Cursor so project MCP loads.',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (detection.codex) {
|
|
23
|
+
clients.push({
|
|
24
|
+
client: 'codex',
|
|
25
|
+
restart: 'Start a new Codex or Grok session so AGENTS.md and MCP config load.',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (clients.length === 0) {
|
|
29
|
+
clients.push({
|
|
30
|
+
client: 'mcp',
|
|
31
|
+
restart: 'Restart the owning MCP host so marrow-mcp loads.',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const required = wroteHarnessConfig(changes);
|
|
35
|
+
return {
|
|
36
|
+
required,
|
|
37
|
+
live_in_this_process: !required,
|
|
38
|
+
prove_command: 'npx @getmarrow/install@latest doctor --self-test',
|
|
39
|
+
clients,
|
|
40
|
+
instruction: clients.map((entry) => entry.restart).join(' '),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function firstCapturePath(detection = {}, agentId) {
|
|
45
|
+
const id = String(agentId || '').trim() || '<agent-id>';
|
|
46
|
+
if (detection.claudeCode) {
|
|
47
|
+
return {
|
|
48
|
+
client: 'claude-code',
|
|
49
|
+
capability_level: 'native_hooks',
|
|
50
|
+
command: null,
|
|
51
|
+
instruction: 'After restart, Claude native hooks capture the next prompt, tool, and session-end automatically.',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (detection.cursor) {
|
|
55
|
+
return {
|
|
56
|
+
client: 'cursor',
|
|
57
|
+
capability_level: 'mcp',
|
|
58
|
+
command: 'marrow_agent_runtime',
|
|
59
|
+
instruction: 'After restart, call marrow_agent_runtime before the next deploy, merge, or publish. Before the session ends, call marrow_session_end. Cursor MCP tools are on demand.',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
client: detection.codex ? 'codex' : 'governed_wrapper',
|
|
64
|
+
capability_level: 'governed_wrapper',
|
|
65
|
+
command: `npx @getmarrow/install run --agent ${id} -- -- <command>`,
|
|
66
|
+
instruction: 'Wrap the next deploy, merge, or publish with the governed runner. Codex and Grok do not intercept tools natively. Before the session ends, call marrow_session_end or marrow_commit. Do not invent token counts.',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
harnessReloadPlan,
|
|
72
|
+
firstCapturePath,
|
|
73
|
+
};
|
package/src/installer.js
CHANGED
|
@@ -4,15 +4,16 @@ const os = require('node:os');
|
|
|
4
4
|
const crypto = require('node:crypto');
|
|
5
5
|
const { version: INSTALLER_ADAPTER_VERSION } = require('../package.json');
|
|
6
6
|
const { controllerStatus, controllerSupportedPlatform, ensureGovernanceController } = require('./controller-manager');
|
|
7
|
+
const { firstCapturePath, harnessReloadPlan } = require('./first-hour');
|
|
7
8
|
|
|
8
9
|
const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
|
|
9
10
|
const MARROW_BLOCK_START = '<!-- marrow:passive-start -->';
|
|
10
11
|
const MARROW_BLOCK_END = '<!-- marrow:passive-end -->';
|
|
11
|
-
const MCP_ADAPTER_VERSION = '3.9.
|
|
12
|
-
const MCP_ADAPTER_SOURCE_SHA = '
|
|
13
|
-
const MCP_ADAPTER_INTEGRITY = 'sha512-
|
|
14
|
-
const SDK_ADAPTER_VERSION = '3.7.
|
|
15
|
-
const SDK_ADAPTER_INTEGRITY = 'sha512-
|
|
12
|
+
const MCP_ADAPTER_VERSION = '3.9.65';
|
|
13
|
+
const MCP_ADAPTER_SOURCE_SHA = 'a314794b606c30cd750f01c672eab9b2c42e9862';
|
|
14
|
+
const MCP_ADAPTER_INTEGRITY = 'sha512-OMsuv8qY7S3PHSEl1kJOPPAQuiCKYPtHng6Dzhq8U7FzY3eICPQgHsYwMtoBjHA+/BIBoNoLyLof7qU2sC1qOQ==';
|
|
15
|
+
const SDK_ADAPTER_VERSION = '3.7.60';
|
|
16
|
+
const SDK_ADAPTER_INTEGRITY = 'sha512-w6QeazGjfDXzw55IBMs85vb0LoMvm1JZLfDeilNm8NEq0081XN6MX574aFo10ZBiMd82GYRMY4vMdJ9FuxtXnQ==';
|
|
16
17
|
const SDK_ADAPTER_TARBALL = `https://registry.npmjs.org/@getmarrow/sdk/-/sdk-${SDK_ADAPTER_VERSION}.tgz`;
|
|
17
18
|
const MCP_PACKAGE_SPEC = `@getmarrow/mcp@${MCP_ADAPTER_VERSION}`;
|
|
18
19
|
const ADAPTER_PROVENANCE = Object.freeze({
|
|
@@ -619,10 +620,15 @@ function passiveInstructions() {
|
|
|
619
620
|
|
|
620
621
|
Marrow should run passively after install:
|
|
621
622
|
|
|
622
|
-
- Use MCP
|
|
623
|
+
- Use MCP plus these instructions in every workspace: \`npx -y --package=@getmarrow/mcp@latest marrow-mcp setup\`.
|
|
623
624
|
- Use SDK passive runtime in owned Node processes: \`createPassiveRuntime().install()\`.
|
|
624
|
-
-
|
|
625
|
+
- Native Claude hooks install only when \`.claude\` is present. Cursor, Composer, Cline, and Windsurf get MCP tools on demand. Codex, Grok, Gemini, and similar CLI harnesses use the governed wrapper. Hermes, OpenClaw, and custom hosts need a bounded event adapter.
|
|
626
|
+
- Keep passive token/model usage proof enabled. Empty savings stay zero until observed model usage lands. Do not invent token, cost, or time savings.
|
|
625
627
|
- Before risky work, use Marrow's decision brief or passive prompt hook.
|
|
628
|
+
- After activate writes MCP or hooks, restart this harness, then run \`npx @getmarrow/install@latest doctor --self-test\`. Do not claim Marrow is live in a process that has not reloaded.
|
|
629
|
+
- First turn: tell the owner the gate is live and empty savings are honest. The next deploy, merge, or publish must go through Marrow.
|
|
630
|
+
- Cursor, Composer, Cline, and Windsurf: call \`marrow_agent_runtime\` before those actions. Codex, Grok, Gemini, and similar CLIs: wrap them with \`npx @getmarrow/install run --agent <agent-id> -- -- <command>\`.
|
|
631
|
+
- Before the session ends, close open work with session-end auto-commit or \`marrow_commit\`. Record model usage only when the host response includes counts.
|
|
626
632
|
- After meaningful work, record the outcome so future agents learn from it.
|
|
627
633
|
- After Marrow blocks, warns, or requires review, use the decision trace receipt to tell the operator what changed and which recorded workflow or proof is required. Stay quiet for routine low-risk work.
|
|
628
634
|
- Check health with \`marrow_agent_status\` or \`GET /v1/agent/status\`.
|
|
@@ -1051,13 +1057,36 @@ function inspectSdkDependency(detection) {
|
|
|
1051
1057
|
};
|
|
1052
1058
|
}
|
|
1053
1059
|
|
|
1060
|
+
function defaultHarnessInstallMatrix(detection = detectEnvironment(process.cwd())) {
|
|
1061
|
+
const node = Boolean(detection.node);
|
|
1062
|
+
return HARNESS_CAPABILITY_REGISTRY.map((entry) => {
|
|
1063
|
+
const detected = detectedClient(detection) === entry.client
|
|
1064
|
+
|| (entry.client === 'claude-code' && detection.claudeCode)
|
|
1065
|
+
|| (entry.client === 'cursor' && detection.cursor)
|
|
1066
|
+
|| (entry.client === 'codex' && detection.codex);
|
|
1067
|
+
return {
|
|
1068
|
+
client: entry.client,
|
|
1069
|
+
capability_level: entry.capability_level,
|
|
1070
|
+
automatic: entry.automatic,
|
|
1071
|
+
install_surface: entry.install_surface,
|
|
1072
|
+
default_install: {
|
|
1073
|
+
mcp: true,
|
|
1074
|
+
instructions: true,
|
|
1075
|
+
sdk_passive_runtime: node,
|
|
1076
|
+
native_hooks: entry.capability_level === 'native_hooks' && Boolean(detection.claudeCode),
|
|
1077
|
+
governed_wrapper: entry.capability_level === 'governed_wrapper',
|
|
1078
|
+
},
|
|
1079
|
+
verified_passive: detected && entry.automatic.length > 0,
|
|
1080
|
+
unsupported_claim: entry.capability_level === 'event_contract'
|
|
1081
|
+
? 'Needs a bounded event adapter. MCP tools remain on demand.'
|
|
1082
|
+
: null,
|
|
1083
|
+
};
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1054
1087
|
function buildPlan(detection, options) {
|
|
1055
1088
|
const mode = options.mode === 'auto'
|
|
1056
|
-
? detection.node
|
|
1057
|
-
? 'both'
|
|
1058
|
-
: detection.node
|
|
1059
|
-
? 'sdk'
|
|
1060
|
-
: 'mcp'
|
|
1089
|
+
? detection.node ? 'both' : 'mcp'
|
|
1061
1090
|
: options.mode;
|
|
1062
1091
|
const writes = [];
|
|
1063
1092
|
|
|
@@ -1092,6 +1121,14 @@ function buildPlan(detection, options) {
|
|
|
1092
1121
|
label: 'Project MCP server config',
|
|
1093
1122
|
transform: upsertMcpServerConfig,
|
|
1094
1123
|
});
|
|
1124
|
+
if (detection.cursor) {
|
|
1125
|
+
writes.push({
|
|
1126
|
+
type: 'json-transform',
|
|
1127
|
+
path: detection.paths.cursorMcp,
|
|
1128
|
+
label: 'Cursor MCP server config',
|
|
1129
|
+
transform: upsertMcpServerConfig,
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1095
1132
|
}
|
|
1096
1133
|
|
|
1097
1134
|
if (mode === 'md' || mode === 'both' || mode === 'mcp') {
|
|
@@ -1675,6 +1712,21 @@ function printReport(report) {
|
|
|
1675
1712
|
}
|
|
1676
1713
|
}
|
|
1677
1714
|
|
|
1715
|
+
if (report.harnessReload) {
|
|
1716
|
+
process.stdout.write('\nHarness reload:\n');
|
|
1717
|
+
process.stdout.write(`- required: ${report.harnessReload.required ? 'yes' : 'no'}\n`);
|
|
1718
|
+
process.stdout.write(`- live in this process: ${report.harnessReload.live_in_this_process ? 'yes' : 'no'}\n`);
|
|
1719
|
+
if (report.harnessReload.instruction) process.stdout.write(`- restart: ${report.harnessReload.instruction}\n`);
|
|
1720
|
+
if (report.harnessReload.prove_command) process.stdout.write(`- prove after restart: ${report.harnessReload.prove_command}\n`);
|
|
1721
|
+
}
|
|
1722
|
+
if (report.firstCapture) {
|
|
1723
|
+
process.stdout.write('\nFirst capture:\n');
|
|
1724
|
+
process.stdout.write(`- client: ${report.firstCapture.client}\n`);
|
|
1725
|
+
process.stdout.write(`- capability: ${report.firstCapture.capability_level}\n`);
|
|
1726
|
+
if (report.firstCapture.command) process.stdout.write(`- command: ${report.firstCapture.command}\n`);
|
|
1727
|
+
process.stdout.write(`- ${report.firstCapture.instruction}\n`);
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1678
1730
|
if (report.remediation) {
|
|
1679
1731
|
process.stdout.write('\nRemediation:\n');
|
|
1680
1732
|
process.stdout.write(`- attempted: ${report.remediation.attempted ? 'yes' : 'no'}\n`);
|
|
@@ -1712,8 +1764,14 @@ function printReport(report) {
|
|
|
1712
1764
|
if (report.controller?.exact_fix) process.stdout.write(`- exact fix: ${report.controller.exact_fix}\n`);
|
|
1713
1765
|
|
|
1714
1766
|
if (report.writeMode === 'doctor') {
|
|
1767
|
+
const liveHere = !report.harnessReload?.required;
|
|
1768
|
+
const activeLabel = report.doctor.active && liveHere
|
|
1769
|
+
? 'yes'
|
|
1770
|
+
: report.doctor.active
|
|
1771
|
+
? 'server confirmed, restart required'
|
|
1772
|
+
: 'no';
|
|
1715
1773
|
process.stdout.write('\nDoctor:\n');
|
|
1716
|
-
process.stdout.write(`- Marrow active: ${
|
|
1774
|
+
process.stdout.write(`- Marrow active: ${activeLabel}\n`);
|
|
1717
1775
|
process.stdout.write(`- missing env: ${report.doctor.missingEnv.length ? report.doctor.missingEnv.join(', ') : 'none'}\n`);
|
|
1718
1776
|
if (report.doctor.envHints.length) process.stdout.write(`- possible env files: ${report.doctor.envHints.join(', ')}\n`);
|
|
1719
1777
|
process.stdout.write(`- missing hooks/config: ${report.doctor.missingHooks.length ? report.doctor.missingHooks.join('; ') : 'none'}\n`);
|
|
@@ -1877,6 +1935,8 @@ async function install(options) {
|
|
|
1877
1935
|
receipt: selfTest.activation_receipt || null,
|
|
1878
1936
|
profile,
|
|
1879
1937
|
},
|
|
1938
|
+
harnessReload: harnessReloadPlan(detection, changes),
|
|
1939
|
+
firstCapture: firstCapturePath(detection, options.agentId),
|
|
1880
1940
|
changes,
|
|
1881
1941
|
doctor: {
|
|
1882
1942
|
active: Boolean(!selfTest.skipped && selfTest.active),
|
|
@@ -1947,4 +2007,7 @@ module.exports = {
|
|
|
1947
2007
|
printReport,
|
|
1948
2008
|
ADAPTER_PROVENANCE,
|
|
1949
2009
|
HARNESS_CAPABILITY_REGISTRY,
|
|
2010
|
+
defaultHarnessInstallMatrix,
|
|
2011
|
+
harnessReloadPlan,
|
|
2012
|
+
firstCapturePath,
|
|
1950
2013
|
};
|