@getmarrow/mcp 3.9.87 → 3.9.89
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 +14 -4
- package/dist/cli.js +10 -1
- package/dist/cli.js.map +1 -1
- package/dist/hook-context.d.ts.map +1 -1
- package/dist/hook-context.js +13 -2
- package/dist/hook-context.js.map +1 -1
- package/dist/hook-contract.d.ts +8 -3
- package/dist/hook-contract.d.ts.map +1 -1
- package/dist/hook-contract.js +39 -11
- package/dist/hook-contract.js.map +1 -1
- package/dist/hook-pre-action.d.ts +1 -0
- package/dist/hook-pre-action.d.ts.map +1 -1
- package/dist/hook-pre-action.js +108 -25
- package/dist/hook-pre-action.js.map +1 -1
- package/dist/hook-session.d.ts.map +1 -1
- package/dist/hook-session.js +9 -3
- package/dist/hook-session.js.map +1 -1
- package/dist/hook-tool-policy.d.ts.map +1 -1
- package/dist/hook-tool-policy.js +13 -3
- package/dist/hook-tool-policy.js.map +1 -1
- package/dist/hook.d.ts +1 -1
- package/dist/hook.d.ts.map +1 -1
- package/dist/hook.js +30 -8
- package/dist/hook.js.map +1 -1
- package/dist/lifecycle-spool.d.ts +4 -0
- package/dist/lifecycle-spool.d.ts.map +1 -1
- package/dist/lifecycle-spool.js +129 -18
- package/dist/lifecycle-spool.js.map +1 -1
- package/dist/session-loop-guard.d.ts +44 -0
- package/dist/session-loop-guard.d.ts.map +1 -0
- package/dist/session-loop-guard.js +414 -0
- package/dist/session-loop-guard.js.map +1 -0
- package/package.json +2 -1
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -130,12 +130,22 @@ A direct `marrow_think` can receive a durable pending response before the backen
|
|
|
130
130
|
|
|
131
131
|
A saved `observed_unverified` outcome is terminal observation evidence, not a committed outcome. Receipt expiry cannot retroactively authorize completed work. Preserve the original decision, receipt, proof and key; an already authorized durable checkpoint may finish through its existing exact recovery path. Do not repeat the action merely to obtain a fresh receipt.
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
### Previous release: v3.9.87
|
|
134
134
|
|
|
135
135
|
v3.9.87 hardens the authenticated control-path canary against single-sample transport blips so monitoring stops flapping on a healthy service. The canary now retries transport-class delivery failures (`request_failed`, `service_unavailable`, `connection_reset`, `dns_unavailable`, `tls_failure`, `edge_access_denied`, `rate_limited`) in-run with the same idempotent operation before declaring a failure, gives the asynchronous `marrow_auto` and `marrow_first_value` calls a separate deadline ceiling (thirty seconds via `MARROW_MCP_CANARY_ASYNC_TOOL_TIMEOUT_MS`), and raises the default total canary budget to forty-five seconds so bounded retries fit. Results recovered by a retry are annotated with `recovered_on_retry: true`. Authentication, authorization, contract, and package-identity failures remain immediate hard failures with no retry. Tool surface, client contracts, and request deadlines are unchanged.
|
|
136
136
|
|
|
137
137
|
v3.9.86 was published with the adapter version constant still at `3.9.85`, so the strict canary identity check rejected it; it is deprecated — use `3.9.87`. SDK `3.7.62` and installer `0.1.56` are unchanged; install MCP `3.9.87`, reload the host, review hook trust, and verify before claiming the updated client is active.
|
|
138
138
|
|
|
139
|
+
## What's New in v3.9.89
|
|
140
|
+
|
|
141
|
+
v3.9.89 adds a default-enabled, private local session loop guard for every supported native-hook installation, independent of Marrow plan or fleet entitlement. It hashes bounded operation inputs and results into owner-only state under `~/.marrow`, stops unchanged successful verification repeats, stops the third unchanged poll or failed attempt, resets after meaningful mutation or a new owner prompt, and clears the session at close. Routine read-only results remain local, so ordinary checks add no Marrow API or database writes; one compact client-reported block marker is emitted only when a configured hook actually denies a repeat. Official Marrow tools remain excluded. `MARROW_AUTO_HOOK=false` and the existing owner local-control disable remain the explicit opt-outs.
|
|
142
|
+
|
|
143
|
+
The pre-action path now reuses a valid runtime-created decision and calls Think only when the runtime completion contract explicitly requires decision creation. Setup reports the loop guard as configured without claiming live enforcement before host restart, trust review, and an observed hook invocation. `marrow-mcp loop-guard-self-test` verifies the local behavior against isolated temporary state without touching the user's ledger. SDK `3.7.62` and installer `0.1.57` are unchanged.
|
|
144
|
+
|
|
145
|
+
### Earlier v3.9.88 changes
|
|
146
|
+
|
|
147
|
+
v3.9.88 makes the lifecycle spool self-healing so users never need a manual `drain-spool` for ordinary failures. Dead letters are now classified: authentication rejections (401/403) stay `attention_required` with credential-restore guidance and are never auto-retried; conflicts (409) are marked `server_owned` because the server already holds durable evidence for that event id, and are never replayed; every other dead letter (transport, schema, or legacy rows without a status) is `recoverable` and retried automatically by the passive nudge — at most 5 events per nudge, 3 recovery attempts each, with a 15-minute cooldown between attempts, inside the existing bounded nudge budget. Recovery bookkeeping stays local and never changes the server request. `spool-status` gains `recoverable`, `server_owned`, and `recovery_exhausted` counts, and `failed` now counts only auth-class dead letters that genuinely need the operator. Explicit `drain-spool` keeps full authority: it still retries every operator-fixable dead letter including the auth class, clears recovery exhaustion for a fresh budget, and skips server-owned events. SDK `3.7.62` and installer `0.1.56` are unchanged.
|
|
148
|
+
|
|
139
149
|
### Previous release: v3.9.85
|
|
140
150
|
|
|
141
151
|
v3.9.85 keeps the existing Marrow Auto request and response deadlines active through response-body consumption and JSON parsing, so a server that sends headers and then stalls ends with the same typed bounded timeout as a stalled header response. The retry owner, four-second write-attempt ceiling, and eight-second Auto response budget are unchanged.
|
|
@@ -443,7 +453,7 @@ For an ordinary gate, continue only when the server declares `completion_contrac
|
|
|
443
453
|
|
|
444
454
|
For arbitration, the ordinary proof marker is not accepted. Approve the exact arbitration decision in the authenticated Marrow dashboard, then call auto with the same operation ID, `arbitration_receipt_id`, and server-issued `owner_approval_receipt_id`. Proof or chat text cannot substitute for this dashboard receipt. A CLI closed response reports `phase: "closed"`, `live_delivery.committed: true`, and `resumable: false`; the library result uses `committed: true`. Neither an ordinary marker nor an outcome record changes a stopped action into an allowed action.
|
|
445
455
|
|
|
446
|
-
The CLI's lifecycle `receipt.queued: true` means its stable event is stored locally for later bounded delivery; `receipt.accepted: false` must not be read as server acceptance. Transient failures preserve the queued event and retry schedule for later bounded delivery, including after restart. Server retry guidance is respected. Authentication
|
|
456
|
+
The CLI's lifecycle `receipt.queued: true` means its stable event is stored locally for later bounded delivery; `receipt.accepted: false` must not be read as server acceptance. Transient failures preserve the queued event and retry schedule for later bounded delivery, including after restart. Server retry guidance is respected. Authentication failures remain failed with explicit credential-repair guidance and are never auto-retried; conflicted events are server-owned evidence and are never replayed; every other dead letter self-heals through bounded automatic recovery during passive nudges. Process exit can interrupt the background nudge, leaving the event for a later run. `phase_timings_ms.total` measures core auto phases. `response_timings_ms` contains numeric `core`, `durable_enqueue`, and `full_response`; the last ends at response construction and excludes subsequent stdout drain and host processing. Canary `latency_ms` independently measures the MCP round trip, while `attempts` and `retry_wait_ms` describe measured outer tool retries, not internal database or network calls.
|
|
447
457
|
|
|
448
458
|
Example pre-action request:
|
|
449
459
|
|
|
@@ -559,14 +569,14 @@ Setup installs distinct Claude Code and Grok hook entrypoints. The public entryp
|
|
|
559
569
|
|
|
560
570
|
Claude Code hooks may cooperatively request guidance and apply the harness permission response, but that does not certify always-on control. Codex native hooks map both block and review-required gates to the supported synchronous deny response. Cursor and Composer use the same Cursor-native pre-action, result, failure, and stop adapters. Cline uses native pre-action and post-tool adapters plus TaskCancel closeout; its documented TaskComplete hook remains coming soon and is not claimed as observed coverage. Windsurf uses native pre-action, success-result, and response-closeout adapters and requires Restricted Mode to be off. Gemini CLI uses native BeforeTool, AfterTool, and AfterAgent adapters; AfterAgent is the deterministic per-turn closeout and no SessionEnd delivery is claimed. Grok uses global native PreToolUse, PostToolUse/PostToolUseFailure, and one nonblocking Stop closeout; Marrow's generated Grok file contains no duplicate SessionEnd closeout. These native paths keep MCP on demand and require restart plus host hook review. Cursor, Cline, Windsurf, Gemini, and Grok deny protected review-required or unavailable-control work when their native contracts cannot make a generic ask enforceable. All activity remains client-self-reported rather than verified host telemetry, and the governed wrapper remains an explicit bounded fallback. Unknown and custom hosts remain on demand unless they provide a bounded event adapter, whose activity is still not certification without an independent authority.
|
|
561
571
|
|
|
562
|
-
Transient lifecycle receipts use a bounded owner-only spool and are retried with stable event IDs. Operators can inspect and drain it without exposing event content:
|
|
572
|
+
Transient lifecycle receipts use a bounded owner-only spool and are retried with stable event IDs. Dead letters self-heal: recoverable failures are retried automatically with bounded attempts and cooldown during passive nudges, and conflicted events are recognized as server-owned evidence that is never replayed. Operators can inspect and drain it without exposing event content:
|
|
563
573
|
|
|
564
574
|
```bash
|
|
565
575
|
npx -y --package=@getmarrow/mcp@latest marrow-mcp spool-status
|
|
566
576
|
npx -y --package=@getmarrow/mcp@latest marrow-mcp drain-spool
|
|
567
577
|
```
|
|
568
578
|
|
|
569
|
-
The output contains only state, bounded pending/failed counts, oldest receipt timestamps, capacity, and an exact fix. A drain applies only to the active credential-and-agent namespace: isolated legacy namespace debt is reported separately and never changes a successful active-namespace drain into a failure. Legacy files are never replayed, merged, deleted, or attributed to the active identity. Restore the exact original identity to drain one, or preserve the selected file unchanged in a separate owner-only quarantine directory when that identity is unavailable.
|
|
579
|
+
The output contains only state, bounded pending/failed/recoverable/server-owned/recovery-exhausted counts, oldest receipt timestamps, capacity, and an exact fix. Only authentication-class dead letters require the operator: restore the credential binding, then drain. A drain applies only to the active credential-and-agent namespace: isolated legacy namespace debt is reported separately and never changes a successful active-namespace drain into a failure. Legacy files are never replayed, merged, deleted, or attributed to the active identity. Restore the exact original identity to drain one, or preserve the selected file unchanged in a separate owner-only quarantine directory when that identity is unavailable. Authentication failures in the active namespace remain explicit durable failures with repair guidance; recovery-exhausted events stop cycling instead of retrying indefinitely, and `drain-spool` remains an explicit operator tool rather than a user requirement.
|
|
570
580
|
|
|
571
581
|
Check the installed runtime:
|
|
572
582
|
|
package/dist/cli.js
CHANGED
|
@@ -29,6 +29,7 @@ const redact_1 = require("./redact");
|
|
|
29
29
|
const status_cache_1 = require("./status-cache");
|
|
30
30
|
const habit_loop_copy_1 = require("./habit-loop-copy");
|
|
31
31
|
const host_capability_1 = require("./host-capability");
|
|
32
|
+
const session_loop_guard_1 = require("./session-loop-guard");
|
|
32
33
|
// Parse CLI args
|
|
33
34
|
function parseArgs() {
|
|
34
35
|
const args = process.argv.slice(2);
|
|
@@ -62,6 +63,9 @@ function parseArgs() {
|
|
|
62
63
|
if (args[i] === 'ping' || args[i] === '--ping') {
|
|
63
64
|
result.ping = true;
|
|
64
65
|
}
|
|
66
|
+
if (args[i] === 'loop-guard-self-test' || args[i] === '--loop-guard-self-test') {
|
|
67
|
+
result.loopGuardSelfTest = true;
|
|
68
|
+
}
|
|
65
69
|
}
|
|
66
70
|
return result;
|
|
67
71
|
}
|
|
@@ -71,7 +75,7 @@ function reportLifecycleSpool(input) {
|
|
|
71
75
|
}
|
|
72
76
|
catch { /* owner-only quarantine is best effort */ }
|
|
73
77
|
const spool = (0, lifecycle_spool_1.lifecycleSpoolStatus)({ apiKey: input.apiKey, agentId: input.agentId });
|
|
74
|
-
if (input.baseUrl &&
|
|
78
|
+
if (input.baseUrl && (0, lifecycle_spool_1.shouldNudgeLifecycleSpool)(spool)) {
|
|
75
79
|
void (0, lifecycle_spool_1.nudgeLifecycleSpool)({ apiKey: input.apiKey, baseUrl: input.baseUrl, agentId: input.agentId });
|
|
76
80
|
}
|
|
77
81
|
return spool;
|
|
@@ -256,6 +260,8 @@ ${MARROW_BLOCK_END}`;
|
|
|
256
260
|
process.stdout.write(`Grok native hook configuration is present at ${grokHookInstall.settingsPath}. Restart Grok and inspect /hooks before relying on it. Activity remains client-self-reported and does not certify observed coverage.\n`);
|
|
257
261
|
}
|
|
258
262
|
process.stdout.write(`Hook settings: ${hookInstall.settingsPath}\n`);
|
|
263
|
+
process.stdout.write('Configured private local session loop guard for supported native hook events. It becomes active only after host restart/trust review and an actual hook invocation; setup alone does not prove enforcement.\n');
|
|
264
|
+
process.stdout.write('Offline verification: marrow-mcp loop-guard-self-test (uses isolated temporary state and does not touch the user ledger).\n');
|
|
259
265
|
process.stdout.write('Set MARROW_AUTO_HOOK=false to disable passive hooks.\n');
|
|
260
266
|
process.stdout.write('Set MARROW_PASSIVE_BRIEF=false to disable automatic decision briefs, or MARROW_PASSIVE_BRIEF=always to brief every prompt.\n');
|
|
261
267
|
process.stdout.write('Set MARROW_HOOK_DEBUG=true for write-side hook diagnostics, or MARROW_CONTEXT_HOOK_DEBUG=true for prompt-context diagnostics.\n');
|
|
@@ -381,6 +387,9 @@ if (process.argv[2] !== 'keys') {
|
|
|
381
387
|
else if (cliArgs.ping) {
|
|
382
388
|
void runPingCommand();
|
|
383
389
|
}
|
|
390
|
+
else if (cliArgs.loopGuardSelfTest) {
|
|
391
|
+
process.stdout.write(`${JSON.stringify((0, session_loop_guard_1.runSessionLoopGuardSelfTest)(), null, 2)}\n`);
|
|
392
|
+
}
|
|
384
393
|
else if (cliArgs.setup) {
|
|
385
394
|
runSetup();
|
|
386
395
|
}
|