@junghanacs/entwurf 0.14.2 → 0.15.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 (87) hide show
  1. package/AGENTS.md +9 -5
  2. package/CHANGELOG.md +149 -0
  3. package/DELIVERY.md +72 -59
  4. package/README.md +120 -20
  5. package/VERIFY.md +10 -7
  6. package/demo/README.md +1 -1
  7. package/docs/acp-backend-rail.md +2 -2
  8. package/docs/external-mcp-host.md +26 -4
  9. package/docs/setup-clean-host.md +118 -18
  10. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +8 -6
  11. package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/copilot-fresh-preflight.js +253 -0
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +10 -2
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +102 -28
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +77 -11
  16. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook-copilot.js +288 -0
  17. package/mcp/entwurf-bridge/src/index.ts +10 -6
  18. package/mcp/entwurf-bridge/tsconfig.build.json +2 -1
  19. package/package.json +22 -11
  20. package/pi/copilot-receive/entwurf-receive/extension.mjs +323 -0
  21. package/pi/entwurf-capabilities.json +1 -0
  22. package/pi/meta-bridge-copilot/.claude-plugin/marketplace.json +11 -0
  23. package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/.claude-plugin/plugin.json +5 -0
  24. package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/hooks/hooks.json +7 -0
  25. package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/scripts/copilot-hook-launch.sh +85 -0
  26. package/pi-extensions/entwurf-control.ts +17 -8
  27. package/pi-extensions/lib/copilot-fresh-preflight.ts +251 -0
  28. package/pi-extensions/lib/meta-sender-identity.ts +10 -2
  29. package/pi-extensions/lib/meta-session.ts +102 -29
  30. package/pi-extensions/lib/mux-fresh-call.ts +82 -11
  31. package/pi-extensions/meta-bridge-hook-copilot.ts +323 -0
  32. package/run.sh +1079 -186
  33. package/scripts/agy-bridge.sh +4 -2
  34. package/scripts/check-copilot-birth-hook.ts +1174 -0
  35. package/scripts/check-copilot-launch.ts +395 -0
  36. package/scripts/check-copilot-receive-arm.ts +734 -0
  37. package/scripts/check-copilot-statusline.ts +122 -0
  38. package/scripts/check-entwurf-capabilities.ts +25 -6
  39. package/scripts/check-fresh-cut-gate.sh +104 -27
  40. package/scripts/check-gate-qualification.ts +10 -1
  41. package/scripts/check-install-container.sh +2 -2
  42. package/scripts/check-install-surface.ts +1 -1
  43. package/scripts/check-meta-capability-source.ts +89 -5
  44. package/scripts/check-meta-doctor-oracle.sh +26 -0
  45. package/scripts/check-meta-manifest-schema.py +38 -0
  46. package/scripts/check-meta-receiver-marker.ts +25 -2
  47. package/scripts/check-meta-session.ts +32 -0
  48. package/scripts/check-setup-qualification.sh +126 -0
  49. package/scripts/copilot-bridge-doctor.sh +242 -0
  50. package/scripts/copilot-bridge-install.sh +384 -0
  51. package/scripts/copilot-bridge-oracle.sh +223 -0
  52. package/scripts/copilot-bridge-uninstall.sh +137 -0
  53. package/scripts/copilot-launch.sh +236 -0
  54. package/scripts/copilot-mcp-bridge.sh +177 -0
  55. package/scripts/copilot-mcp-config.py +221 -0
  56. package/scripts/copilot-receive-bridge.sh +483 -0
  57. package/scripts/copilot-statusline-bridge.sh +149 -0
  58. package/scripts/copilot-statusline-config.py +201 -0
  59. package/scripts/copilot-statusline.sh +68 -0
  60. package/scripts/dev-bin.sh +53 -9
  61. package/scripts/fake-copilot-vendor.sh +67 -0
  62. package/scripts/meta-bridge-hook-log.sh +17 -5
  63. package/scripts/mutants/capability-cache.json +64 -0
  64. package/scripts/mutants/copilot-birth.json +244 -0
  65. package/scripts/mutants/copilot-launch.json +187 -0
  66. package/scripts/mutants/copilot-receive.json +263 -0
  67. package/scripts/mutants/fresh-cut.json +17 -0
  68. package/scripts/mutants/mux-fresh-call.json +216 -2
  69. package/scripts/mutants/pack-install.json +17 -0
  70. package/scripts/mutants/pi-package-ownership.json +92 -0
  71. package/scripts/mutants/setup-verdict.json +148 -0
  72. package/scripts/mutants/source-install.json +32 -0
  73. package/scripts/pi_settings_io.py +22 -0
  74. package/scripts/raw-async-delivery/README.md +170 -125
  75. package/scripts/raw-async-delivery/copilot-enqueue-addressed.sh +35 -0
  76. package/scripts/raw-async-delivery/copilot-extension-receive/extension.mjs +123 -0
  77. package/scripts/register-pi-package.py +525 -7
  78. package/scripts/register-pi-provider.py +162 -12
  79. package/scripts/smoke-agy-install-state.sh +86 -30
  80. package/scripts/smoke-agy-statusline-state.sh +9 -6
  81. package/scripts/smoke-copilot-mcp-state.sh +153 -0
  82. package/scripts/smoke-copilot-statusline-state.sh +131 -0
  83. package/scripts/smoke-mux-fresh-call-live.ts +2 -0
  84. package/scripts/smoke-mux-lifecycle-live.ts +3 -1
  85. package/scripts/smoke-setup-verdict.sh +291 -0
  86. package/scripts/smoke-user-scope-citizen.sh +388 -1
  87. package/scripts/tsconfig.json +1 -0
@@ -0,0 +1,244 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "copilot-birth",
4
+ "mutants": [
5
+ {
6
+ "claim": "COPILOT-BIRTH-NO-ARGV-LAUNCH",
7
+ "title": "reusing the Claude no-argv refusal in the Copilot launcher kills every Copilot birth (this is the exact defect that held copilot at 0 of 409 records)",
8
+ "subject": "pi/meta-bridge-copilot/entwurf-meta-receive-copilot/scripts/copilot-hook-launch.sh",
9
+ "find": ["exec \"$NODE_BIN\" \"$HOOK_ENTRY\""],
10
+ "replace": [
11
+ "if [ \"$#\" -eq 0 ]; then",
12
+ "\techo 'entwurf meta-bridge: this hook was launched with NO arguments.' >&2",
13
+ "\texit 1",
14
+ "fi",
15
+ "exec \"$NODE_BIN\" \"$HOOK_ENTRY\""
16
+ ],
17
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
18
+ "timeoutSeconds": 300,
19
+ "signature": "[QK:COPILOT-BIRTH-NO-ARGV-LAUNCH]",
20
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
21
+ },
22
+ {
23
+ "claim": "COPILOT-BIRTH-MINTS-COPILOT",
24
+ "title": "minting a Copilot session under the claude-code backend gives it a citizenship it cannot own and hides the Copilot lane's own count",
25
+ "subject": "pi-extensions/meta-bridge-hook-copilot.ts",
26
+ "find": ["\t\t\tinput: { backend: \"copilot\", nativeSessionId: envelope.sessionId, cwd: envelope.cwd },"],
27
+ "replace": ["\t\t\tinput: { backend: \"claude-code\", nativeSessionId: envelope.sessionId, cwd: envelope.cwd },"],
28
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
29
+ "timeoutSeconds": 300,
30
+ "signature": "[QK:COPILOT-BIRTH-MINTS-COPILOT]",
31
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
32
+ },
33
+ {
34
+ "claim": "COPILOT-BIRTH-ID-DISAGREEMENT",
35
+ "title": "preferring one id when the two envelope keys disagree mints a citizen no live session can be joined back to",
36
+ "subject": "pi-extensions/meta-bridge-hook-copilot.ts",
37
+ "find": [
38
+ "\tif (native && compat && native !== compat) {",
39
+ "\t\treturn { refusal: `sessionId and session_id disagree (${native} vs ${compat})` };",
40
+ "\t}"
41
+ ],
42
+ "replace": ["\t// disagreement tolerated: the native key simply wins"],
43
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
44
+ "timeoutSeconds": 300,
45
+ "signature": "[QK:COPILOT-BIRTH-ID-DISAGREEMENT]",
46
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
47
+ },
48
+ {
49
+ "claim": "COPILOT-BIRTH-EXEC-IS-STRING",
50
+ "title": "declaring the Copilot hook in Claude's array form is rejected at plugin load, before any prompt — the plugin never runs at all",
51
+ "subject": "pi/meta-bridge-copilot/entwurf-meta-receive-copilot/hooks/hooks.json",
52
+ "find": ["\t\t\"sessionStart\": [{ \"exec\": \"__COPILOT_LAUNCHER__\" }],"],
53
+ "replace": ["\t\t\"sessionStart\": [{ \"exec\": [\"__COPILOT_LAUNCHER__\"] }],"],
54
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
55
+ "timeoutSeconds": 300,
56
+ "signature": "[QK:COPILOT-BIRTH-EXEC-IS-STRING]",
57
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
58
+ },
59
+ {
60
+ "claim": "CAPABILITY-DRIFT-SCOPE-FROM-CONST",
61
+ "title": "a literal lane list in the capability drift guard lets any new backend's descriptor ship without ever being compared — the hole #82 found and closed",
62
+ "subject": "scripts/check-entwurf-capabilities.ts",
63
+ "find": ["const driftScope: readonly MetaBackend[] = META_BACKENDS;"],
64
+ "replace": ["const driftScope: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"codex\"];"],
65
+ "gate": ["bash", "run.sh", "check-entwurf-capabilities"],
66
+ "timeoutSeconds": 300,
67
+ "signature": "[QK:CAPABILITY-DRIFT-SCOPE-FROM-CONST]",
68
+ "signatureSource": "scripts/check-entwurf-capabilities.ts"
69
+ },
70
+ {
71
+ "claim": "COPILOT-INSTALL-QUALIFIED-STALE",
72
+ "title": "a BARE stale-unit name reaches a same-named plugin from somebody else's marketplace and uninstalls it",
73
+ "subject": "scripts/copilot-bridge-install.sh",
74
+ "find": ["STALE_CLAUDE_UNIT=\"entwurf-meta-receive@meta-bridge-local\""],
75
+ "replace": ["STALE_CLAUDE_UNIT=\"entwurf-meta-receive\""],
76
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
77
+ "timeoutSeconds": 300,
78
+ "signature": "[QK:COPILOT-INSTALL-QUALIFIED-STALE]",
79
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
80
+ },
81
+ {
82
+ "claim": "COPILOT-INSTALL-UNINSTALL-FAILURE-IS-FATAL",
83
+ "title": "swallowing a failed stale-unit uninstall installs on top of a unit that is still firing and reports success",
84
+ "subject": "scripts/copilot-bridge-install.sh",
85
+ "find": [
86
+ " copilot plugin uninstall \"$STALE_CLAUDE_UNIT\" >/dev/null \\",
87
+ " || die \"the stale Claude unit '$STALE_CLAUDE_UNIT' is installed in Copilot but could not be removed. It fires on every prompt and exits 1 before node starts, so installing on top of it would leave that noise in place. Fix the Copilot CLI error above, or re-run with --keep-stale-claude-unit to proceed deliberately.\""
88
+ ],
89
+ "replace": [" copilot plugin uninstall \"$STALE_CLAUDE_UNIT\" >/dev/null 2>&1 || true"],
90
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
91
+ "timeoutSeconds": 300,
92
+ "signature": "[QK:COPILOT-INSTALL-UNINSTALL-FAILURE-IS-FATAL]",
93
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
94
+ },
95
+ {
96
+ "claim": "HOOK-LOG-RAIL-SCOPED",
97
+ "title": "an untagged ERROR grep lets a Copilot fail-closed refusal redden the CLAUDE doctor forever — copilot's recovery token cannot exist on that rail",
98
+ "subject": "scripts/meta-bridge-hook-log.sh",
99
+ "find": [" own=\"$(grep -v ' \\[copilot\\] ' \"$log\" 2>/dev/null || true)\""],
100
+ "replace": [" own=\"$(cat \"$log\" 2>/dev/null || true)\""],
101
+ "gate": ["bash", "run.sh", "check-meta-doctor-oracle"],
102
+ "timeoutSeconds": 600,
103
+ "signature": "[QK:HOOK-LOG-RAIL-SCOPED]",
104
+ "signatureSource": "scripts/check-meta-doctor-oracle.sh"
105
+ },
106
+ {
107
+ "claim": "COPILOT-BIRTH-DOES-NOT-ARM-RECEIVER",
108
+ "title": "arming a mailbox from the BIRTH hook claims a watch this process does not hold. Copilot now has a doorbell (#82 RAIL 5), which is exactly why the writer matters: the extension owns the watch, so a marker minted here would name the host pid as a watcher and keep a wired-to-nothing citizen deliverable for as long as the TUI stayed open",
109
+ "subject": "pi-extensions/meta-bridge-hook-copilot.ts",
110
+ "find": ["\t\tlogLine(\n\t\t\t\"INFO\","],
111
+ "replace": [
112
+ "\t\tfs.mkdirSync(path.join(path.dirname(defaultMetaSessionsDir()), \"meta-mailbox\", result.record.gardenId), { recursive: true });\n\t\tlogLine(\n\t\t\t\"INFO\","
113
+ ],
114
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
115
+ "timeoutSeconds": 300,
116
+ "signature": "[QK:COPILOT-BIRTH-DOES-NOT-ARM-RECEIVER]",
117
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
118
+ },
119
+ {
120
+ "claim": "COPILOT-BIRTH-WRITES-SENDER-MARKER",
121
+ "title": "dropping the sender-marker write leaves the reader open and the writer closed — the citizen calls entwurf_v2, the bridge holds its owner pid, finds no marker, and the send is refused as anonymous with nothing in any log naming the cause (the #46 defect, re-planted on the copilot rail)",
122
+ "subject": "pi-extensions/meta-bridge-hook-copilot.ts",
123
+ "find": ["\t\twriteCopilotSenderMarker(result.record.gardenId, envelope);"],
124
+ "replace": ["\t\t// sender marker skipped"],
125
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
126
+ "timeoutSeconds": 300,
127
+ "signature": "[QK:COPILOT-BIRTH-WRITES-SENDER-MARKER]",
128
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
129
+ },
130
+ {
131
+ "claim": "COPILOT-SENDER-READER-OPEN",
132
+ "title": "closing the reader half leaves the writer talking to nobody — the hook writes a copilot marker, the bridge never looks in that directory, and the citizen's sends are refused as anonymous (the #46 shape, which is why writer and reader open in one change)",
133
+ "subject": "pi-extensions/lib/meta-sender-identity.ts",
134
+ "find": [
135
+ "export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"copilot\"];"
136
+ ],
137
+ "replace": ["export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\"];"],
138
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
139
+ "timeoutSeconds": 300,
140
+ "signature": "[QK:COPILOT-SENDER-READER-OPEN]",
141
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
142
+ },
143
+ {
144
+ "claim": "COPILOT-INSTALL-LIST-FAILURE-IS-FATAL",
145
+ "title": "reading a failed `copilot plugin list` as an empty host installs on top of a stale unit that is still firing",
146
+ "subject": "scripts/copilot-bridge-install.sh",
147
+ "find": [" if ! INSTALLED_LIST=\"$(copilot plugin list 2>/dev/null)\"; then"],
148
+ "replace": [" INSTALLED_LIST=\"$(copilot plugin list 2>/dev/null || true)\"", " if false; then"],
149
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
150
+ "timeoutSeconds": 300,
151
+ "signature": "[QK:COPILOT-INSTALL-LIST-FAILURE-IS-FATAL]",
152
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
153
+ },
154
+ {
155
+ "claim": "COPILOT-BIRTH-INVERSE-NO-STATE",
156
+ "title": "the inverse runs as a blind best-effort remove with NO ownership state, deleting vendor registrations this package cannot prove it owns",
157
+ "subject": "scripts/copilot-bridge-uninstall.sh",
158
+ "find": [
159
+ "[ -f \"$STATE_FILE\" ] || die \"no ownership state at $STATE_FILE — nothing this package provably owns to remove. A legacy no-state installation is adopted by './run.sh install-copilot-bridge' first, then removed.\""
160
+ ],
161
+ "replace": [
162
+ "[ -f \"$STATE_FILE\" ] || { copilot plugin uninstall \"$QUALIFIED\" >/dev/null 2>&1 || true; copilot plugin marketplace remove \"$MKT_NAME\" >/dev/null 2>&1 || true; rm -rf \"$ASM\"; exit 0; }"
163
+ ],
164
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
165
+ "timeoutSeconds": 300,
166
+ "signature": "[QK:COPILOT-BIRTH-INVERSE-NO-STATE]",
167
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
168
+ },
169
+ {
170
+ "claim": "COPILOT-BIRTH-INVERSE-FOREIGN",
171
+ "title": "the inverse removes a marketplace that carries our name but is registered at ANOTHER path — someone else's registration deleted by our uninstall",
172
+ "subject": "scripts/copilot-bridge-uninstall.sh",
173
+ "find": [
174
+ " if [ \"$MKT_PATH\" != \"$ASM\" ]; then\n die \"a marketplace named '$MKT_NAME' is registered at '$MKT_PATH', not at the recorded assembly ($ASM). That registration is not provably ours — refusing with zero vendor/filesystem writes; inspect 'copilot plugin marketplace list' manually.\"\n fi"
175
+ ],
176
+ "replace": [" :"],
177
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
178
+ "timeoutSeconds": 300,
179
+ "signature": "[QK:COPILOT-BIRTH-INVERSE-FOREIGN]",
180
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
181
+ },
182
+ {
183
+ "claim": "COPILOT-MKT-DUPLICATE-REFUSED",
184
+ "title": "the marketplace-row parser silently returns the FIRST of several same-named rows instead of refusing the ambiguity — the retired grep|head -1 behavior, re-planted: a second marketplace with our name steers every path check at whichever row happens to print first (#86 C3a corrective amendment, B defect 2)",
185
+ "subject": "scripts/copilot-bridge-oracle.sh",
186
+ "find": [
187
+ "if len(paths) > 1:\n print(f\"multiple marketplace rows named {name}: paths {paths} — duplicates are ambiguity nobody may act on\", file=sys.stderr)\n sys.exit(1)\nprint(f\"one {paths[0]}\" if paths else \"absent\")"
188
+ ],
189
+ "replace": ["print(f\"one {paths[0]}\" if paths else \"absent\")"],
190
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
191
+ "timeoutSeconds": 300,
192
+ "signature": "[QK:COPILOT-MKT-DUPLICATE-REFUSED]",
193
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
194
+ },
195
+ {
196
+ "claim": "COPILOT-MALFORMED-ROW-NOT-ABSENT",
197
+ "title": "a truncated/garbled exact plugin row falls through the parser and rounds to ABSENT, which the inverse reads as retry-safe absence and continues past — the exact fall-through B reproduced (`(v0.1` with no closing paren) against 47a5ae3 (#86 C3a corrective amendment, B defect 3)",
198
+ "subject": "scripts/copilot-bridge-oracle.sh",
199
+ "find": [
200
+ " if not (rest.startswith(\"(v\") and rest.endswith(\")\")):\n print(f\"malformed exact row for {qualified}: {row!r} does not parse as '<qualified> (v<version>)'\", file=sys.stderr)\n sys.exit(1)"
201
+ ],
202
+ "replace": [" if not (rest.startswith(\"(v\") and rest.endswith(\")\")):\n continue"],
203
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
204
+ "timeoutSeconds": 300,
205
+ "signature": "[QK:COPILOT-MALFORMED-ROW-NOT-ABSENT]",
206
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
207
+ },
208
+ {
209
+ "claim": "COPILOT-STATE-VERSION-WHITESPACE",
210
+ "title": "the state validator accepts a pluginVersion carrying whitespace, so the space-separated fact transport (`cut -d' ' -f3`) truncates it into a FABRICATED version and consumers act on a value the state never recorded (#86 C3a corrective amendment, B defect 4)",
211
+ "subject": "scripts/copilot-bridge-oracle.sh",
212
+ "find": ["if any(ord(c) < 0x21 or ord(c) == 0x7f for c in state[\"pluginVersion\"]):"],
213
+ "replace": ["if False and state[\"pluginVersion\"]:"],
214
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
215
+ "timeoutSeconds": 300,
216
+ "signature": "[QK:COPILOT-STATE-VERSION-WHITESPACE]",
217
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
218
+ },
219
+ {
220
+ "claim": "COPILOT-DOCTOR-ORACLE-CONSUMED",
221
+ "title": "the doctor's structural verdict stops consulting the shared oracle and reads every assembly as green, so a unit install/adopt would refuse (broken hooks.json, unbaked launcher) doctors as healthy — the second-parser drift B flagged, taken to its end state (#86 C3a corrective amendment, B defect 1)",
222
+ "subject": "scripts/copilot-bridge-doctor.sh",
223
+ "find": ["if ORACLE_REASON=\"$(copilot_assembly_valid \"$ASM\" \"$PLUGIN\" 2>&1)\"; then"],
224
+ "replace": ["if ORACLE_REASON=\"\"; then"],
225
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
226
+ "timeoutSeconds": 300,
227
+ "signature": "[QK:COPILOT-DOCTOR-ORACLE-CONSUMED]",
228
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
229
+ },
230
+ {
231
+ "claim": "COPILOT-BIRTH-NO-FALSE-ABSENCE",
232
+ "title": "the inverse reads a FAILING `copilot plugin list` as an empty host and reports a clean removal over a host whose real contents nobody read",
233
+ "subject": "scripts/copilot-bridge-uninstall.sh",
234
+ "find": [
235
+ "if ! INSTALLED_LIST=\"$(copilot plugin list 2>/dev/null)\"; then\n die \"'copilot plugin list' failed, so this host's installed plugins are UNKNOWN — refusing with zero writes. Fix the Copilot CLI error and re-run.\"\nfi"
236
+ ],
237
+ "replace": ["INSTALLED_LIST=\"$(copilot plugin list 2>/dev/null)\" || INSTALLED_LIST=\"\""],
238
+ "gate": ["bash", "run.sh", "check-copilot-birth-hook"],
239
+ "timeoutSeconds": 300,
240
+ "signature": "[QK:COPILOT-BIRTH-NO-FALSE-ABSENCE]",
241
+ "signatureSource": "scripts/check-copilot-birth-hook.ts"
242
+ }
243
+ ]
244
+ }
@@ -0,0 +1,187 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "copilot-launch",
4
+ "mutants": [
5
+ {
6
+ "claim": "COPILOT-LAUNCH-REQUIRES-RECEIVER",
7
+ "title": "launching with the scan flag while no receiver unit is installed promises a doorbell nothing can ring — the session looks managed and is permanently undeliverable, with no error anywhere",
8
+ "subject": "scripts/copilot-launch.sh",
9
+ "find": [
10
+ "[ -f \"$STATE_FILE\" ] \\",
11
+ "\t|| fail \"no receiver install-state at $STATE_FILE.",
12
+ " '$VENDOR_CMD' launched with $FLAG_ENV=$FLAG_VALUE would scan for an extension that is",
13
+ " not there, and the session would never become deliverable. Run: $REPAIR\""
14
+ ],
15
+ "replace": [
16
+ "if [ ! -f \"$STATE_FILE\" ]; then",
17
+ "\tmkdir -p \"$STATE_DIR\"",
18
+ "\tprintf '{\"schemaVersion\":1,\"unit\":\"%s\",\"path\":\"%s\"}\\n' \"$UNIT\" \"$DEST\" > \"$STATE_FILE\"",
19
+ "fi"
20
+ ],
21
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
22
+ "timeoutSeconds": 300,
23
+ "signature": "[QK:COPILOT-LAUNCH-REQUIRES-RECEIVER]",
24
+ "signatureSource": "scripts/check-copilot-launch.ts"
25
+ },
26
+ {
27
+ "claim": "COPILOT-LAUNCH-REFUSES-PATH-MISMATCH",
28
+ "title": "accepting an install-state that names a different extensions root lets the CLI scan a directory nobody installed into, while every artifact check stays green",
29
+ "subject": "scripts/copilot-launch.sh",
30
+ "find": [
31
+ "[ \"$claimed_path\" = \"$DEST\" ] \\",
32
+ "\t|| fail \"receiver install-state points at '$claimed_path' but this environment scans '$DEST'.",
33
+ " The CLI would read a different extensions root than the one that was installed",
34
+ " (COPILOT_EXTENSIONS_DIR / HOME differ from install time). Run: $REPAIR\""
35
+ ],
36
+ "replace": ["# whichever root the state names is close enough"],
37
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
38
+ "timeoutSeconds": 300,
39
+ "signature": "[QK:COPILOT-LAUNCH-REFUSES-PATH-MISMATCH]",
40
+ "signatureSource": "scripts/check-copilot-launch.ts"
41
+ },
42
+ {
43
+ "claim": "COPILOT-LAUNCH-SETS-EXTENSIONS-TOKEN",
44
+ "title": "not guaranteeing the EXTENSIONS token makes the managed launch identical to a plain one — Copilot skips the extension scan silently and the whole surface is decoration",
45
+ "subject": "scripts/copilot-launch.sh",
46
+ "find": ["[ \"$seen_extensions\" -eq 1 ] || flags_out=\"${flags_out:+$flags_out,}$FLAG_VALUE\""],
47
+ "replace": ["# assume the operator already set it"],
48
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
49
+ "timeoutSeconds": 300,
50
+ "signature": "[QK:COPILOT-LAUNCH-SETS-EXTENSIONS-TOKEN]",
51
+ "signatureSource": "scripts/check-copilot-launch.ts"
52
+ },
53
+ {
54
+ "claim": "COPILOT-LAUNCH-PRESERVES-OPERATOR-TOKENS",
55
+ "title": "overwriting the feature-flag variable instead of extending it silently disables every other vendor feature flag the operator had enabled",
56
+ "subject": "scripts/copilot-launch.sh",
57
+ "find": ["export \"$FLAG_ENV=$flags_out\""],
58
+ "replace": ["export \"$FLAG_ENV=$FLAG_VALUE\""],
59
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
60
+ "timeoutSeconds": 300,
61
+ "signature": "[QK:COPILOT-LAUNCH-PRESERVES-OPERATOR-TOKENS]",
62
+ "signatureSource": "scripts/check-copilot-launch.ts"
63
+ },
64
+ {
65
+ "claim": "COPILOT-LAUNCH-DEFAULTS-BEFORE-TERMINATOR",
66
+ "title": "appending the injected defaults after the argv terminator turns them from options into positional data the vendor reads as prompt text, so the managed profile silently stops applying",
67
+ "subject": "scripts/copilot-launch.sh",
68
+ "find": [
69
+ "final_args=()",
70
+ "for (( i = 0; i < scan_end; i++ )); do final_args+=(\"${args[$i]}\"); done",
71
+ "if [ \"${#injected[@]}\" -gt 0 ]; then final_args+=(\"${injected[@]}\"); fi",
72
+ "for (( i = scan_end; i < ${#args[@]}; i++ )); do final_args+=(\"${args[$i]}\"); done"
73
+ ],
74
+ "replace": [
75
+ "final_args=(\"${args[@]}\")",
76
+ "if [ \"${#injected[@]}\" -gt 0 ]; then final_args+=(\"${injected[@]}\"); fi"
77
+ ],
78
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
79
+ "timeoutSeconds": 300,
80
+ "signature": "[QK:COPILOT-LAUNCH-DEFAULTS-BEFORE-TERMINATOR]",
81
+ "signatureSource": "scripts/check-copilot-launch.ts"
82
+ },
83
+ {
84
+ "claim": "COPILOT-LAUNCH-NO-DEFAULT-OVER-EXPLICIT-POLICY",
85
+ "title": "treating only the broadening flags as explicit policy means an operator who NARROWS permissions (--allow-url, --deny-tool, --excluded-tools) still gets --yolo appended — the managed default silently widens exactly what they were restricting",
86
+ "subject": "scripts/copilot-launch.sh",
87
+ "find": ["\t--allow-url", "\t--deny-url", "\t--available-tools", "\t--excluded-tools"],
88
+ "replace": ["\t# narrowing flags are not policy"],
89
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
90
+ "timeoutSeconds": 300,
91
+ "signature": "[QK:COPILOT-LAUNCH-NO-DEFAULT-OVER-EXPLICIT-POLICY]",
92
+ "signatureSource": "scripts/check-copilot-launch.ts"
93
+ },
94
+ {
95
+ "claim": "COPILOT-LAUNCH-PREFIX-IS-NOT-POLICY",
96
+ "title": "matching policy flags by prefix instead of exactly makes --allow-all-mcp-server-instructions read as --allow-all, so a prompt-content flag suppresses the managed permission default",
97
+ "subject": "scripts/copilot-launch.sh",
98
+ "find": ["\t\tif [ \"$head\" = \"$ov\" ]; then"],
99
+ "replace": ["\t\tif case \"$head\" in \"$ov\"*) true ;; *) false ;; esac; then"],
100
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
101
+ "timeoutSeconds": 300,
102
+ "signature": "[QK:COPILOT-LAUNCH-PREFIX-IS-NOT-POLICY]",
103
+ "signatureSource": "scripts/check-copilot-launch.ts"
104
+ },
105
+ {
106
+ "claim": "COPILOT-LAUNCH-KEEPS-OPERATOR-MODEL",
107
+ "title": "injecting the default model regardless of what the operator asked for silently overrides an explicit --model",
108
+ "subject": "scripts/copilot-launch.sh",
109
+ "find": ["\t\thas_model=1"],
110
+ "replace": ["\t\thas_model=0"],
111
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
112
+ "timeoutSeconds": 300,
113
+ "signature": "[QK:COPILOT-LAUNCH-KEEPS-OPERATOR-MODEL]",
114
+ "signatureSource": "scripts/check-copilot-launch.ts"
115
+ },
116
+ {
117
+ "claim": "COPILOT-LAUNCH-EXECS-NOT-FORKS",
118
+ "title": "running the vendor as a child instead of exec'ing it leaves an entwurf shell sitting between the operator's terminal and the CLI, owning a pid and a signal path that belong to the vendor",
119
+ "subject": "scripts/copilot-launch.sh",
120
+ "find": ["exec \"$copilot_bin\" \"${final_args[@]}\""],
121
+ "replace": ["\"$copilot_bin\" \"${final_args[@]}\""],
122
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
123
+ "timeoutSeconds": 300,
124
+ "signature": "[QK:COPILOT-LAUNCH-EXECS-NOT-FORKS]",
125
+ "signatureSource": "scripts/check-copilot-launch.ts"
126
+ },
127
+ {
128
+ "claim": "COPILOT-LAUNCH-REFUSES-RECURSION",
129
+ "title": "dropping the sentinel lets a PATH entry that calls back into the managed launch spin forever; the operator sees a hung terminal, not an error",
130
+ "subject": "scripts/copilot-launch.sh",
131
+ "find": ["if [ -n \"${ENTWURF_COPILOT_LAUNCH_ACTIVE:-}\" ]; then"],
132
+ "replace": ["if false; then"],
133
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
134
+ "timeoutSeconds": 300,
135
+ "signature": "[QK:COPILOT-LAUNCH-REFUSES-RECURSION]",
136
+ "signatureSource": "scripts/check-copilot-launch.ts"
137
+ },
138
+ {
139
+ "claim": "COPILOT-LAUNCH-REFUSES-ABSENT-VENDOR",
140
+ "title": "not checking that the vendor resolved turns a missing CLI into an opaque exec failure instead of the one sentence that says what is missing",
141
+ "subject": "scripts/copilot-launch.sh",
142
+ "find": [
143
+ "[ -n \"$copilot_bin\" ] \\",
144
+ "\t|| fail \"no '$VENDOR_CMD' executable found on PATH.",
145
+ " The managed launch runs the GitHub Copilot CLI; install it, or put it on PATH.\""
146
+ ],
147
+ "replace": ["# an empty resolution will surface itself at exec time"],
148
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
149
+ "timeoutSeconds": 300,
150
+ "signature": "[QK:COPILOT-LAUNCH-REFUSES-ABSENT-VENDOR]",
151
+ "signatureSource": "scripts/check-copilot-launch.ts"
152
+ },
153
+ {
154
+ "claim": "COPILOT-LAUNCH-KEEPS-CALLER-CWD",
155
+ "title": "dispatching the managed launch through the repo-scoped subshell every neighbouring verb uses would start the vendor in the entwurf checkout instead of the operator's own directory",
156
+ "subject": "run.sh",
157
+ "find": [" shift || true", " exec bash \"$REPO_DIR/scripts/copilot-launch.sh\" \"$@\""],
158
+ "replace": [" shift || true", " (cd \"$REPO_DIR\" && bash scripts/copilot-launch.sh \"$@\")"],
159
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
160
+ "timeoutSeconds": 300,
161
+ "signature": "[QK:COPILOT-LAUNCH-KEEPS-CALLER-CWD]",
162
+ "signatureSource": "scripts/check-copilot-launch.ts"
163
+ },
164
+ {
165
+ "claim": "COPILOT-LAUNCH-STRIPS-PI-IDENTITY",
166
+ "title": "the managed launch forwards inherited PI_SESSION_ID/PI_AGENT_ID — the Copilot session and every child it spawns then speak under the PARENT pi citizen's garden id, with a perfectly correct native marker sitting unused beside it",
167
+ "subject": "scripts/copilot-launch.sh",
168
+ "find": ["unset PI_SESSION_ID PI_AGENT_ID\n"],
169
+ "replace": [""],
170
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
171
+ "timeoutSeconds": 300,
172
+ "signature": "[QK:COPILOT-LAUNCH-STRIPS-PI-IDENTITY]",
173
+ "signatureSource": "scripts/check-copilot-launch.ts"
174
+ },
175
+ {
176
+ "claim": "COPILOT-LAUNCH-STRIPS-BOTH-CARRIERS",
177
+ "title": "only one half of the identity pair is cleared — the failure merely changes wording while a carrier stays behind for the next partial reader to believe",
178
+ "subject": "scripts/copilot-launch.sh",
179
+ "find": ["unset PI_SESSION_ID PI_AGENT_ID"],
180
+ "replace": ["unset PI_SESSION_ID"],
181
+ "gate": ["bash", "run.sh", "check-copilot-launch"],
182
+ "timeoutSeconds": 300,
183
+ "signature": "[QK:COPILOT-LAUNCH-STRIPS-BOTH-CARRIERS]",
184
+ "signatureSource": "scripts/check-copilot-launch.ts"
185
+ }
186
+ ]
187
+ }