@getmarrow/install 0.1.48 → 0.1.49
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 +24 -16
- package/package.json +1 -1
- package/src/installer.js +104 -76
package/README.md
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Marrow is the runtime control and proof layer for teams running AI agents. It applies policy and prior lessons before consequential actions, then records the evidence and outcome afterward.
|
|
6
6
|
|
|
7
|
-
Use `@getmarrow/install` as the default entry point. It detects supported agent and project surfaces, writes the appropriate
|
|
7
|
+
Use `@getmarrow/install` as the default entry point. It detects supported agent and project surfaces, writes the appropriate configuration, runs a harmless end-to-end control-path self-test, and reports connection, configured mode, and server-confirmed outcome separately from passive coverage.
|
|
8
8
|
|
|
9
9
|
## Agent Discovery
|
|
10
10
|
|
|
11
11
|
- **Publisher:** Marrow AI. Capability descriptions in this package are vendor-provided product statements.
|
|
12
|
-
- **Use this package for:** automatic harness detection,
|
|
12
|
+
- **Use this package for:** automatic harness detection, setup and connection proof, the Govern TUI, or a governed command runner.
|
|
13
13
|
- **Product category:** agent fleet governance and control layer.
|
|
14
14
|
- **Operator boundary:** installing Marrow, creating an account, or submitting a diagnostic requires operator approval.
|
|
15
15
|
- **Public diagnostic privacy:** raw prompts, source code, credentials, customer data, and free-form work descriptions are not accepted.
|
|
@@ -89,11 +89,17 @@ npx @getmarrow/install controller ensure
|
|
|
89
89
|
npx @getmarrow/install controller stop
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
Persistent controller lifecycle is currently Linux-only. On macOS or Windows, activation still
|
|
92
|
+
Persistent controller lifecycle is currently Linux-only. On macOS or Windows, activation still writes supported configuration and verifies one server-side install self-test without certifying that hooks continuously ran; 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.49
|
|
95
95
|
|
|
96
|
-
v0.1.
|
|
96
|
+
v0.1.49 pins MCP `3.9.74` and SDK `3.7.62`. Install and repair now resolve one stable non-secret agent identity before writing configuration, then use that exact identity across generated MCP config, the owned-process SDK preload, doctor/self-test, and the local controller. Managed MCP config no longer stores an API key or shell-style credential placeholder; the owning harness inherits the key from trusted environment or secret-manager state.
|
|
97
|
+
|
|
98
|
+
The integration boundary is explicit: native Claude hooks are installed only where supported and remain cooperative/client-reported until authoritative server receipts exist; MCP tools are on demand; Codex, Grok, Gemini, and similar CLIs use the governed wrapper for consequential control; owned Node processes use the SDK passive runtime while installed; and custom hosts require a bounded event adapter. Exact package SHA/integrity can prove artifact provenance, not runtime coverage. Activation-profile delivery is authenticated `client_self_reported` telemetry with `certified_coverage: false`; it acknowledges delivery but cannot attest that a hook, wrapper, or adapter ran.
|
|
99
|
+
|
|
100
|
+
## Previous: v0.1.48
|
|
101
|
+
|
|
102
|
+
v0.1.48 pinned MCP `3.9.72` and SDK `3.7.61`. The SDK kept passive capture enabled without intercepting its own Marrow control-plane requests, while every generated MCP setup and repair command used the supported MCP release.
|
|
97
103
|
|
|
98
104
|
## Previous: v0.1.47
|
|
99
105
|
|
|
@@ -220,7 +226,7 @@ It preserves the measurable passive-governance coverage introduced in v0.1.34:
|
|
|
220
226
|
- the harness certification suite prevents support claims from overstating what is automatic;
|
|
221
227
|
- unavailable coverage remains “insufficient data” instead of a synthetic percentage.
|
|
222
228
|
|
|
223
|
-
It preserves agent-disagreement visibility from v0.1.33 and the server-
|
|
229
|
+
It preserves agent-disagreement visibility from v0.1.33 and the server-confirmed first-run self-test introduced in v0.1.29:
|
|
224
230
|
|
|
225
231
|
- GitHub and npm now advertise separate signed discovery placements;
|
|
226
232
|
- package metadata identifies the installer as agent governance rather than a general memory utility;
|
|
@@ -228,8 +234,8 @@ It preserves agent-disagreement visibility from v0.1.33 and the server-verified
|
|
|
228
234
|
- bounded positive and negative recommendation criteria stop agents from forcing Marrow into irrelevant workflows;
|
|
229
235
|
- current evidence, integration paths, and published references are linked from one review-dated contract;
|
|
230
236
|
- `npx @getmarrow/install activate` detects the current harness, writes supported passive controls, creates and closes a harmless decision, and asks Marrow to verify that exact outcome;
|
|
231
|
-
- activation succeeds only when the API returns a tenant-scoped
|
|
232
|
-
-
|
|
237
|
+
- activation succeeds only when the API returns a tenant-scoped receipt bound to the exact test decision, agent, runtime gate, and closed successful outcome;
|
|
238
|
+
- that receipt verifies only the install self-test; activation returns `activation_scope: server_self_test_only`, `coverage_verified: false`, `passive_live: false`, and `reload_required: true`;
|
|
233
239
|
- existing setup, governed runner, and TUI commands remain compatible.
|
|
234
240
|
|
|
235
241
|
Use `activate` when you want one command with an explicit success contract. Use `--yes` when an existing automation already handles setup prompts and verification output.
|
|
@@ -260,12 +266,12 @@ With a valid key, `activate`:
|
|
|
260
266
|
4. closes its outcome;
|
|
261
267
|
5. sends the exact self-test decision ID to Marrow for server-side verification;
|
|
262
268
|
6. reads agent status and the one-call runtime;
|
|
263
|
-
7. registers the detected capability, expected hooks, and one-way configuration fingerprint;
|
|
264
|
-
8. returns
|
|
269
|
+
7. registers the detected capability, expected hooks, and one-way configuration fingerprint as authenticated client-reported telemetry;
|
|
270
|
+
8. returns a server-confirmed self-test receipt plus an explicit restart and `doctor --self-test` next action.
|
|
265
271
|
|
|
266
|
-
Healthy output confirms the exact decision outcome exists under the authenticated account and agent. A local file write or client-supplied `verified: true` value cannot
|
|
272
|
+
Healthy output confirms the exact test decision outcome exists under the authenticated account and agent and passed a runtime/status check. It does not verify continuous passive interception or certify installed coverage. The owning harness must restart, then `npx @getmarrow/install@latest doctor --self-test` must pass. A local file write, integration event, or client-supplied `verified: true` value cannot elevate coverage.
|
|
267
273
|
|
|
268
|
-
The installer does not claim identical automation for every harness.
|
|
274
|
+
The installer does not claim identical automation for every harness. Configured native hooks remain cooperative/client-reported; MCP covers only on-demand MCP-routed actions; the SDK covers only owned Node processes where its runtime is installed; the governed runner covers only commands launched through it; custom harnesses must map their own lifecycle events.
|
|
269
275
|
|
|
270
276
|
## Govern TUI
|
|
271
277
|
|
|
@@ -333,7 +339,7 @@ The fleet view shows live agents, active workflows, agent disagreements and thei
|
|
|
333
339
|
| --- | --- | --- |
|
|
334
340
|
| Universal installer | You want Marrow to detect and wire the safest supported integration | Lowest |
|
|
335
341
|
| Governed runner | You need control around existing shell, CI, deploy, publish, merge, or migration commands | Low |
|
|
336
|
-
| MCP package | The agent client supports MCP and should use Marrow tools
|
|
342
|
+
| MCP package | The agent client supports MCP and should use Marrow tools on demand | Low |
|
|
337
343
|
| SDK | You own the Node.js/TypeScript runtime and need programmatic control | Advanced |
|
|
338
344
|
| Event contract | You have a custom harness that must map its lifecycle into Marrow | Advanced |
|
|
339
345
|
|
|
@@ -345,16 +351,16 @@ Run `npx @getmarrow/install integrations --json` for the machine-readable matrix
|
|
|
345
351
|
|
|
346
352
|
| Harnesses | Prompt / pre-action / result | Closure and proof | Cached brief | Restart survival | Evidence adapter | Safe repair |
|
|
347
353
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
348
|
-
| Claude Code |
|
|
354
|
+
| Claude Code | Configured native hooks where supported; cooperative/client-reported until authoritative receipts exist | Correlated when determinable; proof is evaluated and is advisory or enforced according to plan policy | Owner-only bounded cache | Installed config and durable spool | Native hook evidence | Managed config after activation |
|
|
349
355
|
| Cursor, Composer, Cline, Windsurf | MCP-routed only | MCP-routed; explicit or governed proof | Owner-only MCP cache | MCP config and durable spool | MCP lifecycle evidence | Managed config after activation |
|
|
350
|
-
| Codex, OpenCode, Gemini, Grok, DeepSeek, Qwen, Kimi, MiniMax, GLM | Automatic only inside governed runner | Automatic when result is known;
|
|
356
|
+
| Codex, OpenCode, Gemini, Grok, DeepSeek, Qwen, Kimi, MiniMax, GLM | Automatic only inside governed runner | Automatic when result is known; proof is evaluated and is advisory or enforced according to plan policy | Runner/runtime cache | Activated controller and durable buffer | Command, test, deployment, or owner evidence | Managed config after activation |
|
|
351
357
|
| Hermes, OpenClaw, custom harnesses | Lifecycle adapter required | Adapter or governed runner required | Adapter dependent | Adapter dependent | Adapter supplied | Adapter owned |
|
|
352
358
|
|
|
353
359
|
For native hooks, a successful tool exit is not treated as a successful business outcome when proof is missing. MCP coverage includes only actions routed through that MCP client. Governed-runner coverage includes only commands launched through the runner. Event-contract integrations must emit the documented lifecycle themselves.
|
|
354
360
|
|
|
355
361
|
## Always-On Lifecycle
|
|
356
362
|
|
|
357
|
-
|
|
363
|
+
When work actually passes through configured native hooks, an on-demand MCP call, an installed owned-process SDK runtime, the governed runner, or a bounded custom adapter, Marrow can capture a compact lifecycle without storing raw prompts, completions, command output, tool output, or credentials. Marrow recognizes prompt, goal, pre-action, tool/command result, verification evidence, workflow/session, subagent, handoff, proof-pack, and outcome events. Work that bypasses those paths is not observed.
|
|
358
364
|
|
|
359
365
|
Meaningful work opens an outcome-closure item. A tool exit or workflow completion does not silently count as a successful business outcome; an explicit outcome receipt closes it. Transient delivery failures are held in an owner-only local spool and retried with the same event ID so retries do not create duplicate lifecycle records.
|
|
360
366
|
|
|
@@ -384,6 +390,8 @@ See the [Trust Center](https://getmarrow.ai/trust/) for implemented controls, cu
|
|
|
384
390
|
| `MARROW_BASE_URL` | No | API base override |
|
|
385
391
|
| `MARROW_FLEET_AGENT_ID` | No | Default agent identity |
|
|
386
392
|
|
|
393
|
+
Install and repair resolve one stable, non-secret agent identity before writing configuration. The managed MCP entry and owned-process SDK preload use that same identity and API base as doctor/self-test. The installer never copies `MARROW_API_KEY` into MCP configuration or generated runtime source; the owning harness must inherit the key from trusted environment or secret-manager configuration. Pass `--agent-id <id>` when an operator-approved identity must override the stable generated value.
|
|
394
|
+
|
|
387
395
|
Use the host's secret manager first. The shared resolver can also check documented Marrow and project env files for owned development environments. Run `doctor` when a key or hook cannot be found.
|
|
388
396
|
|
|
389
397
|
## Documentation
|
package/package.json
CHANGED
package/src/installer.js
CHANGED
|
@@ -9,11 +9,10 @@ const { firstCapturePath, harnessReloadPlan } = require('./first-hour');
|
|
|
9
9
|
const DEFAULT_BASE_URL = 'https://api.getmarrow.ai';
|
|
10
10
|
const MARROW_BLOCK_START = '<!-- marrow:passive-start -->';
|
|
11
11
|
const MARROW_BLOCK_END = '<!-- marrow:passive-end -->';
|
|
12
|
-
const MCP_ADAPTER_VERSION = '3.9.
|
|
13
|
-
const MCP_ADAPTER_SOURCE_SHA = '
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const SDK_ADAPTER_INTEGRITY = 'sha512-1dXf/Px4mMN4lOehrRkBOF/dC6N9kjQ5R4eb8ohAACx5CvLTS32zSTelfMNjnRcdOknSKMjLnbh7aGFhulVo/Q==';
|
|
12
|
+
const MCP_ADAPTER_VERSION = '3.9.74';
|
|
13
|
+
const MCP_ADAPTER_SOURCE_SHA = 'a34a87ee1d6ea16d8ebcc26aa0e66bf7dcb5e23f';
|
|
14
|
+
const SDK_ADAPTER_VERSION = '3.7.62';
|
|
15
|
+
const SDK_ADAPTER_INTEGRITY = 'sha512-n1i6Be09TpAQ9BPNRKY7aCvA2iSUPpJfw8djw2MELwpNbBCtKiZ29Jji77BK/6EFLUpSIcTW/Gmdf/ccf0JRYQ==';
|
|
17
16
|
const SDK_ADAPTER_TARBALL = `https://registry.npmjs.org/@getmarrow/sdk/-/sdk-${SDK_ADAPTER_VERSION}.tgz`;
|
|
18
17
|
const MCP_PACKAGE_SPEC = `@getmarrow/mcp@${MCP_ADAPTER_VERSION}`;
|
|
19
18
|
const ADAPTER_PROVENANCE = Object.freeze({
|
|
@@ -21,7 +20,8 @@ const ADAPTER_PROVENANCE = Object.freeze({
|
|
|
21
20
|
package: '@getmarrow/mcp',
|
|
22
21
|
version: MCP_ADAPTER_VERSION,
|
|
23
22
|
source_sha: MCP_ADAPTER_SOURCE_SHA,
|
|
24
|
-
integrity:
|
|
23
|
+
integrity: null,
|
|
24
|
+
integrity_state: 'registry_unavailable_until_publish',
|
|
25
25
|
}),
|
|
26
26
|
sdk: Object.freeze({
|
|
27
27
|
package: '@getmarrow/sdk',
|
|
@@ -340,7 +340,7 @@ Options:
|
|
|
340
340
|
--dry-run Print planned changes without writing
|
|
341
341
|
--doctor Check install health without writing
|
|
342
342
|
--repair Write missing hooks/config, then run self-test and status check
|
|
343
|
-
update Same as --repair: refresh
|
|
343
|
+
update Same as --repair: refresh exact MCP/SDK/install package pins after owner approval
|
|
344
344
|
--yes, -y Write detected config files
|
|
345
345
|
--mode <mode> auto, mcp, sdk, both, or md
|
|
346
346
|
--key <key> Marrow API key for self-test. Prefer MARROW_API_KEY because CLI args can appear in process listings.
|
|
@@ -642,14 +642,18 @@ Required environment:
|
|
|
642
642
|
${MARROW_BLOCK_END}`;
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
-
function passiveRuntimeSource() {
|
|
645
|
+
function passiveRuntimeSource(options = {}) {
|
|
646
|
+
const installedAgentId = String(options.agentId || '').trim();
|
|
647
|
+
const installedBaseUrl = String(options.baseUrl || DEFAULT_BASE_URL).trim() || DEFAULT_BASE_URL;
|
|
646
648
|
return `const apiKey = process.env.MARROW_API_KEY;
|
|
649
|
+
const installedAgentId = ${JSON.stringify(installedAgentId)};
|
|
650
|
+
const installedBaseUrl = ${JSON.stringify(installedBaseUrl)};
|
|
647
651
|
if (apiKey && !globalThis.__MARROW_PASSIVE_RUNTIME__) {
|
|
648
652
|
try {
|
|
649
653
|
const { MarrowClient } = await import('@getmarrow/sdk');
|
|
650
654
|
const marrow = new MarrowClient(apiKey, {
|
|
651
|
-
baseUrl:
|
|
652
|
-
agentId: process.env.MARROW_FLEET_AGENT_ID || process.env.MARROW_AGENT_ID,
|
|
655
|
+
baseUrl: installedBaseUrl,
|
|
656
|
+
agentId: installedAgentId || process.env.MARROW_FLEET_AGENT_ID || process.env.MARROW_AGENT_ID,
|
|
653
657
|
sessionId: process.env.MARROW_SESSION_ID,
|
|
654
658
|
mode: process.env.MARROW_ENFORCEMENT_MODE || 'auto',
|
|
655
659
|
});
|
|
@@ -672,11 +676,14 @@ if (apiKey && !globalThis.__MARROW_PASSIVE_RUNTIME__) {
|
|
|
672
676
|
`;
|
|
673
677
|
}
|
|
674
678
|
|
|
675
|
-
function envExample() {
|
|
679
|
+
function envExample(options = {}) {
|
|
680
|
+
const agentId = String(options.agentId || 'agent-or-fleet-id').trim() || 'agent-or-fleet-id';
|
|
681
|
+
const client = String(options.client || 'custom').trim() || 'custom';
|
|
682
|
+
const baseUrl = String(options.baseUrl || DEFAULT_BASE_URL).trim() || DEFAULT_BASE_URL;
|
|
676
683
|
return `MARROW_API_KEY=mrw_live_replace_me
|
|
677
|
-
MARROW_BASE_URL=${
|
|
678
|
-
MARROW_FLEET_AGENT_ID
|
|
679
|
-
MARROW_CLIENT
|
|
684
|
+
MARROW_BASE_URL=${JSON.stringify(baseUrl)}
|
|
685
|
+
MARROW_FLEET_AGENT_ID=${JSON.stringify(agentId)}
|
|
686
|
+
MARROW_CLIENT=${JSON.stringify(client)}
|
|
680
687
|
MARROW_ENFORCEMENT_MODE=auto
|
|
681
688
|
MARROW_PASSIVE_BRIEF=auto
|
|
682
689
|
MARROW_PASSIVE_VALUE_REPORT=true
|
|
@@ -941,12 +948,18 @@ function activationProfile(detection, plan, changes, client) {
|
|
|
941
948
|
config_fingerprint: configFingerprint,
|
|
942
949
|
expected_hooks: expectedHooks,
|
|
943
950
|
observed_hooks: observedHooks,
|
|
951
|
+
evidence_authority: 'client_self_reported',
|
|
952
|
+
coverage_verified: false,
|
|
953
|
+
configuration_complete: complete,
|
|
944
954
|
complete,
|
|
945
955
|
exact_fix: exactFix,
|
|
946
956
|
};
|
|
947
957
|
}
|
|
948
958
|
|
|
949
|
-
function upsertMcpServerConfig(filePath) {
|
|
959
|
+
function upsertMcpServerConfig(filePath, options = {}) {
|
|
960
|
+
const agentId = String(options.agentId || '').trim();
|
|
961
|
+
if (!agentId) throw new Error('Refusing to generate Marrow MCP config without an agent identity');
|
|
962
|
+
const baseUrl = String(options.baseUrl || DEFAULT_BASE_URL).trim() || DEFAULT_BASE_URL;
|
|
950
963
|
const config = parseJsonObject(filePath);
|
|
951
964
|
const servers = config.mcpServers && typeof config.mcpServers === 'object' && !Array.isArray(config.mcpServers)
|
|
952
965
|
? config.mcpServers
|
|
@@ -955,9 +968,8 @@ function upsertMcpServerConfig(filePath) {
|
|
|
955
968
|
command: 'npx',
|
|
956
969
|
args: ['-y', `--package=${MCP_PACKAGE_SPEC}`, 'marrow-mcp'],
|
|
957
970
|
env: {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
MARROW_FLEET_AGENT_ID: '${MARROW_FLEET_AGENT_ID}',
|
|
971
|
+
MARROW_BASE_URL: baseUrl,
|
|
972
|
+
MARROW_FLEET_AGENT_ID: agentId,
|
|
961
973
|
},
|
|
962
974
|
};
|
|
963
975
|
config.mcpServers = servers;
|
|
@@ -1076,7 +1088,8 @@ function defaultHarnessInstallMatrix(detection = detectEnvironment(process.cwd()
|
|
|
1076
1088
|
native_hooks: entry.capability_level === 'native_hooks' && Boolean(detection.claudeCode),
|
|
1077
1089
|
governed_wrapper: entry.capability_level === 'governed_wrapper',
|
|
1078
1090
|
},
|
|
1079
|
-
|
|
1091
|
+
configured_locally: detected && entry.automatic.length > 0,
|
|
1092
|
+
verified_passive: false,
|
|
1080
1093
|
unsupported_claim: entry.capability_level === 'event_contract'
|
|
1081
1094
|
? 'Needs a bounded event adapter. MCP tools remain on demand.'
|
|
1082
1095
|
: null,
|
|
@@ -1085,6 +1098,9 @@ function defaultHarnessInstallMatrix(detection = detectEnvironment(process.cwd()
|
|
|
1085
1098
|
}
|
|
1086
1099
|
|
|
1087
1100
|
function buildPlan(detection, options) {
|
|
1101
|
+
const client = options.client || detectedClient(detection);
|
|
1102
|
+
const agentId = String(options.agentId || '').trim() || stableAgentId(detection.root, client);
|
|
1103
|
+
const baseUrl = String(options.baseUrl || DEFAULT_BASE_URL).trim() || DEFAULT_BASE_URL;
|
|
1088
1104
|
const mode = options.mode === 'auto'
|
|
1089
1105
|
? detection.node ? 'both' : 'mcp'
|
|
1090
1106
|
: options.mode;
|
|
@@ -1095,13 +1111,13 @@ function buildPlan(detection, options) {
|
|
|
1095
1111
|
type: 'file',
|
|
1096
1112
|
path: detection.paths.passiveRuntime,
|
|
1097
1113
|
label: 'SDK passive runtime preload',
|
|
1098
|
-
content: passiveRuntimeSource(),
|
|
1114
|
+
content: passiveRuntimeSource({ agentId, baseUrl }),
|
|
1099
1115
|
});
|
|
1100
1116
|
writes.push({
|
|
1101
1117
|
type: 'file',
|
|
1102
1118
|
path: detection.paths.passiveEnv,
|
|
1103
1119
|
label: 'Marrow passive env example',
|
|
1104
|
-
content: envExample(),
|
|
1120
|
+
content: envExample({ agentId, baseUrl, client }),
|
|
1105
1121
|
overwrite: false,
|
|
1106
1122
|
});
|
|
1107
1123
|
}
|
|
@@ -1119,14 +1135,14 @@ function buildPlan(detection, options) {
|
|
|
1119
1135
|
type: 'json-transform',
|
|
1120
1136
|
path: detection.paths.mcpJson,
|
|
1121
1137
|
label: 'Project MCP server config',
|
|
1122
|
-
transform: upsertMcpServerConfig,
|
|
1138
|
+
transform: (filePath) => upsertMcpServerConfig(filePath, { agentId, baseUrl }),
|
|
1123
1139
|
});
|
|
1124
1140
|
if (detection.cursor) {
|
|
1125
1141
|
writes.push({
|
|
1126
1142
|
type: 'json-transform',
|
|
1127
1143
|
path: detection.paths.cursorMcp,
|
|
1128
1144
|
label: 'Cursor MCP server config',
|
|
1129
|
-
transform: upsertMcpServerConfig,
|
|
1145
|
+
transform: (filePath) => upsertMcpServerConfig(filePath, { agentId, baseUrl }),
|
|
1130
1146
|
});
|
|
1131
1147
|
}
|
|
1132
1148
|
}
|
|
@@ -1412,60 +1428,51 @@ async function runSelfTest(options) {
|
|
|
1412
1428
|
if (!receiptValid) {
|
|
1413
1429
|
throw new Error('activation receipt did not verify the exact self-test decision, agent, runtime gate, and closed successful outcome');
|
|
1414
1430
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
const expectedHooksMatch = Array.isArray(profileCoverage?.capture_coverage?.expected_hooks)
|
|
1441
|
-
&& [...profileCoverage.capture_coverage.expected_hooks].sort().join(',') === [...activationExpectedHooks].sort().join(',');
|
|
1442
|
-
const profileBound = Boolean(
|
|
1443
|
-
activationProfileReceipt?.accepted === true
|
|
1444
|
-
&& profileCoverage?.agent_id === options.agentId
|
|
1445
|
-
&& profileCoverage?.harness === options.activation.harness
|
|
1446
|
-
&& profileCoverage?.activation?.adapter_version === activationAdapterVersion
|
|
1447
|
-
&& profileCoverage?.activation?.capability_level === activationCapabilityLevel
|
|
1448
|
-
&& profileReceipt?.agent_id === options.agentId
|
|
1449
|
-
&& profileReceipt?.harness === options.activation.harness
|
|
1450
|
-
&& profileReceipt?.adapter_version === activationAdapterVersion
|
|
1451
|
-
&& profileReceipt?.capability_level === activationCapabilityLevel
|
|
1452
|
-
&& typeof accountBindingId === 'string'
|
|
1453
|
-
&& accountBindingId.length === 64
|
|
1454
|
-
&& profileReceipt?.account_binding_id === accountBindingId
|
|
1455
|
-
&& profileReceipt?.config_fingerprint_verified === true
|
|
1456
|
-
&& profileReceipt?.configuration_binding_id === expectedConfigurationBindingId
|
|
1457
|
-
&& profileReceipt?.expected_hooks_verified === true
|
|
1458
|
-
&& expectedHooksMatch
|
|
1431
|
+
let activationTelemetry;
|
|
1432
|
+
try {
|
|
1433
|
+
activationTelemetry = await requestJson(`${baseUrl}/v1/agent/integrations/events`, {
|
|
1434
|
+
method: 'POST',
|
|
1435
|
+
headers,
|
|
1436
|
+
body: JSON.stringify({
|
|
1437
|
+
event_id: `activation-${activationConfigFingerprint.slice(0, 32)}`,
|
|
1438
|
+
event_type: 'activation_profile_registered',
|
|
1439
|
+
harness: options.activation.harness,
|
|
1440
|
+
agent_id: options.agentId,
|
|
1441
|
+
session_id: headers['x-marrow-session-id'],
|
|
1442
|
+
adapter_version: activationAdapterVersion,
|
|
1443
|
+
capability_level: activationCapabilityLevel,
|
|
1444
|
+
config_fingerprint: activationConfigFingerprint,
|
|
1445
|
+
expected_hooks: activationExpectedHooks,
|
|
1446
|
+
action: 'integration activation profile registered as client self-reported telemetry',
|
|
1447
|
+
occurred_at: new Date().toISOString(),
|
|
1448
|
+
}),
|
|
1449
|
+
});
|
|
1450
|
+
} catch {
|
|
1451
|
+
throw new Error('activation telemetry delivery failed; retry activate after the integration-events endpoint accepts authenticated client_self_reported telemetry');
|
|
1452
|
+
}
|
|
1453
|
+
const telemetryAccepted = Boolean(
|
|
1454
|
+
activationTelemetry?.accepted === true
|
|
1455
|
+
&& activationTelemetry?.evidence_authority === 'client_self_reported'
|
|
1459
1456
|
);
|
|
1457
|
+
if (!telemetryAccepted) {
|
|
1458
|
+
throw new Error('activation telemetry was not acknowledged as authenticated client_self_reported delivery; update the backend/client compatibility pair, then retry activate');
|
|
1459
|
+
}
|
|
1460
|
+
// Never project response-supplied coverage or profile receipts into the install
|
|
1461
|
+
// result. This endpoint acknowledges bounded, authenticated client telemetry;
|
|
1462
|
+
// it does not certify that hooks, wrappers, or adapters continuously ran.
|
|
1463
|
+
activationProfileReceipt = {
|
|
1464
|
+
accepted: true,
|
|
1465
|
+
evidence_authority: 'client_self_reported',
|
|
1466
|
+
certified_coverage: false,
|
|
1467
|
+
};
|
|
1460
1468
|
activationVerified = Boolean(
|
|
1461
1469
|
firstValue.active
|
|
1462
1470
|
&& runtimeGateVerified(runtime)
|
|
1463
1471
|
&& (status.enabled ?? status.ok)
|
|
1464
|
-
&&
|
|
1465
|
-
&& profileBound,
|
|
1472
|
+
&& telemetryAccepted,
|
|
1466
1473
|
);
|
|
1467
1474
|
if (!activationVerified) {
|
|
1468
|
-
throw new Error('activation prerequisites were not all verified by the server');
|
|
1475
|
+
throw new Error('activation self-test prerequisites were not all verified by the server');
|
|
1469
1476
|
}
|
|
1470
1477
|
}
|
|
1471
1478
|
return {
|
|
@@ -1481,9 +1488,16 @@ async function runSelfTest(options) {
|
|
|
1481
1488
|
runtime_exact_next_action: runtime.exact_next_action || null,
|
|
1482
1489
|
runtime_before_you_act: runtime.before_you_act || null,
|
|
1483
1490
|
activation_verified: activationVerified,
|
|
1491
|
+
activation_scope: options.activation ? 'server_self_test_only' : null,
|
|
1492
|
+
coverage_verified: false,
|
|
1493
|
+
passive_live: false,
|
|
1494
|
+
reload_required: Boolean(options.activation),
|
|
1495
|
+
activation_next_action: options.activation
|
|
1496
|
+
? 'Restart the owning harness, then run npx @getmarrow/install@latest doctor --self-test.'
|
|
1497
|
+
: null,
|
|
1484
1498
|
activation_receipt: activationReceipt,
|
|
1485
1499
|
activation_profile_receipt: activationProfileReceipt,
|
|
1486
|
-
activation_coverage:
|
|
1500
|
+
activation_coverage: null,
|
|
1487
1501
|
first_value: firstValue && firstValue.ok !== false ? firstValue : null,
|
|
1488
1502
|
first_value_signal: firstValueSignal,
|
|
1489
1503
|
install_value_moment: installValueMoment,
|
|
@@ -1636,7 +1650,13 @@ function printReport(report) {
|
|
|
1636
1650
|
if (report.activation?.requested) {
|
|
1637
1651
|
process.stdout.write('Activation:\n');
|
|
1638
1652
|
process.stdout.write(`- agent: ${report.activation.agent_id}\n`);
|
|
1639
|
-
process.stdout.write(`- server confirmed: ${report.activation.server_confirmed ? 'yes' : 'no'}\n
|
|
1653
|
+
process.stdout.write(`- self-test server confirmed: ${report.activation.server_confirmed ? 'yes' : 'no'}\n`);
|
|
1654
|
+
process.stdout.write(`- scope: ${report.activation.activation_scope}\n`);
|
|
1655
|
+
process.stdout.write(`- coverage verified: ${report.activation.coverage_verified ? 'yes' : 'no'}\n`);
|
|
1656
|
+
process.stdout.write(`- passive live in this process: ${report.activation.passive_live ? 'yes' : 'no'}\n`);
|
|
1657
|
+
process.stdout.write(`- reload required: ${report.activation.reload_required ? 'yes' : 'no'}\n`);
|
|
1658
|
+
if (report.activation.next_action) process.stdout.write(`- next action: ${report.activation.next_action}\n`);
|
|
1659
|
+
process.stdout.write('\n');
|
|
1640
1660
|
}
|
|
1641
1661
|
|
|
1642
1662
|
process.stdout.write('Detected:\n');
|
|
@@ -1814,12 +1834,12 @@ async function install(options) {
|
|
|
1814
1834
|
throw new Error('repair requires explicit write authorization (--yes)');
|
|
1815
1835
|
}
|
|
1816
1836
|
const detection = detectEnvironment(options.cwd);
|
|
1837
|
+
const client = detectedClient(detection);
|
|
1838
|
+
options.client = client;
|
|
1839
|
+
options.agentId = String(options.agentId || '').trim() || stableAgentId(detection.root, client);
|
|
1817
1840
|
const plan = buildPlan(detection, options);
|
|
1818
1841
|
const writeMode = options.doctor ? 'doctor' : options.dryRun ? 'dry-run' : options.repair ? 'repair' : options.yes ? 'write' : 'dry-run';
|
|
1819
1842
|
const changes = applyPlan(plan, options);
|
|
1820
|
-
const client = detectedClient(detection);
|
|
1821
|
-
options.client = client;
|
|
1822
|
-
if (!options.agentId) options.agentId = stableAgentId(detection.root, client);
|
|
1823
1843
|
const profile = activationProfile(detection, plan, changes, client);
|
|
1824
1844
|
options.activation = options.activate ? {
|
|
1825
1845
|
harness: client,
|
|
@@ -1830,7 +1850,10 @@ async function install(options) {
|
|
|
1830
1850
|
.filter((change) => change.changed && change.applied && /hook|runtime|rule|instruction|config/i.test(change.label))
|
|
1831
1851
|
.map((change) => change.label)
|
|
1832
1852
|
.slice(0, 20),
|
|
1833
|
-
capture_verified:
|
|
1853
|
+
capture_verified: false,
|
|
1854
|
+
configuration_complete: changes.every((change) => change.applied || change.already_present),
|
|
1855
|
+
evidence_authority: 'client_self_reported',
|
|
1856
|
+
coverage_verified: false,
|
|
1834
1857
|
adapter_version: profile.adapter_version,
|
|
1835
1858
|
capability_level: profile.capability_level,
|
|
1836
1859
|
config_fingerprint: profile.config_fingerprint,
|
|
@@ -1932,6 +1955,11 @@ async function install(options) {
|
|
|
1932
1955
|
requested: options.activate,
|
|
1933
1956
|
agent_id: options.agentId,
|
|
1934
1957
|
server_confirmed: Boolean(selfTest.activation_verified),
|
|
1958
|
+
activation_scope: selfTest.activation_scope || null,
|
|
1959
|
+
coverage_verified: false,
|
|
1960
|
+
passive_live: false,
|
|
1961
|
+
reload_required: Boolean(options.activate),
|
|
1962
|
+
next_action: selfTest.activation_next_action || null,
|
|
1935
1963
|
receipt: selfTest.activation_receipt || null,
|
|
1936
1964
|
profile,
|
|
1937
1965
|
},
|