@junghanacs/entwurf 0.14.2 → 0.15.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 +8 -5
- package/CHANGELOG.md +79 -0
- package/DELIVERY.md +72 -59
- package/README.md +55 -4
- package/VERIFY.md +2 -2
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +26 -4
- package/docs/setup-clean-host.md +3 -3
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +8 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/copilot-fresh-preflight.js +253 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +10 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +102 -28
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +77 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook-copilot.js +288 -0
- package/mcp/entwurf-bridge/src/index.ts +10 -6
- package/mcp/entwurf-bridge/tsconfig.build.json +2 -1
- package/package.json +22 -11
- package/pi/copilot-receive/entwurf-receive/extension.mjs +323 -0
- package/pi/entwurf-capabilities.json +1 -0
- package/pi/meta-bridge-copilot/.claude-plugin/marketplace.json +11 -0
- package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/.claude-plugin/plugin.json +5 -0
- package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/hooks/hooks.json +7 -0
- package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/scripts/copilot-hook-launch.sh +85 -0
- package/pi-extensions/entwurf-control.ts +17 -8
- package/pi-extensions/lib/copilot-fresh-preflight.ts +251 -0
- package/pi-extensions/lib/meta-sender-identity.ts +10 -2
- package/pi-extensions/lib/meta-session.ts +102 -29
- package/pi-extensions/lib/mux-fresh-call.ts +82 -11
- package/pi-extensions/meta-bridge-hook-copilot.ts +323 -0
- package/run.sh +334 -16
- package/scripts/check-copilot-birth-hook.ts +497 -0
- package/scripts/check-copilot-launch.ts +395 -0
- package/scripts/check-copilot-receive-arm.ts +734 -0
- package/scripts/check-copilot-statusline.ts +122 -0
- package/scripts/check-entwurf-capabilities.ts +25 -6
- package/scripts/check-fresh-cut-gate.sh +92 -23
- package/scripts/check-gate-qualification.ts +7 -1
- package/scripts/check-install-container.sh +2 -2
- package/scripts/check-install-surface.ts +1 -1
- package/scripts/check-meta-capability-source.ts +89 -5
- package/scripts/check-meta-doctor-oracle.sh +26 -0
- package/scripts/check-meta-manifest-schema.py +38 -0
- package/scripts/check-meta-receiver-marker.ts +25 -2
- package/scripts/check-meta-session.ts +32 -0
- package/scripts/copilot-bridge-doctor.sh +209 -0
- package/scripts/copilot-bridge-install.sh +224 -0
- package/scripts/copilot-launch.sh +236 -0
- package/scripts/copilot-mcp-bridge.sh +177 -0
- package/scripts/copilot-mcp-config.py +221 -0
- package/scripts/copilot-receive-bridge.sh +483 -0
- package/scripts/copilot-statusline-bridge.sh +149 -0
- package/scripts/copilot-statusline-config.py +201 -0
- package/scripts/copilot-statusline.sh +68 -0
- package/scripts/dev-bin.sh +4 -1
- package/scripts/meta-bridge-hook-log.sh +17 -5
- package/scripts/mutants/capability-cache.json +64 -0
- package/scripts/mutants/copilot-birth.json +155 -0
- package/scripts/mutants/copilot-launch.json +187 -0
- package/scripts/mutants/copilot-receive.json +263 -0
- package/scripts/mutants/fresh-cut.json +17 -0
- package/scripts/mutants/mux-fresh-call.json +216 -2
- package/scripts/mutants/pack-install.json +17 -0
- package/scripts/raw-async-delivery/README.md +170 -125
- package/scripts/raw-async-delivery/copilot-enqueue-addressed.sh +35 -0
- package/scripts/raw-async-delivery/copilot-extension-receive/extension.mjs +123 -0
- package/scripts/smoke-copilot-mcp-state.sh +153 -0
- package/scripts/smoke-copilot-statusline-state.sh +131 -0
- package/scripts/smoke-mux-fresh-call-live.ts +2 -0
- package/scripts/smoke-mux-lifecycle-live.ts +3 -1
- package/scripts/tsconfig.json +1 -0
|
@@ -46,26 +46,47 @@
|
|
|
46
46
|
*/
|
|
47
47
|
import { randomBytes } from "node:crypto";
|
|
48
48
|
import { classifyTmuxCwd } from "./classify-tmux-cwd.js";
|
|
49
|
+
import { COPILOT_PREFLIGHT_HINT, copilotFreshPreflight, } from "./copilot-fresh-preflight.js";
|
|
49
50
|
import { assertLaunchTarget, LaunchPreconditionError, resolveRuntimeOnPath, } from "./mux-launch.js";
|
|
50
51
|
import { APPEND_FORMAT, assertSelector, assertTmuxOk, inspectPlacement, parseWindowFields, requireSameContext, runTmux, } from "./mux-placement.js";
|
|
51
|
-
/** The
|
|
52
|
-
* not a config entry. */
|
|
53
|
-
export const FRESH_CALL_BACKENDS = ["pi", "claude-code"];
|
|
54
|
-
/**
|
|
52
|
+
/** The backends this rail can open. Fixed set, not a profile — a further one is a decision,
|
|
53
|
+
* not a config entry. `copilot` was added by #82 RAIL 9 under the step 9 admission contract. */
|
|
54
|
+
export const FRESH_CALL_BACKENDS = ["pi", "claude-code", "copilot"];
|
|
55
|
+
/**
|
|
56
|
+
* The fixed runtime each backend resolves on PATH. Same reason `mux-launch` uses PATH rather
|
|
55
57
|
* than a compiled-in location: the official binary is whatever the operator's environment gives
|
|
56
|
-
* when they type the name.
|
|
58
|
+
* when they type the name.
|
|
59
|
+
*
|
|
60
|
+
* `copilot` resolves `entwurf`, NOT the vendor CLI, and that is the contract rather than a
|
|
61
|
+
* convenience. Step 9 clause 1 requires ONE fixed MANAGED runtime path, and a bare `copilot`
|
|
62
|
+
* is not one: it would start without the `COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS` token
|
|
63
|
+
* whose absence skips the extension scan SILENTLY, so the sibling would look launched and could
|
|
64
|
+
* never be delivered to. `entwurf copilot` is the accepted managed invocation that owns that
|
|
65
|
+
* flag, its recursion fence and its receiver precondition; fresh call reaches Copilot only
|
|
66
|
+
* through it. The cost is named: a Copilot fresh call needs a current `entwurf` on PATH, the
|
|
67
|
+
* way a pi fresh call needs `pi`.
|
|
68
|
+
*/
|
|
57
69
|
export const FRESH_CALL_RUNTIME = {
|
|
58
70
|
pi: "pi",
|
|
59
71
|
"claude-code": "claude",
|
|
72
|
+
copilot: "entwurf",
|
|
60
73
|
};
|
|
61
74
|
/**
|
|
62
75
|
* The callback tool NAME differs per backend and that is not cosmetic: native pi exposes the
|
|
63
|
-
* capability directly (`entwurf_v2`), while
|
|
64
|
-
*
|
|
76
|
+
* capability directly (`entwurf_v2`), while an MCP-hosted session reaches it under whatever
|
|
77
|
+
* name that harness composes. Naming the wrong one costs the whole first turn.
|
|
78
|
+
*
|
|
79
|
+
* `[측정]` Copilot CLI 1.0.80 composes `<mcpServerName>-<mcpToolName>` — NOT Claude Code's
|
|
80
|
+
* `mcp__<server>__<tool>`. Read from two independent sessions' own event logs
|
|
81
|
+
* (`~/.copilot/session-state/<id>/events.jsonl`): `assistant.message.toolRequests[].name` and
|
|
82
|
+
* `tool.execution_start.toolName` both carry `entwurf-bridge-entwurf_v2`, with
|
|
83
|
+
* `mcpServerName`/`mcpToolName` beside them as the parts. Derive-and-measure, never copy a
|
|
84
|
+
* sibling's spelling (`docs/adding-a-harness.md` step 5).
|
|
65
85
|
*/
|
|
66
86
|
export const FRESH_CALL_CALLBACK_TOOL = {
|
|
67
87
|
pi: "entwurf_v2",
|
|
68
88
|
"claude-code": "mcp__entwurf-bridge__entwurf_v2",
|
|
89
|
+
copilot: "entwurf-bridge-entwurf_v2",
|
|
69
90
|
};
|
|
70
91
|
/** Mirrors the `entwurf_v2` message bound. This is an INTERFACE cap for symmetry with the
|
|
71
92
|
* delivery surface, not a claim that a task of this size was measured through tmux. An argv
|
|
@@ -88,12 +109,41 @@ export function isSafeFreshCallModel(model) {
|
|
|
88
109
|
* Flag-first submitted no message; Pi rejects the equals form for `--model`.
|
|
89
110
|
* claude-code — prompt, then `--allowedTools=` and `--model=` as ONE token each. The space form
|
|
90
111
|
* for allowedTools is variadic and eats the prompt as an option value.
|
|
112
|
+
* copilot — the managed VERB first, then the prompt as the value of `-i/--interactive`,
|
|
113
|
+
* `--model`, value as two tokens, and the policy as the explicit `--yolo`
|
|
114
|
+
* token. Measured from `copilot --help` (1.0.80).
|
|
91
115
|
*
|
|
92
|
-
* Both failures looked identical from outside: window open, record and socket minted,
|
|
116
|
+
* Both pi/claude failures looked identical from outside: window open, record and socket minted,
|
|
117
|
+
* no turn.
|
|
93
118
|
*
|
|
94
|
-
*
|
|
95
|
-
* permitted, so the option's effect was unobservable. What was observed is
|
|
96
|
-
* to the argv. Permission stays a documented host precondition.
|
|
119
|
+
* For pi and claude-code the equals form is NOT a permission guarantee — on the measured host
|
|
120
|
+
* the tool was already permitted, so the option's effect was unobservable. What was observed is
|
|
121
|
+
* that it does no harm to the argv. Permission stays a documented host precondition there.
|
|
122
|
+
*
|
|
123
|
+
* Copilot is the backend where the policy IS carried explicitly (step 9 clause 2), and three of
|
|
124
|
+
* its argv facts are load-bearing:
|
|
125
|
+
*
|
|
126
|
+
* - `copilot` is argv[0] of the RUNTIME `entwurf`, i.e. the managed verb — see
|
|
127
|
+
* `FRESH_CALL_RUNTIME`. Everything after it is forwarded byte-identical by
|
|
128
|
+
* `scripts/copilot-launch.sh`.
|
|
129
|
+
* - the prompt rides `--interactive`, never `-p/--prompt`: `-p` runs the prompt and EXITS,
|
|
130
|
+
* which would close the window on a sibling that is supposed to stay open and be delivered
|
|
131
|
+
* to. `--interactive <prompt>` is non-variadic, so the space form is safe here.
|
|
132
|
+
* - the policy token is `--yolo`, STATED HERE rather than left to the launcher: the launcher
|
|
133
|
+
* injects `--yolo` only when the argv names no policy, and step 9 clause 2 requires the
|
|
134
|
+
* fresh composition to state its model and permission policy explicitly, never to rely
|
|
135
|
+
* invisibly on someone else's default.
|
|
136
|
+
*
|
|
137
|
+
* `--yolo` is a GLG operator decision, not a drifted default. The first cut passed a
|
|
138
|
+
* callback-only `--allow-tool=entwurf-bridge(entwurf_v2)` grant, and GLG's 2026-08-25 operator
|
|
139
|
+
* LIVE measured the consequence: the fresh sibling's footer showed no `YOLO`, and every tool
|
|
140
|
+
* its task needed stopped on a confirmation prompt, which made the sibling impractical to work
|
|
141
|
+
* with. GLG then set the policy explicitly: a fresh Copilot sibling carries the same managed
|
|
142
|
+
* `--yolo` profile a human-typed `entwurf copilot` gets. (Copilot 1.0.80 help: `--yolo` = all
|
|
143
|
+
* tools + all paths + all URLs.) The permission GRAMMAR lesson from that first cut — Copilot's
|
|
144
|
+
* `--allow-tool` takes `<mcp-server-name>(tool-name?)`, a different dialect from the
|
|
145
|
+
* model-facing tool name — stays recorded in `docs/adding-a-harness.md` step 9's worked
|
|
146
|
+
* example; it is a measured vendor fact even though this argv no longer uses it.
|
|
97
147
|
*/
|
|
98
148
|
export function buildBackendArgs(backend, prompt, model) {
|
|
99
149
|
switch (backend) {
|
|
@@ -101,6 +151,8 @@ export function buildBackendArgs(backend, prompt, model) {
|
|
|
101
151
|
return [prompt, "--entwurf-control", "--model", model];
|
|
102
152
|
case "claude-code":
|
|
103
153
|
return [prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL["claude-code"]}`, `--model=${model}`];
|
|
154
|
+
case "copilot":
|
|
155
|
+
return ["copilot", "--interactive", prompt, "--model", model, "--yolo"];
|
|
104
156
|
}
|
|
105
157
|
}
|
|
106
158
|
/**
|
|
@@ -204,6 +256,17 @@ export function freshCall(params, env = process.env, nonce = mintNonce()) {
|
|
|
204
256
|
return { ok: false, reason: err.reason };
|
|
205
257
|
throw err;
|
|
206
258
|
}
|
|
259
|
+
// Backend capability, still PRE-MUTATION (step 9 clause 3). It runs AFTER the runtime is
|
|
260
|
+
// proven, because "entwurf is not on PATH" is the more fundamental answer — telling an
|
|
261
|
+
// operator to run `entwurf install-copilot-bridge` when they have no `entwurf` at all sends
|
|
262
|
+
// them to the wrong repair. It runs BEFORE placement for the reason this whole ordering
|
|
263
|
+
// exists: a refusal here cannot leave a window behind, while the launcher's own equivalent
|
|
264
|
+
// check (receiver only, manual `entwurf copilot`) necessarily runs after one is open.
|
|
265
|
+
if (params.backend === "copilot") {
|
|
266
|
+
const missing = copilotFreshPreflight(env);
|
|
267
|
+
if (missing)
|
|
268
|
+
return { ok: false, reason: missing };
|
|
269
|
+
}
|
|
207
270
|
const inspected = inspectPlacement(env);
|
|
208
271
|
if (!inspected.ok)
|
|
209
272
|
return { ok: false, reason: inspected.reason };
|
|
@@ -244,6 +307,9 @@ export function freshCall(params, env = process.env, nonce = mintNonce()) {
|
|
|
244
307
|
/** Why each refusal happened, in the caller's terms. A reason a caller cannot act on is a reason
|
|
245
308
|
* they will guess about. */
|
|
246
309
|
const REJECT_HINT = {
|
|
310
|
+
// The Copilot capability reasons keep their repair text on the leaf that decides them, so
|
|
311
|
+
// the sentence an operator reads cannot drift away from the predicate that produced it.
|
|
312
|
+
...COPILOT_PREFLIGHT_HINT,
|
|
247
313
|
"no-tmux-context": "this agent is not running inside tmux, so there is no session to open a sibling beside",
|
|
248
314
|
"anchor-malformed": "TMUX_PANE is not a native pane id",
|
|
249
315
|
"anchor-unresolved": "tmux resolved no pane for this agent's anchor",
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* meta-bridge-hook-copilot — the GitHub Copilot CLI native-session BIRTH entry (#82).
|
|
3
|
+
*
|
|
4
|
+
* WHAT THIS IS, AND WHAT IT DELIBERATELY IS NOT
|
|
5
|
+
*
|
|
6
|
+
* It mints, then names the minted citizen as this host's SENDER:
|
|
7
|
+
*
|
|
8
|
+
* stdin {sessionId|session_id, cwd} (Copilot hook envelope, either shape)
|
|
9
|
+
* -> upsertMetaSession(copilot) idempotent create/attach the record
|
|
10
|
+
* -> gardenId the session's garden address
|
|
11
|
+
* -> writeMetaSenderMarker(ppid) who-sent join for this host's MCP children
|
|
12
|
+
*
|
|
13
|
+
* No receiver marker, no mailbox arm, no watchPaths — and that is still the contract now
|
|
14
|
+
* that Copilot HAS a doorbell (#82 RAIL 5). The reason changed, the rule did not. A
|
|
15
|
+
* receiver marker is a claim that a LIVE process holds a watch, and the process that holds
|
|
16
|
+
* Copilot's watch is the forked extension (`pi/copilot-receive/`), not this hook. Minted
|
|
17
|
+
* here it would name the Copilot host pid as the owner of a watch that pid does not hold,
|
|
18
|
+
* and the citizen would read deliverable, wired to nothing, for as long as the TUI stayed
|
|
19
|
+
* open. Arming belongs to the watcher; birth belongs here.
|
|
20
|
+
*
|
|
21
|
+
* THE SENDER MARKER IS A DIFFERENT FACT, AND THIS UNIT USED TO CONFLATE THEM. Until
|
|
22
|
+
* #82 RAIL 5b this file wrote no marker of EITHER kind, and gave the doorbell's
|
|
23
|
+
* absence as the reason for both. That reasoning is only valid for the receiver:
|
|
24
|
+
*
|
|
25
|
+
* receiver marker = "a live session is ARMED to be woken" -> needs a doorbell
|
|
26
|
+
* sender marker = "who owns this MCP child process" -> needs a shared parent
|
|
27
|
+
*
|
|
28
|
+
* `lib/meta-sender-identity.ts` states the sender join in one line — the hook writes a
|
|
29
|
+
* marker keyed by ITS parent pid, the bridge child looks one up under its own parent,
|
|
30
|
+
* and that shared ancestor IS the join key. Nothing in it consults a doorbell. So a
|
|
31
|
+
* Copilot citizen with the MCP hand installed could read (`entwurf_peers`) but never
|
|
32
|
+
* send: the bridge held the owner pid and found no marker to look up. Writing one is
|
|
33
|
+
* what closes that, and it changes exactly one thing for the receiver of a message —
|
|
34
|
+
* it learns WHO sent it.
|
|
35
|
+
*
|
|
36
|
+
* IT DOES NOT MAKE THIS CITIZEN REPLYABLE, and must never be described as if it did.
|
|
37
|
+
* `mcp/entwurf-bridge/src/index.ts` picks the reply rail from `nativePushSupported`;
|
|
38
|
+
* copilot is not native-push, so it lands in the self-fetch domain, where `replyable`
|
|
39
|
+
* comes from a RECEIVER marker written by the extension when it joins the session. A
|
|
40
|
+
* citizen that is born but whose receiver has not armed is `replyable: false` with a real
|
|
41
|
+
* garden identity — the honest answer, and it becomes true on its own once the extension
|
|
42
|
+
* binds. What this file must never do is anticipate that answer.
|
|
43
|
+
*
|
|
44
|
+
* WHY A SECOND ENTRY FILE. `meta-bridge-hook.ts` hardcodes `backend: "claude-code"`
|
|
45
|
+
* at mint and then does the marker/watch work above, and two gates pin that unit to
|
|
46
|
+
* Claude's exec form and its four PascalCase events. Copilot's schema has no `args`
|
|
47
|
+
* key at all, its exec form is a single `exec` string and its events are camelCase,
|
|
48
|
+
* so the two units cannot share a manifest — and once the manifests are separate,
|
|
49
|
+
* sharing an entry would only buy a runtime branch that the gates would then have to
|
|
50
|
+
* unpick. The shared half lives where it belongs: `lib/meta-session.ts`.
|
|
51
|
+
*
|
|
52
|
+
* BIRTH IS ON THE FIRST PROMPT, NOT AT SESSION OPEN. Measured: opening the TUI
|
|
53
|
+
* registers a session and fires NO hook (11:17:19.920Z registration, three idle
|
|
54
|
+
* minutes, zero hook lines, `Session: 0 AIC used`). The first prompt then fires
|
|
55
|
+
* `userPromptSubmitted` (11:20:29.476Z) -> `sessionStart` (11:20:32.102Z). Both are
|
|
56
|
+
* wired to this entry and the upsert is idempotent, so the earlier of the two mints
|
|
57
|
+
* and the later attaches. Do not describe a Copilot citizen as born when its window
|
|
58
|
+
* opens; it is born when it is first spoken to.
|
|
59
|
+
*
|
|
60
|
+
* ENVELOPE SHAPE — TWO ACCEPTED, ON PURPOSE. Copilot ships a Claude-compat envelope
|
|
61
|
+
* translator: a Claude-form hook declaration receives `{hook_event_name, session_id,
|
|
62
|
+
* cwd, ...}` (measured), while its native declarations carry `{sessionId, timestamp,
|
|
63
|
+
* cwd, source, ...}`. This unit declares the NATIVE form, and which of the two shapes
|
|
64
|
+
* a native declaration puts on stdin was not measured. Reading both is not sloppiness
|
|
65
|
+
* about which is true — it is refusing to bet a citizen's existence on an unmeasured
|
|
66
|
+
* key name when the two shapes are trivially distinguishable and the log line records
|
|
67
|
+
* which one actually arrived. That log line is how the doctor turns the guess into a
|
|
68
|
+
* measurement on the first real session.
|
|
69
|
+
*
|
|
70
|
+
* FAILURE POLICY, inherited from the Claude unit: BEST-EFFORT + LOG. Never scream
|
|
71
|
+
* into the operator's terminal, never block the turn. On any error, append a level-
|
|
72
|
+
* tagged line to `<pi-agent-dir>/meta-bridge-hook.log` and exit 0 with `{}` on
|
|
73
|
+
* stdout. The fail-loud surface is the doctor, which reads that log.
|
|
74
|
+
*
|
|
75
|
+
* LAUNCH: never invoked directly by Copilot. `hooks/hooks.json` declares
|
|
76
|
+
* `exec: <baked abspath of scripts/copilot-hook-launch.sh>` and that launcher `exec`s
|
|
77
|
+
* this payload. See copilot-hook-launch.sh for why it cannot be the Claude launcher.
|
|
78
|
+
*/
|
|
79
|
+
import * as fs from "node:fs";
|
|
80
|
+
import * as path from "node:path";
|
|
81
|
+
import { defaultMetaSessionsDir, isPlausibleOwnerPid, upsertMetaSession, writeMetaSenderMarker, } from "./lib/meta-session.js";
|
|
82
|
+
/**
|
|
83
|
+
* The launch-provenance handshake, held as LOCAL literals on purpose.
|
|
84
|
+
*
|
|
85
|
+
* The Claude payload declares the same pair privately, and `check-meta-receiver-marker`
|
|
86
|
+
* asserts the literal is present in THAT source — so hoisting the two strings into a
|
|
87
|
+
* shared module would drag a sibling rail's production file and its gate into this lane
|
|
88
|
+
* for no behavioral gain (PM decision, 2026-08-21).
|
|
89
|
+
*
|
|
90
|
+
* This is not an unguarded copy. The value already exists on both sides of a shell/TS
|
|
91
|
+
* boundary anyway (`copilot-hook-launch.sh` exports it), and `check-copilot-birth-hook`
|
|
92
|
+
* fires the REAL assembled launcher, so a drift between the two spellings shows up as a
|
|
93
|
+
* refused marker in that gate rather than as a silent mismatch.
|
|
94
|
+
*/
|
|
95
|
+
const META_HOOK_LAUNCH_ENV = "ENTWURF_META_HOOK_LAUNCH";
|
|
96
|
+
const META_HOOK_LAUNCH_TOKEN = "hook-launch/v1";
|
|
97
|
+
/** Append a best-effort diagnostic line; swallow even its own failure. Same log file
|
|
98
|
+
* and same LEVEL vocabulary as the Claude unit, so one doctor grep covers both. */
|
|
99
|
+
function logLine(level, message) {
|
|
100
|
+
try {
|
|
101
|
+
const file = path.join(path.dirname(defaultMetaSessionsDir()), "meta-bridge-hook.log");
|
|
102
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
103
|
+
fs.appendFileSync(file, `${new Date().toISOString()} ${level} [copilot] ${message}\n`);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* logging is best-effort; a broken log must not break the session */
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** Emit the neutral hook response and leave. Copilot has no watchPaths to arm, so
|
|
110
|
+
* there is never anything else to say. */
|
|
111
|
+
function emit() {
|
|
112
|
+
process.stdout.write("{}\n");
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Reduce either envelope shape to the two fields birth needs, or refuse.
|
|
117
|
+
*
|
|
118
|
+
* ACCEPTING TWO SHAPES IS NOT THE SAME AS PREFERRING ONE. `sessionId ?? session_id`
|
|
119
|
+
* would silently pick a winner when the two disagree, and a disagreement is exactly
|
|
120
|
+
* the case worth refusing: it means the compat translator produced two different
|
|
121
|
+
* identities for one session, or something hand-built the envelope. A record minted
|
|
122
|
+
* from the loser would be a citizen no live session can be joined back to. So both
|
|
123
|
+
* present + equal is fine (`agreeing-both`); both present + different is a REFUSAL
|
|
124
|
+
* (cross-review, terra, 2026-08-20).
|
|
125
|
+
*
|
|
126
|
+
* `cwd` has NO process.cwd() fallback, unlike the Claude entry. There the hook runs
|
|
127
|
+
* in the session's own cwd, so the fallback is the same value by another route; here
|
|
128
|
+
* the record is the ONLY thing this unit ever writes and a guessed cwd would be a
|
|
129
|
+
* fact nothing later can correct. Both measured Copilot shapes carry `cwd`.
|
|
130
|
+
*/
|
|
131
|
+
export function readBirthEnvelope(env) {
|
|
132
|
+
const nativeRaw = env.sessionId;
|
|
133
|
+
const compatRaw = env.session_id;
|
|
134
|
+
const native = typeof nativeRaw === "string" ? nativeRaw : "";
|
|
135
|
+
const compat = typeof compatRaw === "string" ? compatRaw : "";
|
|
136
|
+
if (nativeRaw !== undefined && native.length === 0)
|
|
137
|
+
return { refusal: "sessionId present but not a non-empty string" };
|
|
138
|
+
if (compatRaw !== undefined && compat.length === 0)
|
|
139
|
+
return { refusal: "session_id present but not a non-empty string" };
|
|
140
|
+
if (native && compat && native !== compat) {
|
|
141
|
+
return { refusal: `sessionId and session_id disagree (${native} vs ${compat})` };
|
|
142
|
+
}
|
|
143
|
+
const sessionId = native || compat;
|
|
144
|
+
if (!sessionId)
|
|
145
|
+
return { refusal: "no sessionId/session_id" };
|
|
146
|
+
const shape = native && compat ? "agreeing-both" : native ? "copilot-native" : "claude-compat";
|
|
147
|
+
if (typeof env.cwd !== "string" || env.cwd.length === 0)
|
|
148
|
+
return { refusal: "cwd missing or not a non-empty string" };
|
|
149
|
+
const cwd = env.cwd;
|
|
150
|
+
const eventLabel = typeof env.hook_event_name === "string" && env.hook_event_name.length > 0
|
|
151
|
+
? env.hook_event_name
|
|
152
|
+
: typeof env.source === "string" && env.source.length > 0
|
|
153
|
+
? `native(source=${env.source})`
|
|
154
|
+
: "unlabeled";
|
|
155
|
+
return { sessionId, cwd, shape, eventLabel };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Which pid does a sender marker written here belong to — or NONE.
|
|
159
|
+
*
|
|
160
|
+
* `copilot-hook-launch.sh` `exec`s this payload, so on the shipped path this process IS
|
|
161
|
+
* the launcher and its parent is the Copilot host that ran the hook. Two things that
|
|
162
|
+
* form cannot promise are asked anyway, and both fail CLOSED:
|
|
163
|
+
*
|
|
164
|
+
* 1. LAUNCH PROVENANCE. `process.ppid` only names the Copilot host when this payload
|
|
165
|
+
* was reached THROUGH the shipped launcher. A session still holding an older cached
|
|
166
|
+
* hook command, or a hand-run of the entry file, has some other parent — so the
|
|
167
|
+
* launcher stamps a token and this reads it. No token, no claim.
|
|
168
|
+
* 2. A PLAUSIBLE LIVE PARENT. `isPlausibleOwnerPid` is the predicate shared with every
|
|
169
|
+
* marker writer, reader and the generation cut. A marker naming init outlives every
|
|
170
|
+
* process that could refute it, and one such leftover once blocked a host's
|
|
171
|
+
* fresh-cut until it was deleted by hand (#53 A).
|
|
172
|
+
*
|
|
173
|
+
* Failing closed costs only who-sent, which this backend did not have five minutes ago,
|
|
174
|
+
* and the doctor reads the WARN. Claiming a transient wrapper as the owner would instead
|
|
175
|
+
* attribute a citizen's messages to a pid that never sent them.
|
|
176
|
+
*
|
|
177
|
+
* MEASUREMENT STATE OF THE JOIN ITSELF. `[측정]` Closed end to end on Copilot CLI 1.0.80,
|
|
178
|
+
* 2026-08-21, through the PRODUCTION events this unit wires: a live session's marker owner
|
|
179
|
+
* was the running Copilot native process, that same pid was the parent of the running
|
|
180
|
+
* entwurf MCP child, and a send from that session arrived carrying its own garden id with
|
|
181
|
+
* `origin: "meta-session"`. Marker owner == native host == MCP child's parent is therefore
|
|
182
|
+
* an observed fact on this backend, not an assumption inherited from the other two.
|
|
183
|
+
*
|
|
184
|
+
* The claim is still BOUNDED, and the bound is the vendor version: one CLI release is not a
|
|
185
|
+
* promise about the next, and this join is the only thing standing between a marker and the
|
|
186
|
+
* child that must find it. That is why the success line below prints the owner pid — it
|
|
187
|
+
* keeps the join re-checkable from the log alone, with no probe to re-run.
|
|
188
|
+
*/
|
|
189
|
+
/**
|
|
190
|
+
* Arm who-sent for this host's MCP children, or say in the log why it could not be.
|
|
191
|
+
*
|
|
192
|
+
* BEST-EFFORT + LOG, exactly like the mint above it: a Copilot turn must never be broken
|
|
193
|
+
* or spammed by our bookkeeping, so nothing here throws and nothing reaches the terminal.
|
|
194
|
+
* The three outcomes get three distinct tokens because they need three different fixes,
|
|
195
|
+
* and the doctor greps this log:
|
|
196
|
+
*
|
|
197
|
+
* `sender marker <pid> -> <gid>` armed. The pid is printed because it is the join key
|
|
198
|
+
* AND the production-event measurement that is still
|
|
199
|
+
* open (see resolveCopilotHookOwnerPid).
|
|
200
|
+
* `sender-marker-refused` we declined to claim an owner: no launch provenance
|
|
201
|
+
* (reinstall + restart that session) or an implausible
|
|
202
|
+
* parent (a reparented orphan). Not an error — a
|
|
203
|
+
* fail-closed answer, so WARN.
|
|
204
|
+
* `sender-marker-failed` we tried and the write itself broke (permissions, a
|
|
205
|
+
* full disk, a refused owner pid). ERROR.
|
|
206
|
+
*
|
|
207
|
+
* Either non-success costs only who-sent: the citizen still exists, still appears in
|
|
208
|
+
* `entwurf_peers`, and can still be addressed BY others. Only its own outbound sends fall
|
|
209
|
+
* back to the bridge's default refusal.
|
|
210
|
+
*/
|
|
211
|
+
function writeCopilotSenderMarker(gardenId, envelope) {
|
|
212
|
+
const ownerPid = resolveCopilotHookOwnerPid();
|
|
213
|
+
if (ownerPid === null) {
|
|
214
|
+
logLine("WARN", process.env[META_HOOK_LAUNCH_ENV] !== META_HOOK_LAUNCH_TOKEN
|
|
215
|
+
? `sender-marker-refused garden=${gardenId}: exec-launch provenance missing (${META_HOOK_LAUNCH_ENV}); this hook was NOT reached through copilot-hook-launch.sh, so its parent is not a trustworthy owner. Reinstall the Copilot bridge and RESTART that session. This citizen exists but cannot send (event=${envelope.eventLabel})`
|
|
216
|
+
: `sender-marker-refused garden=${gardenId}: parent pid ${process.ppid} is not a plausible owner (reparented orphan?); this citizen exists but cannot send (event=${envelope.eventLabel})`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
writeMetaSenderMarker({
|
|
221
|
+
backend: "copilot",
|
|
222
|
+
gardenId,
|
|
223
|
+
nativeSessionId: envelope.sessionId,
|
|
224
|
+
cwd: envelope.cwd,
|
|
225
|
+
ownerPid,
|
|
226
|
+
});
|
|
227
|
+
logLine("INFO", `sender marker ${ownerPid} -> ${gardenId} (event=${envelope.eventLabel})`);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
logLine("ERROR", `sender-marker-failed pid=${ownerPid} garden=${gardenId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function resolveCopilotHookOwnerPid() {
|
|
234
|
+
if (process.env[META_HOOK_LAUNCH_ENV] !== META_HOOK_LAUNCH_TOKEN)
|
|
235
|
+
return null;
|
|
236
|
+
const ownerPid = process.ppid;
|
|
237
|
+
if (!isPlausibleOwnerPid(ownerPid))
|
|
238
|
+
return null;
|
|
239
|
+
return ownerPid;
|
|
240
|
+
}
|
|
241
|
+
function main() {
|
|
242
|
+
let raw;
|
|
243
|
+
try {
|
|
244
|
+
raw = fs.readFileSync(0, "utf8"); // fd 0 = stdin (the Copilot hook envelope)
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
logLine("ERROR", `stdin read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
248
|
+
emit();
|
|
249
|
+
}
|
|
250
|
+
let env;
|
|
251
|
+
try {
|
|
252
|
+
const parsed = JSON.parse(raw);
|
|
253
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
254
|
+
throw new Error("envelope is not an object");
|
|
255
|
+
env = parsed;
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
logLine("ERROR", `envelope parse failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
259
|
+
emit();
|
|
260
|
+
}
|
|
261
|
+
const envelope = readBirthEnvelope(env);
|
|
262
|
+
if ("refusal" in envelope) {
|
|
263
|
+
// A record keyed to a guess would be a citizen nobody can join back to a real
|
|
264
|
+
// session, so refuse — and make it ERROR, because this session did NOT become a
|
|
265
|
+
// garden citizen. The doctor reads this line.
|
|
266
|
+
logLine("ERROR", `degraded envelope: ${envelope.refusal} (keys=${Object.keys(env).sort().join(",")})`);
|
|
267
|
+
emit();
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
// transcriptPath and model are omitted, not guessed: Copilot's envelope carries
|
|
271
|
+
// neither, and both axes are nullable at mint by design.
|
|
272
|
+
const result = upsertMetaSession({
|
|
273
|
+
input: { backend: "copilot", nativeSessionId: envelope.sessionId, cwd: envelope.cwd },
|
|
274
|
+
});
|
|
275
|
+
logLine("INFO", `${result.action} record ${path.basename(result.path)} (event=${envelope.eventLabel}, shape=${envelope.shape}, native=${envelope.sessionId})`);
|
|
276
|
+
// RECORD AUTHORITY FIRST: the marker is only a pid->garden hint that the record
|
|
277
|
+
// must vouch for, so it is written INSIDE the success branch. A marker minted
|
|
278
|
+
// after a failed upsert would name a garden id with no record behind it — the
|
|
279
|
+
// resolver would read it, find nothing, and report "names nobody" for a citizen
|
|
280
|
+
// whose real failure was the mint. Same order as the agy writer.
|
|
281
|
+
writeCopilotSenderMarker(result.record.gardenId, envelope);
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
logLine("ERROR", `upsert failed (event=${envelope.eventLabel}, native=${envelope.sessionId}): ${err instanceof Error ? err.message : String(err)}`);
|
|
285
|
+
}
|
|
286
|
+
emit();
|
|
287
|
+
}
|
|
288
|
+
main();
|
|
@@ -655,14 +655,16 @@ server.tool(
|
|
|
655
655
|
// against that answer would call home to a garden id nobody holds.
|
|
656
656
|
server.tool(
|
|
657
657
|
"entwurf_fresh_call",
|
|
658
|
-
"Open ONE fresh visible sibling in the operator's own tmux session and hand it a first task.
|
|
659
|
-
"backends only: pi, claude-code. The sibling's FIRST action is a callback to you carrying a nonce, and the " +
|
|
658
|
+
"Open ONE fresh visible sibling in the operator's own tmux session and hand it a first task. Three fixed " +
|
|
659
|
+
"backends only: pi, claude-code, copilot. The sibling's FIRST action is a callback to you carrying a nonce, and the " +
|
|
660
660
|
"sender envelope of that callback is its garden id — that is how you learn the address of something that " +
|
|
661
661
|
"did not exist a moment ago. This returns a LAUNCH receipt (tmux window/pane plus that nonce) and nothing " +
|
|
662
662
|
"else: it does NOT mean the runtime started, the first turn ran, or the task was delivered. Nothing polls " +
|
|
663
663
|
"for the callback; if it never arrives the window is visible and can be read directly. For EXISTING " +
|
|
664
664
|
"citizens use entwurf_v2 — this tool only creates, and entwurf_peers only reports. Model is REQUIRED and " +
|
|
665
|
-
"is passed to the chosen runtime CLI (`provider/model` for pi; model id/alias for Claude Code
|
|
665
|
+
"is passed to the chosen runtime CLI (`provider/model` for pi; model id/alias for Claude Code; a model name " +
|
|
666
|
+
"or `auto` for copilot). A copilot launch goes through entwurf's own managed invocation and is refused " +
|
|
667
|
+
"BEFORE any window opens if this host lacks the Copilot birth, MCP, receiver or visible-footer units. An optional " +
|
|
666
668
|
"cwd starts the sibling in ONE literal absolute existing directory (cross-repo fresh) — never pick resume " +
|
|
667
669
|
"for a dormant record's cwd; resume is continuity-only. Omitted/empty cwd means the caller's own directory. " +
|
|
668
670
|
"There are no arbitrary command/env knobs. Do not put secrets in the task — model and task argv are visible to " +
|
|
@@ -670,8 +672,8 @@ server.tool(
|
|
|
670
672
|
"inside tmux: without a pane anchor there is no session to open a sibling beside.",
|
|
671
673
|
{
|
|
672
674
|
backend: z
|
|
673
|
-
.enum(["pi", "claude-code"])
|
|
674
|
-
.describe("Which fixed runtime to open. Only these
|
|
675
|
+
.enum(["pi", "claude-code", "copilot"])
|
|
676
|
+
.describe("Which fixed runtime to open. Only these three; there is no arbitrary command."),
|
|
675
677
|
model: z
|
|
676
678
|
.string()
|
|
677
679
|
.min(1)
|
|
@@ -685,7 +687,9 @@ server.tool(
|
|
|
685
687
|
// as an unused suppression while the escape goes back to being fixable.
|
|
686
688
|
// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above
|
|
687
689
|
.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\[\]-]*$/)
|
|
688
|
-
.describe(
|
|
690
|
+
.describe(
|
|
691
|
+
"Required runtime model: canonical provider/model for pi, a Claude Code model id/alias, or a Copilot model name (or auto).",
|
|
692
|
+
),
|
|
689
693
|
task: z
|
|
690
694
|
.string()
|
|
691
695
|
.min(1)
|
|
@@ -121,6 +121,7 @@
|
|
|
121
121
|
"../../scripts/meta-bridge-prune.ts",
|
|
122
122
|
"../../scripts/meta-bridge-fresh-cut.ts",
|
|
123
123
|
"../../scripts/meta-facts.ts",
|
|
124
|
-
"../../pi-extensions/meta-bridge-hook.ts"
|
|
124
|
+
"../../pi-extensions/meta-bridge-hook.ts",
|
|
125
|
+
"../../pi-extensions/meta-bridge-hook-copilot.ts"
|
|
125
126
|
]
|
|
126
127
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@junghanacs/entwurf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Garden-citizen dispatch substrate and meta-bridge for Claude Code, Codex, Antigravity, and pi harnesses.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -56,6 +56,11 @@
|
|
|
56
56
|
"pi/meta-bridge/entwurf-meta-receive/hooks/hooks.json",
|
|
57
57
|
"pi/meta-bridge/entwurf-meta-receive/scripts/doorbell.sh",
|
|
58
58
|
"pi/meta-bridge/entwurf-meta-receive/scripts/hook-launch.sh",
|
|
59
|
+
"pi/meta-bridge-copilot/.claude-plugin/marketplace.json",
|
|
60
|
+
"pi/meta-bridge-copilot/entwurf-meta-receive-copilot/.claude-plugin/plugin.json",
|
|
61
|
+
"pi/meta-bridge-copilot/entwurf-meta-receive-copilot/hooks/hooks.json",
|
|
62
|
+
"pi/meta-bridge-copilot/entwurf-meta-receive-copilot/scripts/copilot-hook-launch.sh",
|
|
63
|
+
"pi/copilot-receive/entwurf-receive/extension.mjs",
|
|
59
64
|
"pi/skill-plugin-example/",
|
|
60
65
|
"run.sh",
|
|
61
66
|
"AGENTS.md",
|
|
@@ -81,16 +86,16 @@
|
|
|
81
86
|
"zod": "^3.25.0 || ^4.0.0"
|
|
82
87
|
},
|
|
83
88
|
"peerDependencies": {
|
|
84
|
-
"@earendil-works/pi-ai": ">=0.84.
|
|
85
|
-
"@earendil-works/pi-coding-agent": ">=0.84.
|
|
86
|
-
"@earendil-works/pi-tui": ">=0.84.
|
|
89
|
+
"@earendil-works/pi-ai": ">=0.84.3 <0.85",
|
|
90
|
+
"@earendil-works/pi-coding-agent": ">=0.84.3 <0.85",
|
|
91
|
+
"@earendil-works/pi-tui": ">=0.84.3 <0.85",
|
|
87
92
|
"typebox": "*"
|
|
88
93
|
},
|
|
89
94
|
"devDependencies": {
|
|
90
95
|
"@biomejs/biome": "^2.4.13",
|
|
91
|
-
"@earendil-works/pi-ai": "0.84.
|
|
92
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
93
|
-
"@earendil-works/pi-tui": "0.84.
|
|
96
|
+
"@earendil-works/pi-ai": "0.84.3",
|
|
97
|
+
"@earendil-works/pi-coding-agent": "0.84.3",
|
|
98
|
+
"@earendil-works/pi-tui": "0.84.3",
|
|
94
99
|
"@types/node": "^24.3.0",
|
|
95
100
|
"husky": "^9.1.7",
|
|
96
101
|
"rregex": "1.13.1",
|
|
@@ -122,6 +127,11 @@
|
|
|
122
127
|
"check-dep-versions": "./run.sh check-dep-versions",
|
|
123
128
|
"check-node-floor-coherence": "./run.sh check-node-floor-coherence",
|
|
124
129
|
"check-claude-floor-coherence": "./run.sh check-claude-floor-coherence",
|
|
130
|
+
"check-copilot-birth-hook": "./run.sh check-copilot-birth-hook",
|
|
131
|
+
"check-copilot-statusline": "./run.sh check-copilot-statusline",
|
|
132
|
+
"check-copilot-launch": "./run.sh check-copilot-launch",
|
|
133
|
+
"smoke-copilot-statusline-state": "./run.sh smoke-copilot-statusline-state",
|
|
134
|
+
"smoke-copilot-mcp-state": "./run.sh smoke-copilot-mcp-state",
|
|
125
135
|
"check-hook-launch-topology": "./run.sh check-hook-launch-topology",
|
|
126
136
|
"check-acp-carrier-augment": "./run.sh check-acp-carrier-augment",
|
|
127
137
|
"check-agy-permission-matrix": "./run.sh check-agy-permission-matrix",
|
|
@@ -144,9 +154,9 @@
|
|
|
144
154
|
"check:core": "pnpm run check:toolchain && pnpm run check:vitest && pnpm run check:contracts",
|
|
145
155
|
"check:toolchain": "pnpm lint && pnpm typecheck",
|
|
146
156
|
"check:vitest": "./run.sh check-mux-fresh-call && ./run.sh check-acp-sdk-surface",
|
|
147
|
-
"check:contracts": "./run.sh check-shell-quote && ./run.sh check-entwurf-session-identity && ./run.sh check-meta-session && ./run.sh check-meta-v3-record && ./run.sh check-mailbox-receipt-state && ./run.sh check-entwurf-capabilities && ./run.sh check-capability-bundle-reach && ./run.sh check-meta-mailbox-state-write && ./run.sh check-meta-receiver-marker && ./run.sh check-meta-capability-source && ./run.sh check-model-lock && ./run.sh check-dep-versions && ./run.sh check-node-floor-coherence && ./run.sh check-claude-floor-coherence && ./run.sh check-pi-import-surface && ./run.sh check-env-namespace && ./run.sh check-pi-runtime-version && ./run.sh check-pi-preflight && ./run.sh check-project-trust-handler && ./run.sh check-entwurf-v2-contract && ./run.sh check-entwurf-v2-lock && ./run.sh check-entwurf-v2-decider && ./run.sh check-entwurf-v2-matrix && ./run.sh check-entwurf-v2-release && ./run.sh check-entwurf-v2-send && ./run.sh check-entwurf-v2-send-fallback && ./run.sh check-entwurf-v2-mailbox && ./run.sh check-entwurf-v2-native-push && ./run.sh check-entwurf-v2-runner && ./run.sh check-entwurf-v2-production && ./run.sh check-entwurf-v2-surface && ./run.sh check-entwurf-bridge-pi-free && ./run.sh check-entwurf-resume-args && ./run.sh check-resume-launch-identity && ./run.sh check-mux-placement && ./run.sh check-mux-launch && ./run.sh check-mux-resume-call && ./run.sh check-mux-parent-artifact && ./run.sh check-mux-launcher-fence && ./run.sh check-entwurf-v2-visible-resume && ./run.sh check-entwurf-facts && ./run.sh check-control-socket-path && ./run.sh check-socket-discovery && ./run.sh check-meta-listing && ./run.sh check-entwurf-fact-provider && ./run.sh check-entwurf-peers-surface && ./run.sh check-entwurf-self-address && ./run.sh check-entwurf-deliverability && ./run.sh check-native-push-adapter && ./run.sh check-native-push-register && ./run.sh check-auth-boundary && ./run.sh check-acp-overlay && ./run.sh check-acp-tool-surface && ./run.sh check-acp-event-mapper && ./run.sh check-acp-prompt-builder && ./run.sh check-acp-config && ./run.sh check-acp-session-store && ./run.sh check-acp-carrier-augment",
|
|
148
|
-
"check:hermetic": "./run.sh check-bridge-delivery && ./run.sh smoke-pi-attach && ./run.sh check-fresh-cut-gate && ./run.sh check-hook-launch-topology && ./run.sh check-meta-identity-consumers && ./run.sh check-socket-probe && ./run.sh smoke-meta-honesty && ./run.sh check-meta-doctor-oracle && ./run.sh check-agy-permission-matrix && ./run.sh smoke-agy-statusline-state && ./run.sh smoke-agy-hooks-state && ./run.sh smoke-pi-provider-state && ./run.sh smoke-user-scope-citizen && ./run.sh smoke-meta-prune && ./run.sh smoke-meta-keyset-guard && ./run.sh check-meta-manifest-schema && ./run.sh check-entwurf-control-rpc && ./run.sh check-entwurf-bridge-boot && ./run.sh check-probe-bridge-command && ./run.sh check-meta-facts && ./run.sh check-agy-sender-identity && ./run.sh check-acp-provider-surface && ./run.sh check-acp-stop-reason && ./run.sh check-acp-prompt-lifecycle && ./run.sh check-acp-stream-hooks && ./run.sh check-acp-backend-preflight && ./run.sh check-acp-session-reuse && ./run.sh check-release-gate-outcomes && ./run.sh check-probe-ordering && ./run.sh check-probe-cli-shim && ./run.sh check-acp-cortex",
|
|
149
|
-
"check:package": "./run.sh check-install-surface && ./run.sh smoke-meta-install-state && ./run.sh smoke-agy-install-state && ./run.sh check-package-source-routing && ./run.sh check-install-preflight && ./run.sh check-pack"
|
|
157
|
+
"check:contracts": "./run.sh check-shell-quote && ./run.sh check-entwurf-session-identity && ./run.sh check-meta-session && ./run.sh check-meta-v3-record && ./run.sh check-mailbox-receipt-state && ./run.sh check-entwurf-capabilities && ./run.sh check-capability-bundle-reach && ./run.sh check-meta-mailbox-state-write && ./run.sh check-meta-receiver-marker && ./run.sh check-meta-capability-source && ./run.sh check-model-lock && ./run.sh check-dep-versions && ./run.sh check-node-floor-coherence && ./run.sh check-claude-floor-coherence && ./run.sh check-copilot-statusline && ./run.sh check-pi-import-surface && ./run.sh check-env-namespace && ./run.sh check-pi-runtime-version && ./run.sh check-pi-preflight && ./run.sh check-project-trust-handler && ./run.sh check-entwurf-v2-contract && ./run.sh check-entwurf-v2-lock && ./run.sh check-entwurf-v2-decider && ./run.sh check-entwurf-v2-matrix && ./run.sh check-entwurf-v2-release && ./run.sh check-entwurf-v2-send && ./run.sh check-entwurf-v2-send-fallback && ./run.sh check-entwurf-v2-mailbox && ./run.sh check-entwurf-v2-native-push && ./run.sh check-entwurf-v2-runner && ./run.sh check-entwurf-v2-production && ./run.sh check-entwurf-v2-surface && ./run.sh check-entwurf-bridge-pi-free && ./run.sh check-entwurf-resume-args && ./run.sh check-resume-launch-identity && ./run.sh check-mux-placement && ./run.sh check-mux-launch && ./run.sh check-mux-resume-call && ./run.sh check-mux-parent-artifact && ./run.sh check-mux-launcher-fence && ./run.sh check-entwurf-v2-visible-resume && ./run.sh check-entwurf-facts && ./run.sh check-control-socket-path && ./run.sh check-socket-discovery && ./run.sh check-meta-listing && ./run.sh check-entwurf-fact-provider && ./run.sh check-entwurf-peers-surface && ./run.sh check-entwurf-self-address && ./run.sh check-entwurf-deliverability && ./run.sh check-native-push-adapter && ./run.sh check-native-push-register && ./run.sh check-auth-boundary && ./run.sh check-acp-overlay && ./run.sh check-acp-tool-surface && ./run.sh check-acp-event-mapper && ./run.sh check-acp-prompt-builder && ./run.sh check-acp-config && ./run.sh check-acp-session-store && ./run.sh check-acp-carrier-augment",
|
|
158
|
+
"check:hermetic": "./run.sh check-bridge-delivery && ./run.sh smoke-pi-attach && ./run.sh check-fresh-cut-gate && ./run.sh check-hook-launch-topology && ./run.sh check-copilot-birth-hook && ./run.sh check-copilot-receive-arm && ./run.sh check-copilot-launch && ./run.sh check-meta-identity-consumers && ./run.sh check-socket-probe && ./run.sh smoke-meta-honesty && ./run.sh check-meta-doctor-oracle && ./run.sh check-agy-permission-matrix && ./run.sh smoke-agy-statusline-state && ./run.sh smoke-copilot-statusline-state && ./run.sh smoke-copilot-mcp-state && ./run.sh smoke-agy-hooks-state && ./run.sh smoke-pi-provider-state && ./run.sh smoke-user-scope-citizen && ./run.sh smoke-meta-prune && ./run.sh smoke-meta-keyset-guard && ./run.sh check-meta-manifest-schema && ./run.sh check-entwurf-control-rpc && ./run.sh check-entwurf-bridge-boot && ./run.sh check-probe-bridge-command && ./run.sh check-meta-facts && ./run.sh check-agy-sender-identity && ./run.sh check-acp-provider-surface && ./run.sh check-acp-stop-reason && ./run.sh check-acp-prompt-lifecycle && ./run.sh check-acp-stream-hooks && ./run.sh check-acp-backend-preflight && ./run.sh check-acp-session-reuse && ./run.sh check-release-gate-outcomes && ./run.sh check-probe-ordering && ./run.sh check-probe-cli-shim && ./run.sh check-acp-cortex",
|
|
159
|
+
"check:package": "./run.sh check-install-surface && ./run.sh smoke-meta-install-state && ./run.sh smoke-agy-install-state && ./run.sh check-pack-pin-matcher && ./run.sh check-package-source-routing && ./run.sh check-install-preflight && ./run.sh check-pack"
|
|
150
160
|
},
|
|
151
161
|
"pi": {
|
|
152
162
|
"extensions": [
|
|
@@ -161,7 +171,8 @@
|
|
|
161
171
|
"entwurf-bridge": "./mcp/entwurf-bridge/start.sh",
|
|
162
172
|
"entwurf-statusline": "./scripts/meta-bridge-statusline.sh",
|
|
163
173
|
"entwurf-agy-statusline": "./scripts/agy-statusline.sh",
|
|
164
|
-
"entwurf-agy-imprint": "./scripts/agy-imprint.sh"
|
|
174
|
+
"entwurf-agy-imprint": "./scripts/agy-imprint.sh",
|
|
175
|
+
"entwurf-copilot-statusline": "./scripts/copilot-statusline.sh"
|
|
165
176
|
},
|
|
166
177
|
"peerDependenciesMeta": {
|
|
167
178
|
"@earendil-works/pi-ai": {
|