@junghanacs/entwurf 0.40.0 → 0.41.0
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/AGENTS.md +4 -2
- package/BASELINE.md +55 -2
- package/CHANGELOG.md +321 -0
- package/CONTRIBUTING.md +1 -1
- package/DELIVERY.md +18 -2
- package/FAQ.md +8 -4
- package/README.md +26 -8
- package/VERIFY.md +13 -10
- package/docs/acp-backend-rail.md +5 -1
- package/docs/external-mcp-host.md +8 -6
- package/docs/fresh-cut-policy.md +9 -1
- package/docs/setup-clean-host.md +24 -8
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +81 -19
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-pidfd.py +236 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-request.js +473 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-retire.js +125 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire-production.js +149 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire.js +158 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +2 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +283 -20
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +7 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +47 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +96 -16
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +5 -29
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +28 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +26 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-retire-request.js +76 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +67 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/retirement-event.js +211 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +124 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +53 -2
- package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +1 -1
- package/mcp/entwurf-bridge/dist/scripts/probe-bridge-command.js +1 -0
- package/mcp/entwurf-bridge/src/index.ts +93 -19
- package/mcp/entwurf-bridge/test.sh +2 -2
- package/mcp/entwurf-bridge/tsconfig.build.json +10 -1
- package/package.json +4 -4
- package/pi/meta-bridge/entwurf-meta-receive/scripts/hook-launch.sh +3 -3
- package/pi-extensions/entwurf-control.ts +55 -20
- package/pi-extensions/lib/cc-retire-pidfd.py +236 -0
- package/pi-extensions/lib/cc-retire-request.ts +553 -0
- package/pi-extensions/lib/control-retire.ts +195 -0
- package/pi-extensions/lib/entwurf-control-rpc.ts +17 -1
- package/pi-extensions/lib/entwurf-v2-retire-production.ts +227 -0
- package/pi-extensions/lib/entwurf-v2-retire.ts +269 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +2 -1
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +390 -36
- package/pi-extensions/lib/fresh-call-composition.ts +15 -0
- package/pi-extensions/lib/fresh-call-dispatch.ts +45 -4
- package/pi-extensions/lib/herdr-fresh-call.ts +5 -0
- package/pi-extensions/lib/meta-session.ts +140 -16
- package/pi-extensions/lib/mux-fresh-call.ts +7 -27
- package/pi-extensions/lib/mux-launch.ts +29 -0
- package/pi-extensions/lib/mux-resume-call.ts +33 -12
- package/pi-extensions/lib/pi-retire-request.ts +111 -0
- package/pi-extensions/lib/resume-launch-identity.ts +104 -18
- package/pi-extensions/lib/retirement-event.ts +253 -0
- package/pi-extensions/meta-bridge-hook.ts +142 -13
- package/pi-extensions/meta-bridge-pi-durable.ts +56 -2
- package/run.sh +78 -7
- package/scripts/agy-bridge-config.py +4 -1
- package/scripts/build-bridge.sh +14 -0
- package/scripts/check-capability-bundle-reach.ts +135 -2
- package/scripts/check-entwurf-bridge-boot.ts +2 -1
- package/scripts/check-entwurf-fact-provider.ts +1 -0
- package/scripts/check-entwurf-v2-production.ts +2 -0
- package/scripts/check-entwurf-v2-surface.ts +7 -0
- package/scripts/check-gate-qualification.ts +14 -8
- package/scripts/check-herdr-activation.ts +2 -2
- package/scripts/check-herdr-placement.ts +1 -0
- package/scripts/check-hook-launch-topology.ts +6 -15
- package/scripts/check-install-container.sh +2 -2
- package/scripts/check-meta-doctor-oracle.sh +27 -1
- package/scripts/check-meta-facts.ts +8 -3
- package/scripts/check-meta-hook-session-switch.ts +230 -13
- package/scripts/check-meta-identity-consumers.ts +1 -0
- package/scripts/check-meta-listing.ts +1 -0
- package/scripts/check-meta-manifest-schema.py +1 -1
- package/scripts/check-meta-session.ts +31 -0
- package/scripts/check-meta-v3-record.ts +55 -1
- package/scripts/check-mux-resume-call.ts +35 -9
- package/scripts/check-peer-facts.ts +1 -0
- package/scripts/check-pi-durable-contact.ts +3 -1
- package/scripts/check-pi-durable-send.ts +4 -2
- package/scripts/check-pi-mcp-bridge.ts +1 -0
- package/scripts/check-resume-launch-identity.ts +62 -23
- package/scripts/lib/meta-hook-bundle.ts +72 -0
- package/scripts/meta-bridge-claude-floor.sh +13 -9
- package/scripts/meta-bridge-doctor.sh +17 -0
- package/scripts/meta-bridge-install.sh +6 -0
- package/scripts/meta-facts.ts +1 -1
- package/scripts/mutants/bridge-boot-resume.json +5 -2
- package/scripts/mutants/cc-retire-pidfd.json +129 -0
- package/scripts/mutants/cc-retire-request.json +171 -0
- package/scripts/mutants/control-retire.json +105 -0
- package/scripts/mutants/copilot-receive.json +2 -6
- package/scripts/mutants/entwurf-v2-retire.json +476 -0
- package/scripts/mutants/fresh-call-dispatch.json +37 -0
- package/scripts/mutants/meta-hook-session-switch.json +88 -0
- package/scripts/mutants/meta-identity.json +57 -0
- package/scripts/mutants/mux-fresh-call.json +1 -1
- package/scripts/mutants/mux-resume-call.json +40 -4
- package/scripts/mutants/pi-durable.json +79 -0
- package/scripts/mutants/pi-retire-request.json +72 -0
- package/scripts/mutants/resume-launch-identity.json +35 -8
- package/scripts/mutants/retirement-event.json +195 -0
- package/scripts/mutants/v2-surface.json +16 -0
- package/scripts/mutants/v2-visible-resume.json +283 -13
- package/scripts/probe-bridge-command.ts +1 -0
- package/scripts/smoke-agy-install-state.sh +2 -2
- package/scripts/smoke-copilot-mcp-state.sh +1 -1
- package/scripts/smoke-herdr-raw-install-live.sh +5 -4
- package/scripts/smoke-meta-install-state.sh +4 -4
- package/scripts/smoke-mux-lifecycle-live.ts +10 -10
- package/scripts/smoke-omp-mcp-state.sh +1 -1
- package/scripts/smoke-pi-durable-fresh-live.ts +5 -3
- package/scripts/smoke-pi-provider-state.sh +3 -3
|
@@ -73,8 +73,16 @@
|
|
|
73
73
|
"claim": "V2RESUME-OBSERVE-IS-BOUNDED-WAIT",
|
|
74
74
|
"title": "the observation becomes a single immediate probe, which reports every real resume as unobserved (the socket answers ~2-4s later)",
|
|
75
75
|
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
76
|
-
"find": [
|
|
77
|
-
|
|
76
|
+
"find": [
|
|
77
|
+
"\t\t\treturn { kind: \"resume-unobserved\", socketPath, waitedMs: deps.now() - started };",
|
|
78
|
+
"\t\t}",
|
|
79
|
+
"\t\tawait deps.sleep(intervalMs);"
|
|
80
|
+
],
|
|
81
|
+
"replace": [
|
|
82
|
+
"\t\t\treturn { kind: \"resume-unobserved\", socketPath, waitedMs: deps.now() - started };",
|
|
83
|
+
"\t\t}",
|
|
84
|
+
"\t\treturn { kind: \"resume-unobserved\", socketPath, waitedMs: deps.now() - started };"
|
|
85
|
+
],
|
|
78
86
|
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
79
87
|
"timeoutSeconds": 60,
|
|
80
88
|
"signature": "[QK:V2RESUME-OBSERVE-IS-BOUNDED-WAIT]",
|
|
@@ -106,8 +114,8 @@
|
|
|
106
114
|
"claim": "V2RESUME-ARGV-FROM-RECORD",
|
|
107
115
|
"title": "the launcher is handed the caller's own directory instead of the record's, so the citizen returns in the wrong project",
|
|
108
116
|
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
109
|
-
"find": ["\t\tconst launched = deps.launch({ cwd: identity.cwd, runtimeArgs });"],
|
|
110
|
-
"replace": ["\t\tconst launched = deps.launch({ cwd: process.cwd(), runtimeArgs });"],
|
|
117
|
+
"find": ["\t\tconst launched = deps.launch({ backend: \"pi\", cwd: identity.cwd, runtimeArgs });"],
|
|
118
|
+
"replace": ["\t\tconst launched = deps.launch({ backend: \"pi\", cwd: process.cwd(), runtimeArgs });"],
|
|
111
119
|
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
112
120
|
"timeoutSeconds": 60,
|
|
113
121
|
"signature": "[QK:V2RESUME-ARGV-FROM-RECORD]",
|
|
@@ -117,9 +125,11 @@
|
|
|
117
125
|
"claim": "V2RESUME-RECEIPTS-SEPARATE",
|
|
118
126
|
"title": "the launch receipt absorbs the observation, so 'a window opened' and 'the citizen is back' become one claim",
|
|
119
127
|
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
120
|
-
"find": [
|
|
128
|
+
"find": [
|
|
129
|
+
"\t\t\tlaunch: { backend: \"pi\", targetGardenId, sessionFile: identity.sessionFile, handle: launched.handle },"
|
|
130
|
+
],
|
|
121
131
|
"replace": [
|
|
122
|
-
"\t\t\tlaunch: { targetGardenId, sessionFile: identity.sessionFile, handle: launched.handle, kind: observation.kind } as ResumeLaunchReceipt,"
|
|
132
|
+
"\t\t\tlaunch: { backend: \"pi\", targetGardenId, sessionFile: identity.sessionFile, handle: launched.handle, kind: observation.kind } as ResumeLaunchReceipt,"
|
|
123
133
|
],
|
|
124
134
|
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
125
135
|
"timeoutSeconds": 60,
|
|
@@ -156,7 +166,8 @@
|
|
|
156
166
|
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
157
167
|
"find": ["\t\t\treturn { kind: \"resume-unobserved\", socketPath, waitedMs: deps.now() - started };"],
|
|
158
168
|
"replace": [
|
|
159
|
-
"\t\t\t(deps as VisibleResumeDeps).launch({
|
|
169
|
+
"\t\t\t(deps as VisibleResumeDeps).launch({ backend: \"pi\", cwd: \"/tmp\", runtimeArgs: [] });",
|
|
170
|
+
"\t\t\treturn { kind: \"resume-unobserved\", socketPath, waitedMs: deps.now() - started };"
|
|
160
171
|
],
|
|
161
172
|
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
162
173
|
"timeoutSeconds": 60,
|
|
@@ -175,29 +186,29 @@
|
|
|
175
186
|
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
176
187
|
},
|
|
177
188
|
{
|
|
178
|
-
"claim": "V2RESUME-
|
|
189
|
+
"claim": "V2RESUME-BACKEND-UNSUPPORTED-REFUSED",
|
|
179
190
|
"title": "an out-of-domain backend is reported as an error instead of a named refusal, so a fine record reads as a broken one",
|
|
180
191
|
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
181
192
|
"find": ["\t\t\tif (err instanceof ResumeBackendUnsupportedError) {"],
|
|
182
193
|
"replace": ["\t\t\tif (false && err instanceof ResumeBackendUnsupportedError) {"],
|
|
183
194
|
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
184
195
|
"timeoutSeconds": 60,
|
|
185
|
-
"signature": "[QK:V2RESUME-
|
|
196
|
+
"signature": "[QK:V2RESUME-BACKEND-UNSUPPORTED-REFUSED]",
|
|
186
197
|
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
187
198
|
},
|
|
188
199
|
{
|
|
189
|
-
"claim": "V2RESUME-
|
|
200
|
+
"claim": "V2RESUME-BACKEND-UNSUPPORTED-BY-FIELD",
|
|
190
201
|
"title": "the backend is re-derived instead of taken from the typed error, which is the second read this rail refuses",
|
|
191
202
|
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
192
203
|
"find": [
|
|
193
|
-
"\t\t\t\t\t\t`${targetGardenId} is a ${err.backend} citizen; only pi
|
|
204
|
+
"\t\t\t\t\t\t`${targetGardenId} is a ${err.backend} citizen; only pi and Claude Code citizens can be reopened ` +"
|
|
194
205
|
],
|
|
195
206
|
"replace": [
|
|
196
|
-
"\t\t\t\t\t\t`${targetGardenId} is a citizen of another backend; only pi
|
|
207
|
+
"\t\t\t\t\t\t`${targetGardenId} is a citizen of another backend; only pi and Claude Code citizens can be reopened ` +"
|
|
197
208
|
],
|
|
198
209
|
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
199
210
|
"timeoutSeconds": 60,
|
|
200
|
-
"signature": "[QK:V2RESUME-
|
|
211
|
+
"signature": "[QK:V2RESUME-BACKEND-UNSUPPORTED-BY-FIELD]",
|
|
201
212
|
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
202
213
|
},
|
|
203
214
|
{
|
|
@@ -221,6 +232,265 @@
|
|
|
221
232
|
"timeoutSeconds": 60,
|
|
222
233
|
"signature": "[QK:V2RESUME-ACP-MODEL-REFUSED]",
|
|
223
234
|
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"claim": "V2RESUME-CC-DEAD-OWNER-LAUNCHES",
|
|
238
|
+
"title": "a Claude Code resume is launched as `claude --continue`, which reopens whichever session the vendor picks rather than the one the record names",
|
|
239
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
240
|
+
"find": ["\t\truntimeArgs: [\"--resume\", current.nativeSessionId],"],
|
|
241
|
+
"replace": ["\t\truntimeArgs: [\"--continue\"],"],
|
|
242
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
243
|
+
"timeoutSeconds": 60,
|
|
244
|
+
"signature": "[QK:V2RESUME-CC-DEAD-OWNER-LAUNCHES]",
|
|
245
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"claim": "V2RESUME-CC-LIVE-REFUSED",
|
|
249
|
+
"title": "a live Claude Code owner stops being refused as live, so the caller is told to wait on an inconclusive probe instead of sending to the running session",
|
|
250
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
251
|
+
"find": ["\tif (before.owner === \"live\") {"],
|
|
252
|
+
"replace": ["\tif (before.owner === (\"never\" as string)) {"],
|
|
253
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
254
|
+
"timeoutSeconds": 60,
|
|
255
|
+
"signature": "[QK:V2RESUME-CC-LIVE-REFUSED]",
|
|
256
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"claim": "V2RESUME-CC-UNCERTAIN-REFUSED",
|
|
260
|
+
"title": "an owner the shared rule cannot judge is treated as dormant, which can open a second process on a session that is still running",
|
|
261
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
262
|
+
"find": ["\tif (before.owner !== \"dead\") {"],
|
|
263
|
+
"replace": ["\tif (before.owner === (\"never\" as string)) {"],
|
|
264
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
265
|
+
"timeoutSeconds": 60,
|
|
266
|
+
"signature": "[QK:V2RESUME-CC-UNCERTAIN-REFUSED]",
|
|
267
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"claim": "V2RESUME-CC-ABSENT-REFUSED",
|
|
271
|
+
"title": "a Claude Code citizen with no receiver marker is not refused by name, so a session nothing proves dormant falls through the dormancy proof",
|
|
272
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
273
|
+
"find": ["\tif (before.kind === \"absent\") {"],
|
|
274
|
+
"replace": ["\tif (before.kind === (\"never\" as string)) {"],
|
|
275
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
276
|
+
"timeoutSeconds": 60,
|
|
277
|
+
"signature": "[QK:V2RESUME-CC-ABSENT-REFUSED]",
|
|
278
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"claim": "V2RESUME-CC-CORRUPT-REFUSED",
|
|
282
|
+
"title": "an unreadable receiver marker is not refused by name, so a marker whose owner cannot be judged falls through the dormancy proof",
|
|
283
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
284
|
+
"find": ["\tif (before.kind === \"corrupt\") {"],
|
|
285
|
+
"replace": ["\tif (before.kind === (\"never\" as string)) {"],
|
|
286
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
287
|
+
"timeoutSeconds": 60,
|
|
288
|
+
"signature": "[QK:V2RESUME-CC-CORRUPT-REFUSED]",
|
|
289
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"claim": "V2RESUME-CC-MISMATCH-REFUSED",
|
|
293
|
+
"title": "a dead marker for ANOTHER native session is accepted as this session's dormancy proof",
|
|
294
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
295
|
+
"find": ["\t\tmarker.backend !== \"claude-code\" ||", "\t\tmarker.nativeSessionId !== identity.nativeSessionId"],
|
|
296
|
+
"replace": ["\t\tmarker.backend !== \"claude-code\" ||", "\t\tfalse"],
|
|
297
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
298
|
+
"timeoutSeconds": 60,
|
|
299
|
+
"signature": "[QK:V2RESUME-CC-MISMATCH-REFUSED]",
|
|
300
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"claim": "V2RESUME-CC-OBSERVES-NEW-OWNER",
|
|
304
|
+
"title": "the observation accepts the previous owner's marker as the resumed session coming back",
|
|
305
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
306
|
+
"find": [
|
|
307
|
+
"\t\t\t(seen.marker.ownerPid !== previous.ownerPid || seen.marker.ownerStartKey !== previous.ownerStartKey) &&"
|
|
308
|
+
],
|
|
309
|
+
"replace": ["\t\t\ttrue &&"],
|
|
310
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
311
|
+
"timeoutSeconds": 60,
|
|
312
|
+
"signature": "[QK:V2RESUME-CC-OBSERVES-NEW-OWNER]",
|
|
313
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"claim": "V2RESUME-CC-RECORD-DRIFT-UNOBSERVED",
|
|
317
|
+
"title": "the observation stops checking that the record still names the same session with the same createdAt",
|
|
318
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
319
|
+
"find": ["\t\t\t\tcurrent.createdAt === identity.createdAt &&"],
|
|
320
|
+
"replace": ["\t\t\t\ttrue &&"],
|
|
321
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
322
|
+
"timeoutSeconds": 60,
|
|
323
|
+
"signature": "[QK:V2RESUME-CC-RECORD-DRIFT-UNOBSERVED]",
|
|
324
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"claim": "V2RESUME-CC-MARKER-READ-RAW",
|
|
328
|
+
"title": "the receiver marker is read through a path that follows symlinks instead of the no-follow fd reader, so a link to another citizen's marker answers for this one",
|
|
329
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
330
|
+
"find": ["\t\tbytes = readStoreRecordFile(markerPath);"],
|
|
331
|
+
"replace": ["\t\tbytes = process.getBuiltinModule(\"node:fs\").readFileSync(markerPath, \"utf8\");"],
|
|
332
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
333
|
+
"timeoutSeconds": 60,
|
|
334
|
+
"signature": "[QK:V2RESUME-CC-MARKER-READ-RAW]",
|
|
335
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"claim": "V2RESUME-PI-NEVER-READS-RECEIVER",
|
|
339
|
+
"title": "the pi path consults a Claude Code receiver marker, mixing the two backends' dormancy proofs",
|
|
340
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
341
|
+
"find": ["\t\tconst launched = deps.launch({ backend: \"pi\", cwd: identity.cwd, runtimeArgs });"],
|
|
342
|
+
"replace": [
|
|
343
|
+
"\t\tdeps.inspectReceiver(targetGardenId);",
|
|
344
|
+
"\t\tconst launched = deps.launch({ backend: \"pi\", cwd: identity.cwd, runtimeArgs });"
|
|
345
|
+
],
|
|
346
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
347
|
+
"timeoutSeconds": 60,
|
|
348
|
+
"signature": "[QK:V2RESUME-PI-NEVER-READS-RECEIVER]",
|
|
349
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"claim": "V2RESUME-CC-RENDER",
|
|
353
|
+
"title": "the Claude Code launch receipt stops saying it asked for claude --resume, so a reader cannot tell which session the window was asked to open",
|
|
354
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
355
|
+
"find": [
|
|
356
|
+
"\t\t\t\t`LAUNCH receipt: tmux created that window and was asked to start claude --resume on the session above.\\n` +"
|
|
357
|
+
],
|
|
358
|
+
"replace": ["\t\t\t\t`LAUNCH receipt: tmux created that window.\\n` +"],
|
|
359
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
360
|
+
"timeoutSeconds": 60,
|
|
361
|
+
"signature": "[QK:V2RESUME-CC-RENDER]",
|
|
362
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
"claim": "V2RESUME-CC-OBSERVE-HELPER-BOUNDED",
|
|
366
|
+
"title": "the Claude Code observation's deadline reports the previous owner as re-armed instead of unobserved",
|
|
367
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
368
|
+
"find": ["\t\t\treturn { kind: \"resume-unobserved\", waitedMs: deps.now() - started };"],
|
|
369
|
+
"replace": [
|
|
370
|
+
"\t\t\treturn { kind: \"receiver-armed\", ownerPid: previous.ownerPid, waitedMs: deps.now() - started };"
|
|
371
|
+
],
|
|
372
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
373
|
+
"timeoutSeconds": 60,
|
|
374
|
+
"signature": "[QK:V2RESUME-CC-OBSERVE-HELPER-BOUNDED]",
|
|
375
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"claim": "V2RESUME-CC-BINDING-REREAD",
|
|
379
|
+
"title": "the binding is compared against the FIRST record read, so an arm committed between that read and the dead verdict is bound by a stale value",
|
|
380
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
381
|
+
"find": ["\tconst current = deps.resolveIdentity(targetGardenId);"],
|
|
382
|
+
"replace": ["\tconst current = identity;"],
|
|
383
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
384
|
+
"timeoutSeconds": 60,
|
|
385
|
+
"signature": "[QK:V2RESUME-CC-BINDING-REREAD]",
|
|
386
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"claim": "V2RESUME-CC-UNBOUND-LEGACY",
|
|
390
|
+
"title": "a record or marker with no binding (null) passes the binding check, so null == null reads as a match",
|
|
391
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
392
|
+
"find": ["\tif (current.attachIncarnation === null || marker.attachIncarnation === null) {"],
|
|
393
|
+
"replace": ["\tif (false) {"],
|
|
394
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
395
|
+
"timeoutSeconds": 60,
|
|
396
|
+
"signature": "[QK:V2RESUME-CC-UNBOUND-LEGACY]",
|
|
397
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
"claim": "V2RESUME-CC-UNBOUND-STALE",
|
|
401
|
+
"title": "a dead marker whose binding is older than the record's still authorises a launch",
|
|
402
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
403
|
+
"find": ["\tif (current.attachIncarnation !== marker.attachIncarnation) {"],
|
|
404
|
+
"replace": ["\tif (false) {"],
|
|
405
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
406
|
+
"timeoutSeconds": 60,
|
|
407
|
+
"signature": "[QK:V2RESUME-CC-UNBOUND-STALE]",
|
|
408
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"claim": "V2RESUME-CC-UNBOUND-RECORD-MOVED",
|
|
412
|
+
"title": "a record whose createdAt changed between the two reads is still bound",
|
|
413
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
414
|
+
"find": ["\t\tcurrent.createdAt !== identity.createdAt"],
|
|
415
|
+
"replace": ["\t\tfalse"],
|
|
416
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
417
|
+
"timeoutSeconds": 60,
|
|
418
|
+
"signature": "[QK:V2RESUME-CC-UNBOUND-RECORD-MOVED]",
|
|
419
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"claim": "V2RESUME-CC-OBSERVE-PANE-JOIN",
|
|
423
|
+
"title": "the observation accepts a live owner anywhere, not only the pane this call opened",
|
|
424
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
425
|
+
"find": ["\t\t\tString(seen.marker.ownerPid) === panePid &&"],
|
|
426
|
+
"replace": [""],
|
|
427
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
428
|
+
"timeoutSeconds": 60,
|
|
429
|
+
"signature": "[QK:V2RESUME-CC-OBSERVE-PANE-JOIN]",
|
|
430
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"claim": "V2RESUME-CC-OBSERVE-BACKEND",
|
|
434
|
+
"title": "the observation accepts a live receiver marker of another backend",
|
|
435
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
436
|
+
"find": ["\t\t\tseen.marker.backend === \"claude-code\" &&"],
|
|
437
|
+
"replace": [""],
|
|
438
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
439
|
+
"timeoutSeconds": 60,
|
|
440
|
+
"signature": "[QK:V2RESUME-CC-OBSERVE-BACKEND]",
|
|
441
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"claim": "V2RESUME-CC-OBSERVE-FRESH-BINDING",
|
|
445
|
+
"title": "the observation accepts a new owner still showing the binding the dormancy proof bound",
|
|
446
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
447
|
+
"find": ["\t\t\tseen.marker.attachIncarnation !== previous.attachIncarnation"],
|
|
448
|
+
"replace": ["\t\t\ttrue"],
|
|
449
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
450
|
+
"timeoutSeconds": 60,
|
|
451
|
+
"signature": "[QK:V2RESUME-CC-OBSERVE-FRESH-BINDING]",
|
|
452
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"claim": "V2RESUME-CC-OBSERVE-RECORD-BINDING",
|
|
456
|
+
"title": "the observation stops requiring the current record to carry the marker's binding",
|
|
457
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
458
|
+
"find": ["\t\t\t\tcurrent.attachIncarnation === seen.marker.attachIncarnation"],
|
|
459
|
+
"replace": ["\t\t\t\ttrue"],
|
|
460
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
461
|
+
"timeoutSeconds": 60,
|
|
462
|
+
"signature": "[QK:V2RESUME-CC-OBSERVE-RECORD-BINDING]",
|
|
463
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
"claim": "V2RESUME-CC-OBSERVE-RECORD-UNREADABLE",
|
|
467
|
+
"title": "a record defect during the observation is swallowed into the bounded wait instead of stopping it as record-unreadable",
|
|
468
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
469
|
+
"find": [
|
|
470
|
+
"\t\t\t\treturn {",
|
|
471
|
+
"\t\t\t\t\tkind: \"record-unreadable\",",
|
|
472
|
+
"\t\t\t\t\tcause: err instanceof Error ? err.message : String(err),",
|
|
473
|
+
"\t\t\t\t\twaitedMs: deps.now() - started,",
|
|
474
|
+
"\t\t\t\t};"
|
|
475
|
+
],
|
|
476
|
+
"replace": ["\t\t\t\tcurrent = identity;"],
|
|
477
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
478
|
+
"timeoutSeconds": 60,
|
|
479
|
+
"signature": "[QK:V2RESUME-CC-OBSERVE-RECORD-UNREADABLE]",
|
|
480
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"claim": "V2RESUME-CC-MARKER-BINDING-READ",
|
|
484
|
+
"title": "the receiver-marker validator drops the marker's binding, so every marker reads as unbound",
|
|
485
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
486
|
+
"find": [
|
|
487
|
+
"\t\tattachIncarnation: requireAttachIncarnation(raw.attachIncarnation === undefined ? null : raw.attachIncarnation),"
|
|
488
|
+
],
|
|
489
|
+
"replace": ["\t\tattachIncarnation: null,"],
|
|
490
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
491
|
+
"timeoutSeconds": 60,
|
|
492
|
+
"signature": "[QK:V2RESUME-CC-MARKER-BINDING-READ]",
|
|
493
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
224
494
|
}
|
|
225
495
|
]
|
|
226
496
|
}
|
|
@@ -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
|
|
@@ -89,7 +89,7 @@ if [ "${REVIEW_ENV:-}" = "fail" ]; then echo configured-env-failure >&2; exit 24
|
|
|
89
89
|
while IFS= read -r line; do
|
|
90
90
|
case "$line" in
|
|
91
91
|
*'"id":1'*) printf '%s\n' '{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{},"serverInfo":{"name":"fake-entwurf-bridge","version":"0"}}}' ;;
|
|
92
|
-
*'"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"}]}}' ;;
|
|
92
|
+
*'"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"}]}}' ;;
|
|
93
93
|
esac
|
|
94
94
|
done
|
|
95
95
|
FAKE
|
|
@@ -26,7 +26,7 @@ write_mcp_fake() {
|
|
|
26
26
|
while IFS= read -r line; do
|
|
27
27
|
case "$line" in
|
|
28
28
|
*'"id":1'*) printf '%s\n' '{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{},"serverInfo":{"name":"fake-entwurf-bridge","version":"0"}}}' ;;
|
|
29
|
-
*'"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"}]}}' ;;
|
|
29
|
+
*'"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"}]}}' ;;
|
|
30
30
|
esac
|
|
31
31
|
done
|
|
32
32
|
FAKE
|
|
@@ -490,8 +490,8 @@ for (const name of ["entwurf", "entwurf-bridge", "entwurf-statusline"]) {
|
|
|
490
490
|
}
|
|
491
491
|
|
|
492
492
|
// 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 (`
|
|
494
|
-
// zero exit here is the artifact listing all
|
|
493
|
+
// 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
|
|
494
|
+
// zero exit here is the artifact listing all nine garden verbs and no tenth.
|
|
495
495
|
const run = spawnSync(path.join(binDir, "entwurf"), ["check-bridge"], { encoding: "utf8" });
|
|
496
496
|
const said = `${run.stdout ?? ""}${run.stderr ?? ""}`;
|
|
497
497
|
// [a-z0-9_] and not [a-z_]: the first draft of this line printed `entwurf_v` for entwurf_v2
|
|
@@ -502,7 +502,7 @@ const verbs = (said.match(/entwurf_[a-z0-9_]+/g) ?? []).filter((v, i, a) => a.in
|
|
|
502
502
|
// A SECOND, INDEPENDENT COPY OF THE SET, ON PURPOSE (A5 D1). The exit code alone used to be
|
|
503
503
|
// the oracle here, which left the printed list as decoration a parser bug could quietly
|
|
504
504
|
// corrupt — and did, see the regex note just above. The package under test carries the
|
|
505
|
-
// expectation of run.sh
|
|
505
|
+
// `validate_entwurf_bridge` expectation of run.sh in its own bytes, so reading the answer from there would let
|
|
506
506
|
// the artifact grade itself. The literal below is a copy that must AGREE with the shipped
|
|
507
507
|
// one; the two disagreeing is the signal, and a verb genuinely added upstream reddens this
|
|
508
508
|
// smoke until somebody says so here too.
|
|
@@ -513,6 +513,7 @@ const EXPECTED_VERBS = [
|
|
|
513
513
|
"entwurf_peers",
|
|
514
514
|
"entwurf_register_native",
|
|
515
515
|
"entwurf_resume_call",
|
|
516
|
+
"entwurf_retire_call",
|
|
516
517
|
"entwurf_self",
|
|
517
518
|
"entwurf_v2",
|
|
518
519
|
];
|
|
@@ -520,7 +521,7 @@ console.log(` VERBS ${verbs.join(",") || "<none>"}`);
|
|
|
520
521
|
if (run.status === 0) ok(`entwurf check-bridge exit 0 from the installed bin (${verbs.length} verbs listed)`);
|
|
521
522
|
else no(`entwurf check-bridge exit ${run.status}: ${said.trim().slice(0, 400)}`);
|
|
522
523
|
JSON.stringify(verbs) === JSON.stringify(EXPECTED_VERBS)
|
|
523
|
-
? ok(`the receipt names EXACTLY the
|
|
524
|
+
? ok(`the receipt names EXACTLY the nine garden verbs (${EXPECTED_VERBS.length}), parsed from what the installed bin answered`)
|
|
524
525
|
: no(`verb set mismatch — want ${JSON.stringify(EXPECTED_VERBS)} got ${JSON.stringify(verbs)}`);
|
|
525
526
|
process.exit(bad);
|
|
526
527
|
' "$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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
38
|
-
*
|
|
39
|
-
* no window opened and no lock residue after the per-gid coordination lock is
|
|
40
|
-
*
|
|
41
|
-
* resume
|
|
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
|
-
//
|
|
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-
|
|
1044
|
-
ccResume.isError && ccResume.text.includes("target-
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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"
|