@junghanacs/entwurf 0.40.0 → 0.41.1

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 (128) hide show
  1. package/AGENTS.md +4 -2
  2. package/BASELINE.md +55 -2
  3. package/CHANGELOG.md +562 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/DELIVERY.md +18 -2
  6. package/FAQ.md +8 -4
  7. package/README.md +60 -45
  8. package/VERIFY.md +14 -11
  9. package/demo/README.md +1 -1
  10. package/docs/acp-backend-rail.md +6 -2
  11. package/docs/external-mcp-host.md +8 -6
  12. package/docs/fresh-cut-policy.md +9 -1
  13. package/docs/setup-clean-host.md +76 -20
  14. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +81 -19
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-pidfd.py +236 -0
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-request.js +473 -0
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-retire.js +125 -0
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire-production.js +149 -0
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire.js +158 -0
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +2 -1
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +283 -20
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +7 -0
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +47 -3
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -1
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +96 -16
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +5 -29
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +28 -0
  28. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +26 -11
  29. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-retire-request.js +76 -0
  30. package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +67 -17
  31. package/mcp/entwurf-bridge/dist/pi-extensions/lib/retirement-event.js +211 -0
  32. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +124 -10
  33. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +53 -2
  34. package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +1 -1
  35. package/mcp/entwurf-bridge/dist/scripts/probe-bridge-command.js +1 -0
  36. package/mcp/entwurf-bridge/src/index.ts +93 -19
  37. package/mcp/entwurf-bridge/test.sh +2 -2
  38. package/mcp/entwurf-bridge/tsconfig.build.json +10 -1
  39. package/package.json +15 -14
  40. package/pi/meta-bridge/entwurf-meta-receive/scripts/hook-launch.sh +3 -3
  41. package/pi/pi-durable/carrier/tui.js +18 -3
  42. package/pi/pi-durable/overlay/upstream-pin.json +12 -12
  43. package/pi-extensions/entwurf-control.ts +55 -20
  44. package/pi-extensions/lib/acp/backend-adapter.ts +5 -3
  45. package/pi-extensions/lib/acp/backend.ts +12 -9
  46. package/pi-extensions/lib/cc-retire-pidfd.py +236 -0
  47. package/pi-extensions/lib/cc-retire-request.ts +553 -0
  48. package/pi-extensions/lib/control-retire.ts +195 -0
  49. package/pi-extensions/lib/entwurf-control-rpc.ts +17 -1
  50. package/pi-extensions/lib/entwurf-v2-retire-production.ts +227 -0
  51. package/pi-extensions/lib/entwurf-v2-retire.ts +269 -0
  52. package/pi-extensions/lib/entwurf-v2-surface.ts +2 -1
  53. package/pi-extensions/lib/entwurf-v2-visible-resume.ts +390 -36
  54. package/pi-extensions/lib/fresh-call-composition.ts +15 -0
  55. package/pi-extensions/lib/fresh-call-dispatch.ts +45 -4
  56. package/pi-extensions/lib/herdr-fresh-call.ts +5 -0
  57. package/pi-extensions/lib/meta-session.ts +140 -16
  58. package/pi-extensions/lib/mux-fresh-call.ts +7 -27
  59. package/pi-extensions/lib/mux-launch.ts +29 -0
  60. package/pi-extensions/lib/mux-resume-call.ts +33 -12
  61. package/pi-extensions/lib/pi-retire-request.ts +111 -0
  62. package/pi-extensions/lib/resume-launch-identity.ts +104 -18
  63. package/pi-extensions/lib/retirement-event.ts +253 -0
  64. package/pi-extensions/meta-bridge-hook.ts +142 -13
  65. package/pi-extensions/meta-bridge-pi-durable.ts +57 -3
  66. package/run.sh +123 -34
  67. package/scripts/agy-bridge-config.py +4 -1
  68. package/scripts/build-bridge.sh +14 -0
  69. package/scripts/check-capability-bundle-reach.ts +135 -2
  70. package/scripts/check-entwurf-bridge-boot.ts +2 -1
  71. package/scripts/check-entwurf-fact-provider.ts +1 -0
  72. package/scripts/check-entwurf-v2-production.ts +2 -0
  73. package/scripts/check-entwurf-v2-surface.ts +7 -0
  74. package/scripts/check-gate-qualification.ts +14 -8
  75. package/scripts/check-herdr-activation.ts +2 -2
  76. package/scripts/check-herdr-placement.ts +1 -0
  77. package/scripts/check-hook-launch-topology.ts +6 -15
  78. package/scripts/check-install-container.sh +2 -2
  79. package/scripts/check-meta-doctor-oracle.sh +27 -1
  80. package/scripts/check-meta-facts.ts +8 -3
  81. package/scripts/check-meta-hook-session-switch.ts +230 -13
  82. package/scripts/check-meta-identity-consumers.ts +1 -0
  83. package/scripts/check-meta-listing.ts +1 -0
  84. package/scripts/check-meta-manifest-schema.py +1 -1
  85. package/scripts/check-meta-session.ts +31 -0
  86. package/scripts/check-meta-v3-record.ts +55 -1
  87. package/scripts/check-mux-resume-call.ts +35 -9
  88. package/scripts/check-peer-facts.ts +1 -0
  89. package/scripts/check-pi-durable-contact.ts +3 -1
  90. package/scripts/check-pi-durable-send.ts +4 -2
  91. package/scripts/check-pi-mcp-bridge.ts +1 -0
  92. package/scripts/check-resume-launch-identity.ts +62 -23
  93. package/scripts/lib/codex-fresh-live-protocol.ts +3 -2
  94. package/scripts/lib/meta-hook-bundle.ts +72 -0
  95. package/scripts/meta-bridge-claude-floor.sh +13 -9
  96. package/scripts/meta-bridge-doctor.sh +17 -0
  97. package/scripts/meta-bridge-install.sh +6 -0
  98. package/scripts/meta-facts.ts +1 -1
  99. package/scripts/mutants/bridge-boot-resume.json +5 -2
  100. package/scripts/mutants/cc-retire-pidfd.json +129 -0
  101. package/scripts/mutants/cc-retire-request.json +171 -0
  102. package/scripts/mutants/control-retire.json +105 -0
  103. package/scripts/mutants/control-send-receipt.json +1 -1
  104. package/scripts/mutants/copilot-receive.json +2 -6
  105. package/scripts/mutants/entwurf-v2-retire.json +476 -0
  106. package/scripts/mutants/fresh-call-dispatch.json +37 -0
  107. package/scripts/mutants/meta-hook-session-switch.json +88 -0
  108. package/scripts/mutants/meta-identity.json +57 -0
  109. package/scripts/mutants/mux-fresh-call.json +1 -1
  110. package/scripts/mutants/mux-resume-call.json +40 -4
  111. package/scripts/mutants/pack-install.json +4 -4
  112. package/scripts/mutants/pi-durable.json +139 -0
  113. package/scripts/mutants/pi-floor.json +5 -5
  114. package/scripts/mutants/pi-retire-request.json +72 -0
  115. package/scripts/mutants/resume-launch-identity.json +35 -8
  116. package/scripts/mutants/retirement-event.json +195 -0
  117. package/scripts/mutants/v2-surface.json +16 -0
  118. package/scripts/mutants/v2-visible-resume.json +283 -13
  119. package/scripts/probe-bridge-command.ts +1 -0
  120. package/scripts/smoke-agy-install-state.sh +2 -2
  121. package/scripts/smoke-codex-fresh-live.ts +2 -1
  122. package/scripts/smoke-copilot-mcp-state.sh +1 -1
  123. package/scripts/smoke-herdr-raw-install-live.sh +15 -7
  124. package/scripts/smoke-meta-install-state.sh +4 -4
  125. package/scripts/smoke-mux-lifecycle-live.ts +10 -10
  126. package/scripts/smoke-omp-mcp-state.sh +1 -1
  127. package/scripts/smoke-pi-durable-fresh-live.ts +5 -3
  128. package/scripts/smoke-pi-provider-state.sh +3 -3
@@ -110,9 +110,16 @@ fi
110
110
 
111
111
  PI_SPEC="$(node -p "require('$REPO/package.json').dependencies['@earendil-works/pi-coding-agent']")"
112
112
  # Pinned, not floating: a receipt that cannot say WHICH Claude Code it ran is not
113
- # reproducible. This is the version measured in the container on 2026-09-19. Claude Code
114
- # is scaffolding here (Rule 17) — the product face starts at `herdr integration install`.
115
- CLAUDE_SPEC="2.1.278"
113
+ # reproducible. The exact version is the support floor itself, derived from
114
+ # `package.json` `entwurf.claudeCodeFloor` rather than retyped: a hand-kept pin stayed at
115
+ # 2.1.278 after the floor moved to 2.1.306 and the activation then refused it, as it should.
116
+ # Claude Code is scaffolding here (Rule 17) — the product face starts at `herdr integration install`.
117
+ CLAUDE_FLOOR="$(node -p "require('$REPO/package.json').entwurf.claudeCodeFloor")"
118
+ CLAUDE_SPEC="${CLAUDE_FLOOR#>=}"
119
+ if [[ "$CLAUDE_FLOOR" != ">=$CLAUDE_SPEC" || ! "$CLAUDE_SPEC" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
120
+ echo "[smoke-herdr-raw-install-live] FAIL — package.json entwurf.claudeCodeFloor is '$CLAUDE_FLOOR', not '>=X.Y.Z'." >&2
121
+ exit 1
122
+ fi
116
123
  FLOOR_SPEC="$(node -p "require('$REPO/package.json').engines.node")"
117
124
  FLOOR_MAJOR="${FLOOR_SPEC#>=}"; FLOOR_MAJOR="${FLOOR_MAJOR%%.*}"
118
125
  HERDR_VERSION="$(node -p "require('$REPO/scripts/fixtures/herdr-supply.json').version")"
@@ -490,8 +497,8 @@ for (const name of ["entwurf", "entwurf-bridge", "entwurf-statusline"]) {
490
497
  }
491
498
 
492
499
  // The REAL subcommand, from the installed bin, under node_modules — which is the branch of
493
- // start.sh that runs the prebuilt dist. Its own oracle is an EXACT set (`EXPECT_TOOLS` in run.sh check-bridge), so a
494
- // zero exit here is the artifact listing all eight garden verbs and no ninth.
500
+ // start.sh that runs the prebuilt dist. Its own oracle is an EXACT set (`expected` in run.sh `validate_entwurf_bridge`, which check-bridge runs), so a
501
+ // zero exit here is the artifact listing all nine garden verbs and no tenth.
495
502
  const run = spawnSync(path.join(binDir, "entwurf"), ["check-bridge"], { encoding: "utf8" });
496
503
  const said = `${run.stdout ?? ""}${run.stderr ?? ""}`;
497
504
  // [a-z0-9_] and not [a-z_]: the first draft of this line printed `entwurf_v` for entwurf_v2
@@ -502,7 +509,7 @@ const verbs = (said.match(/entwurf_[a-z0-9_]+/g) ?? []).filter((v, i, a) => a.in
502
509
  // A SECOND, INDEPENDENT COPY OF THE SET, ON PURPOSE (A5 D1). The exit code alone used to be
503
510
  // the oracle here, which left the printed list as decoration a parser bug could quietly
504
511
  // corrupt — and did, see the regex note just above. The package under test carries the
505
- // expectation of run.sh:5187 in its own bytes, so reading the answer from there would let
512
+ // `validate_entwurf_bridge` expectation of run.sh in its own bytes, so reading the answer from there would let
506
513
  // the artifact grade itself. The literal below is a copy that must AGREE with the shipped
507
514
  // one; the two disagreeing is the signal, and a verb genuinely added upstream reddens this
508
515
  // smoke until somebody says so here too.
@@ -513,6 +520,7 @@ const EXPECTED_VERBS = [
513
520
  "entwurf_peers",
514
521
  "entwurf_register_native",
515
522
  "entwurf_resume_call",
523
+ "entwurf_retire_call",
516
524
  "entwurf_self",
517
525
  "entwurf_v2",
518
526
  ];
@@ -520,7 +528,7 @@ console.log(` VERBS ${verbs.join(",") || "<none>"}`);
520
528
  if (run.status === 0) ok(`entwurf check-bridge exit 0 from the installed bin (${verbs.length} verbs listed)`);
521
529
  else no(`entwurf check-bridge exit ${run.status}: ${said.trim().slice(0, 400)}`);
522
530
  JSON.stringify(verbs) === JSON.stringify(EXPECTED_VERBS)
523
- ? ok(`the receipt names EXACTLY the eight garden verbs (${EXPECTED_VERBS.length}), parsed from what the installed bin answered`)
531
+ ? ok(`the receipt names EXACTLY the nine garden verbs (${EXPECTED_VERBS.length}), parsed from what the installed bin answered`)
524
532
  : no(`verb set mismatch — want ${JSON.stringify(EXPECTED_VERBS)} got ${JSON.stringify(verbs)}`);
525
533
  process.exit(bad);
526
534
  ' "$ACTIVE" "$REGISTRY" "$PLUGIN_ID" || fail=1
@@ -46,7 +46,7 @@ cat > "$INS_BIN/claude" <<'SH'
46
46
  #!/usr/bin/env bash
47
47
  printf '%s\n' "$*" >> "$FAKE_CLAUDE_LOG"
48
48
  case "$1${2:+ $2}" in
49
- "--version") echo "2.1.217 (Claude Code)" ;;
49
+ "--version") echo "2.1.306 (Claude Code)" ;;
50
50
  "plugin list") printf '%s\n' "entwurf-meta-receive@meta-bridge-local" " Status: enabled" ;;
51
51
  "mcp get") printf '%s\n' "Scope: User config" "Status: Connected" ;;
52
52
  *) : ;;
@@ -95,7 +95,7 @@ case "$1${2:+ $2}" in
95
95
  # Keep writing well past the pipe buffer: a reader that leaves early SIGPIPEs us.
96
96
  cat "$FAKE_MCP_TAIL"
97
97
  exit $? ;;
98
- "--version") echo "2.1.217 (Claude Code)" ;;
98
+ "--version") echo "2.1.306 (Claude Code)" ;;
99
99
  "plugin list") printf '%s\n' "entwurf-meta-receive@meta-bridge-local" " Status: enabled" ;;
100
100
  *) : ;;
101
101
  esac
@@ -710,7 +710,7 @@ FAKE_BIN="$TMP/fake-bin"; mkdir -p "$FAKE_BIN"
710
710
  cat > "$FAKE_BIN/claude" <<'SH'
711
711
  #!/usr/bin/env bash
712
712
  printf '%s\n' "$*" >> "$FAKE_CLAUDE_LOG"
713
- [ "$1" = "--version" ] && echo "2.1.217 (Claude Code)"
713
+ [ "$1" = "--version" ] && echo "2.1.306 (Claude Code)"
714
714
  exit 0
715
715
  SH
716
716
  chmod +x "$FAKE_BIN/claude"
@@ -1027,7 +1027,7 @@ if [ "${1:-} ${2:-} ${3:-}" = "plugin list --json" ]; then
1027
1027
  exit 0
1028
1028
  fi
1029
1029
  case "$1${2:+ $2}" in
1030
- "--version") echo "2.1.217 (Claude Code)" ;;
1030
+ "--version") echo "2.1.306 (Claude Code)" ;;
1031
1031
  "plugin list") printf '%s\n' "entwurf-meta-receive@meta-bridge-local" " Status: enabled" ;;
1032
1032
  "mcp get") printf '%s\n' "Scope: User config" "Status: ✔ Connected" ;;
1033
1033
  *) : ;;
@@ -34,11 +34,11 @@
34
34
  * re-injects a bridge extension (#29), and a resume that silently lost its history would look
35
35
  * identical from the socket axis.
36
36
  *
37
- * Claude Code runs the same first half and then STOPS where its capability stops: callback id,
38
- * mailbox delivery, mailbox read receipt — and a resume that is REFUSED as `target-not-pi`, with
39
- * no window opened and no lock residue after the per-gid coordination lock is released. Only pi
40
- * stands a control socket up, so only pi has a same-id
41
- * resume; the refusal is the proof, not an omission.
37
+ * Claude Code runs the same first half: callback id, mailbox delivery, mailbox read receipt — and a
38
+ * resume of that still-LIVE sibling that is REFUSED as `target-live` (its receiver marker names a
39
+ * live owner), with no window opened and no lock residue after the per-gid coordination lock is
40
+ * released. Claude Code's DORMANT same-id resume (#147 L2) is certified deterministically; its LIVE
41
+ * close→resume leg is not in this smoke yet, and this cell does not stand in for it.
42
42
  *
43
43
  * ── Isolate the WRITES, keep the runtimes real ──
44
44
  *
@@ -1035,20 +1035,20 @@ async function main(): Promise<void> {
1035
1035
  `--- response ---\n${ccRead.text}`,
1036
1036
  );
1037
1037
 
1038
- // No resume is invented for a backend that never stands a control socket up. The refusal is
1039
- // the proof: it opens no window, and its per-gid coordination lock leaves no residue.
1038
+ // A live Claude Code sibling is not reopened: its receiver marker names a live owner. The refusal
1039
+ // is the proof: it opens no window, and its per-gid coordination lock leaves no residue.
1040
1040
  const ccWindowsBefore = windowCount(cc.socket, cc.env);
1041
1041
  const ccResume = await ccBridge.call("entwurf_resume_call", { target: ccCitizen }, RESUME_CALL_TIMEOUT_MS);
1042
1042
  ok(
1043
- "claude-code: entwurf_resume_call is REFUSED as target-not-pi — a capability boundary named as itself, not an error about a record that is perfectly fine",
1044
- ccResume.isError && ccResume.text.includes("target-not-pi"),
1043
+ "claude-code: entwurf_resume_call of the still-live sibling is REFUSED as target-live — its receiver marker names a live owner, so a second window would put two processes on one session",
1044
+ ccResume.isError && ccResume.text.includes("target-live"),
1045
1045
  `--- response ---\n${ccResume.text}`,
1046
1046
  );
1047
1047
  ok(
1048
1048
  "claude-code: that refusal opened no window and left no lock behind",
1049
1049
  windowCount(cc.socket, cc.env) === ccWindowsBefore && lockResidue(cellRoots(REAL_HOME), ccCitizen).length === 0,
1050
1050
  );
1051
- receipts["claude-code/5-resume-refused-not-pi"] = ccResume.text;
1051
+ receipts["claude-code/5-resume-refused-live"] = ccResume.text;
1052
1052
  }
1053
1053
 
1054
1054
  await runClaudeCell();
@@ -53,7 +53,7 @@ cat > "$SB/bin/entwurf-bridge" <<'FAKE'
53
53
  while IFS= read -r line; do
54
54
  case "$line" in
55
55
  *'"id":1'*) printf '%s\n' '{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{},"serverInfo":{"name":"fake-entwurf-bridge","version":"0"}}}' ;;
56
- *'"id":2'*) printf '%s\n' '{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"entwurf_v2"},{"name":"entwurf_self"},{"name":"entwurf_peers"},{"name":"entwurf_inbox_read"},{"name":"entwurf_register_native"},{"name":"entwurf_fresh_call"},{"name":"entwurf_resume_call"},{"name":"entwurf_callback"}]}}' ;;
56
+ *'"id":2'*) printf '%s\n' '{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"entwurf_v2"},{"name":"entwurf_self"},{"name":"entwurf_peers"},{"name":"entwurf_inbox_read"},{"name":"entwurf_register_native"},{"name":"entwurf_fresh_call"},{"name":"entwurf_resume_call"},{"name":"entwurf_retire_call"},{"name":"entwurf_callback"}]}}' ;;
57
57
  esac
58
58
  done
59
59
  FAKE
@@ -24,7 +24,7 @@
24
24
  * Pi its own JSONL toolCall/toolResult rows and `entwurf-message` custom rows.
25
25
  * pd its NATIVE store, read from a consistent snapshot taken with node:sqlite's online
26
26
  * `backup` while the host is live (a raw copy of a live WAL set is not consistent):
27
- * the `pi.system` entries' `toolsAdded` (the actual offering — task-wide means the six
27
+ * the `pi.system` entries' `toolsAdded` (the actual offering — task-wide means the eight
28
28
  * contact tools AND the native tools, no filter), the generation checkpoint's
29
29
  * `request.model` and the assistant messages' provider/model (the actual model), the
30
30
  * contact tool calls, and the doorbell submission. The live database and its transcript
@@ -74,7 +74,7 @@ const DIST_ENTRY = path.join(REPO, "mcp/entwurf-bridge/dist/mcp/entwurf-bridge/s
74
74
  const PD_MODEL = process.env.ENTWURF_PI_DURABLE_FRESH_MODEL?.trim() || "openai-codex/gpt-6.1-sol";
75
75
  const PI_MODEL = process.env.ENTWURF_PI_DURABLE_FRESH_PI_MODEL?.trim() || "openai-codex/gpt-6.1-sol";
76
76
  const WIDTH = "task-wide";
77
- /** Independent of the adapter's own constant: the six contact tools step 9 expects the host to offer. */
77
+ /** Independent of the adapter's own constant: the eight contact tools step 9 expects the host to offer. */
78
78
  const CONTACT_TOOLS = [
79
79
  "entwurf_self",
80
80
  "entwurf_peers",
@@ -82,6 +82,8 @@ const CONTACT_TOOLS = [
82
82
  "entwurf_inbox_read",
83
83
  "entwurf_callback",
84
84
  "entwurf_fresh_call",
85
+ "entwurf_resume_call",
86
+ "entwurf_retire_call",
85
87
  ];
86
88
  /** The native app's own tools; task-wide = no filter, so they must be offered beside the contact. */
87
89
  const NATIVE_TOOLS = ["bash", "read", "edit", "write", "subagent"];
@@ -584,7 +586,7 @@ const rootId = (roots[0] as { id: number }).id;
584
586
  const view = pdRootView(nativeEntries, rootId);
585
587
  receipts["6-native-offering"] = view.offering.join(" ") || "(no pi.system offering)";
586
588
  ok(
587
- "ACTUAL OFFERING (root pi.system, toolsAdded/toolsRemoved applied): the six contact tools AND the native tools — task-wide, no filter",
589
+ "ACTUAL OFFERING (root pi.system, toolsAdded/toolsRemoved applied): the eight contact tools AND the native tools — task-wide, no filter",
588
590
  CONTACT_TOOLS.every((t) => view.offering.includes(t)) && NATIVE_TOOLS.every((t) => view.offering.includes(t)),
589
591
  `offered: ${view.offering.join(", ") || "(none)"}`,
590
592
  );
@@ -67,7 +67,7 @@ write_mcp_fake() { # $1 = path
67
67
  while IFS= read -r line; do
68
68
  case "$line" in
69
69
  *'"id":1'*) printf '%s\n' '{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{},"serverInfo":{"name":"fake-entwurf-bridge","version":"0"}}}' ;;
70
- *'"id":2'*) printf '%s\n' '{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"entwurf_v2"},{"name":"entwurf_self"},{"name":"entwurf_peers"},{"name":"entwurf_inbox_read"},{"name":"entwurf_register_native"},{"name":"entwurf_fresh_call"},{"name":"entwurf_resume_call"},{"name":"entwurf_callback"}]}}' ;;
70
+ *'"id":2'*) printf '%s\n' '{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"entwurf_v2"},{"name":"entwurf_self"},{"name":"entwurf_peers"},{"name":"entwurf_inbox_read"},{"name":"entwurf_register_native"},{"name":"entwurf_fresh_call"},{"name":"entwurf_resume_call"},{"name":"entwurf_retire_call"},{"name":"entwurf_callback"}]}}' ;;
71
71
  esac
72
72
  done
73
73
  FAKE
@@ -93,7 +93,7 @@ write_stale_fake() { # $1 = path
93
93
  while IFS= read -r line; do
94
94
  case "$line" in
95
95
  *'"id":1'*) printf '%s\n' '{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{},"serverInfo":{"name":"stale-bridge","version":"0"}}}' ;;
96
- *'"id":2'*) printf '%s\n' '{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"entwurf_v2"},{"name":"entwurf_peers"},{"name":"entwurf_inbox_read"},{"name":"entwurf_register_native"},{"name":"entwurf_fresh_call"},{"name":"entwurf_resume_call"},{"name":"entwurf_callback"}]}}' ;;
96
+ *'"id":2'*) printf '%s\n' '{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"entwurf_v2"},{"name":"entwurf_peers"},{"name":"entwurf_inbox_read"},{"name":"entwurf_register_native"},{"name":"entwurf_fresh_call"},{"name":"entwurf_resume_call"},{"name":"entwurf_retire_call"},{"name":"entwurf_callback"}]}}' ;;
97
97
  esac
98
98
  done
99
99
  FAKE
@@ -289,7 +289,7 @@ rm -f "$STATE"
289
289
  # `ownership` field in that state is the PREIMAGE classification — what stood at the key BEFORE this
290
290
  # install — so `absent` means "we created it" and `managed-current` means "we rewrote our own", and
291
291
  # NEITHER means "unowned". A doctor whose only non-drift shape is the bare bin therefore calls every
292
- # plugin-mode host red while the bridge it points at boots and serves all eight verbs. The canonical
292
+ # plugin-mode host red while the bridge it points at boots and serves all nine verbs. The canonical
293
293
  # command is the one the state RECORDS; the stable runtime root is the writer's business and is
294
294
  # deliberately not re-derived here.
295
295
  PLUGIN_BRIDGE="$SB/runtime/active/node_modules/.bin/entwurf-bridge"