@junghanacs/entwurf 0.19.0 → 0.20.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.
Files changed (59) hide show
  1. package/AGENTS.md +1 -1
  2. package/BASELINE.md +23 -5
  3. package/CHANGELOG.md +236 -0
  4. package/DELIVERY.md +59 -6
  5. package/README.md +40 -9
  6. package/VERIFY.md +9 -1
  7. package/docs/acp-backend-rail.md +9 -1
  8. package/docs/external-mcp-host.md +6 -3
  9. package/docs/setup-clean-host.md +93 -7
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +3 -3
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +6 -2
  12. package/package.json +2 -2
  13. package/pi-extensions/acp-provider.ts +1 -1
  14. package/pi-extensions/lib/acp/models.ts +3 -3
  15. package/pi-extensions/lib/acp/overlay.ts +6 -2
  16. package/pi-extensions/lib/meta-session.ts +25 -0
  17. package/run.sh +71 -26
  18. package/scripts/agy-bridge.sh +1 -1
  19. package/scripts/agy-imprint.sh +10 -7
  20. package/scripts/check-acp-carrier-augment.ts +6 -5
  21. package/scripts/check-acp-cortex.ts +41 -0
  22. package/scripts/check-acp-provider-surface.ts +9 -6
  23. package/scripts/check-copilot-birth-hook.ts +3 -1
  24. package/scripts/check-copilot-receive-arm.ts +169 -21
  25. package/scripts/check-copilot-statusline.ts +3 -1
  26. package/scripts/check-gate-qualification.ts +10 -9
  27. package/scripts/check-hook-launch-topology.ts +6 -5
  28. package/scripts/check-install-surface.ts +2 -1
  29. package/scripts/check-meta-facts.ts +6 -4
  30. package/scripts/check-meta-hook-session-switch.ts +4 -3
  31. package/scripts/check-meta-identity-consumers.ts +8 -7
  32. package/scripts/check-meta-receiver-marker.ts +2 -1
  33. package/scripts/check-omp-birth-hook.ts +3 -2
  34. package/scripts/check-probe-bridge-command.ts +3 -1
  35. package/scripts/check-setup-qualification.sh +21 -0
  36. package/scripts/copilot-bridge-doctor.sh +15 -5
  37. package/scripts/copilot-bridge-install.sh +6 -2
  38. package/scripts/copilot-launch.sh +16 -2
  39. package/scripts/copilot-receive-bridge.sh +80 -13
  40. package/scripts/lib/reclaim-on-exit.ts +86 -0
  41. package/scripts/meta-bridge-doctor.sh +56 -15
  42. package/scripts/meta-bridge-install.sh +13 -7
  43. package/scripts/meta-bridge-uninstall.sh +6 -4
  44. package/scripts/mutants/acp-cortex.json +26 -2
  45. package/scripts/mutants/copilot-receive.json +26 -0
  46. package/scripts/mutants/omp-birth.json +23 -6
  47. package/scripts/mutants/setup-verdict.json +13 -0
  48. package/scripts/omp-bridge-doctor.sh +110 -41
  49. package/scripts/omp-bridge-install.sh +6 -2
  50. package/scripts/omp-receive-install.sh +7 -2
  51. package/scripts/raw-async-delivery/README.md +10 -1
  52. package/scripts/raw-codex-measure/README.md +689 -0
  53. package/scripts/raw-codex-measure/source-audit.md +243 -0
  54. package/scripts/raw-macos-measure/README.md +148 -0
  55. package/scripts/raw-macos-measure/probe.sh +389 -0
  56. package/scripts/smoke-meta-async-drift.sh +7 -5
  57. package/scripts/smoke-meta-install-state.sh +70 -19
  58. package/scripts/smoke-omp-bridge-state.sh +38 -0
  59. package/scripts/smoke-setup-verdict.sh +100 -0
@@ -1,8 +1,18 @@
1
1
  # Clean-host setup
2
2
 
3
- Current operator recipe for a fresh Linux desktop/workstation. The neutral npm
4
- package can install elsewhere, but Claude's garden-native meta-bridge is certified
5
- only on Linux because its strict live-owner join uses `/proc`.
3
+ Operator recipe for a POSIX host. **Linux is the certified axis** — §2–§6 are
4
+ written for it and their receipts are Linux receipts. What follows is the macOS
5
+ evidence split, and its three states must not collapse into "macOS is supported":
6
+
7
+ - **CERTIFIED (CI)** — the Entwurf-only install surface on macOS
8
+ (`macos-install-surface`). Weaker than a physical-host doctor green. §1 is
9
+ this surface.
10
+ - **NOT CERTIFIED — pending physical host** — **on macOS**, every garden-native
11
+ harness rail in §2–§6 (pi, Claude, Copilot, OMP, agy), marker join, ACP turn,
12
+ mux. Wiring may be written; that is not a rail receipt. The remaining
13
+ unmeasured Darwin doctor reason is per-process environment DISCOVERY
14
+ (start-key is portable).
15
+ - **UNSUPPORTED** — native Windows only. macOS is never this.
6
16
 
7
17
  ## Requirements
8
18
 
@@ -22,8 +32,35 @@ only on Linux because its strict live-owner join uses `/proc`.
22
32
  Claude Code >=2.1.217 is required for the managed exec-hook lifecycle. The package
23
33
  never supplies or proxies backend credentials.
24
34
 
35
+ On a physical Darwin host, `python3` may be the CommandLineTools stub (a
36
+ dialog instead of an interpreter) — unmeasured. That is a probe cell
37
+ (`scripts/raw-macos-measure/probe.sh` M3), not a certification path.
38
+
25
39
  ## 1. Install Node and entwurf
26
40
 
41
+ This section is the Entwurf-only install surface. On macOS it is
42
+ **CERTIFIED (CI)** (`macos-install-surface`): npm pack → clean consumer
43
+ install → bins → `--help` → `check-bridge` → harness-absent `setup`. That
44
+ is not a harness-rail receipt.
45
+
46
+ On Darwin, `entwurf setup` is intentionally non-green when it detects a
47
+ harness. The wiring is written; the row is FAIL:
48
+
49
+ > the wiring WAS written and nothing failed to install, but this harness
50
+ > rail is NOT CERTIFIED — pending physical host on Darwin. setup runs no
51
+ > doctor; the rail axis is owned by '<doctor>', which refuses on this
52
+ > platform. Tracking: #78.
53
+
54
+ That FAIL is honest: setup runs no doctor, and no physical-host rail
55
+ receipt exists — it is not an install failure. An Entwurf-only host (no
56
+ harness on PATH) stays green (five SKIP, `bins: PASS`, `core: PASS`,
57
+ `result: green`), which is what CERTIFIED (CI) observed.
58
+
59
+ A physical Mac can send host facts without installing entwurf or logging
60
+ into a harness: `scripts/raw-macos-measure/probe.sh` (`/bin/sh`, ~3.5s,
61
+ cells M1–M9, writes nothing). Measurement, not certification — it does
62
+ not move CERTIFIED (CI) or close a rail.
63
+
27
64
  Use the host's normal Node 24 installation. With nvm:
28
65
 
29
66
  ```bash
@@ -107,6 +144,12 @@ packageRoot↔installerRoot coupling mismatch and a package/provider managed-pat
107
144
 
108
145
  ## 2. Optional pi adapter / ACP plugin
109
146
 
147
+ This rail is CERTIFIED on Linux; on macOS it is NOT CERTIFIED — pending
148
+ physical host. Control sockets, mux, and ACP plugin hosting have no
149
+ physical-Darwin receipt. `entwurf install` may write `.pi/settings.json`
150
+ on Darwin; that is wiring, not a rail receipt. If `pi` is on PATH,
151
+ `setup` names the pi row FAIL with the §1 Darwin wording.
152
+
110
153
  Install the exact release floor, then wire the project:
111
154
 
112
155
  ```bash
@@ -134,6 +177,9 @@ The V3 record births the garden id; do not inject a pi session id manually.
134
177
 
135
178
  ## 3. Optional Claude Code native citizen
136
179
 
180
+ This rail is CERTIFIED on Linux; on macOS it is NOT CERTIFIED — pending physical
181
+ host (see the end of this section).
182
+
137
183
  First register the MCP bridge if the stable bin is not already present:
138
184
 
139
185
  ```bash
@@ -159,12 +205,21 @@ validation, or hand-inspected marker cannot replace a new real session. If the l
159
205
  form is unsupported, reinstall; if ownership is correct but the live join is absent,
160
206
  restart the affected session.
161
207
 
162
- New macOS wiring is refused because the live join is not instrumented there. Darwin
163
- uninstall remains available for cleaning an older managed install; this is an evidence
164
- boundary, not a permanent impossibility claim.
208
+ The Darwin install fence is open (`Linux | Darwin`); python3 is the
209
+ refusal, not the platform name. A completed Darwin install is still not
210
+ a rail receipt: this rail is NOT CERTIFIED — pending physical host. The
211
+ remaining unmeasured doctor reason is per-process environment DISCOVERY
212
+ of live bridge children (start-key is portable). A CI runner cannot
213
+ supply a Claude login. Uninstall is open on Darwin too. That is an
214
+ evidence boundary, not UNSUPPORTED.
165
215
 
166
216
  ## 4. Optional GitHub Copilot CLI native citizen
167
217
 
218
+ This rail is CERTIFIED on Linux; on macOS it is NOT CERTIFIED — pending
219
+ physical host. The Darwin install fence for `install-copilot-bridge` is
220
+ open (`Linux | Darwin`); a completed install is not a rail receipt. That
221
+ is an evidence boundary, not UNSUPPORTED.
222
+
168
223
  Copilot has four independently owned surfaces. `setup` composes all four when `copilot` is on
169
224
  PATH (#86 C3b); the commands below are the per-unit repair, doctor, and inverse surfaces. All
170
225
  four must be green for supported visible fresh; a manual citizen may omit the footer, but fresh
@@ -187,7 +242,12 @@ scanning for that process, checks the receiver, removes inherited pi identity ca
187
242
  the model/permission defaults. Birth occurs on the first prompt. `entwurf_fresh_call` uses this
188
243
  same managed invocation and requires the birth, MCP, receiver, and visible-identity preflight.
189
244
 
190
- ## 4b. Optional OMP (`omp`) native citizen — accepted on one host
245
+ ## 4b. Optional OMP (`omp`) native citizen — accepted on one Linux host (thinkpad)
246
+
247
+ This rail is CERTIFIED on Linux (one host, named in the version rule
248
+ below); on macOS it is NOT CERTIFIED — pending physical host. The Darwin
249
+ install fences for `install-omp-bridge` and `install-omp-receive` are
250
+ open (`Linux | Darwin`); a completed install is not a rail receipt.
191
251
 
192
252
  Three independently owned surfaces, and a boundary that is part of the instructions rather
193
253
  than a footnote. Birth, visible identity, who-sent, the MCP hand and RECEIVE are landed, and
@@ -338,6 +398,10 @@ why `disabledServers` is never the way to hide an import.
338
398
 
339
399
  ## 5. Optional Antigravity native citizen
340
400
 
401
+ This rail is CERTIFIED on Linux; on macOS it is NOT CERTIFIED — pending
402
+ physical host. The installers may write on Darwin; a green install is
403
+ not a native-push receipt.
404
+
341
405
  Install the three independently owned surfaces:
342
406
 
343
407
  ```bash
@@ -363,6 +427,10 @@ LIVE=1 AGY_CONVERSATION_ID=<id> entwurf smoke-agy-native-push-live
363
427
 
364
428
  ## 6. Optional ACP backend turns
365
429
 
430
+ ACP turns are CERTIFIED on Linux; on macOS they are NOT CERTIFIED —
431
+ pending physical host. Mux (visible fresh / resume) is the same state.
432
+ A CI runner has no Claude or Cortex login.
433
+
366
434
  Claude uses the operator's existing local Claude authentication:
367
435
 
368
436
  ```bash
@@ -386,6 +454,15 @@ After upgrading the package, rerun the managed installers for every native harne
386
454
  in use and restart their existing processes. Native plugin caches are not live-reload
387
455
  safe across launch-contract changes.
388
456
 
457
+ On Darwin the four previously closed install fences
458
+ (`install-meta-bridge`, `install-copilot-bridge`, `install-omp-bridge`,
459
+ `install-omp-receive`) now accept `Linux | Darwin` and refuse on the
460
+ real toolchain (python3 / node / harness presence), not the platform
461
+ name. Re-running them writes wiring. `setup` still names every detected
462
+ harness unit FAIL with the §1 Darwin wording — upgrade does not mint a
463
+ rail receipt. Doctors refuse on Darwin until a physical-host receipt
464
+ exists.
465
+
389
466
  If install or doctor reports an unreadable/old active citizen generation, do not edit
390
467
  records by hand. Close pi, Claude, Copilot, and agy sessions first, run
391
468
  `entwurf meta-bridge-fresh-cut`, and read its exit status before any install. Then choose the
@@ -414,6 +491,10 @@ PASS/SKIP/FAIL summary. The complete quiescence, archive, and exit-code contract
414
491
  core / full candidate floor); maintainer checkout only.
415
492
  - `check-install-container`: checkout-invisible Linux package-consumer shape using
416
493
  fixtures; not a native lifecycle proof.
494
+ - `macos-install-surface`: macOS Entwurf-only package-consumer shape, CERTIFIED (CI)
495
+ (`macos-latest` runner, run 34303884286 @ `70eda03`); not a native lifecycle proof.
496
+ - `scripts/raw-macos-measure/probe.sh`: physical-Darwin host facts (~3.5s,
497
+ no install, no login). Measurement, not a certification path.
417
498
  - `doctor-meta-bridge`: one installed real Claude host, only with a new live session.
418
499
  - `LIVE=1 entwurf release-gate /path/to/scratch --cut`: aggregate runtime acceptance (`--cut` makes any MUST SKIP red; without it the run is a diagnostic pass).
419
500
 
@@ -422,6 +503,11 @@ host verdicts are [BASELINE.md](../BASELINE.md).
422
503
 
423
504
  ## Uninstall
424
505
 
506
+ Darwin uninstall is open for the same surfaces the installers write
507
+ (the Claude uninstall fence was already open; the four install fences
508
+ now match). Running an inverse on Darwin is cleanup, not a rail
509
+ certification.
510
+
425
511
  Run only the surfaces this host owns:
426
512
 
427
513
  ```bash
@@ -49,11 +49,11 @@ export const ENTWURF_ACP_NO_AUTH_SENTINEL = "entwurf-no-auth";
49
49
  // both axes (protocol smoke + agent interview) — do not extend casually.
50
50
  // Exported so the claude backend adapter (backend-adapter.ts) can answer
51
51
  // `routeModel` without re-deriving the set from curatedClaudeModels().
52
- export const SUPPORTED_ANTHROPIC_MODEL_IDS = ["claude-sonnet-5", "claude-opus-5"];
52
+ export const SUPPORTED_ANTHROPIC_MODEL_IDS = ["claude-sonnet-5", "claude-opus-5", "claude-fable-5-1"];
53
53
  /** The anchor model whose absence is a hard registry regression, not a soft skip. */
54
54
  export const CURATED_ANCHOR_MODEL_ID = "claude-opus-5";
55
- // Anthropic's registry reports 1M for both Sonnet 5 and Opus 5, and the
56
- // entwurf surface exposes the full 1M for BOTH. Sonnet 5's 1M window is the
55
+ // Anthropic's registry reports 1M for Sonnet 5, Opus 5 and Fable 5.1, and the
56
+ // entwurf surface exposes the full 1M for all three. Sonnet 5's 1M window is the
57
57
  // whole point of the 0.12.3 bump — it is the compact-free long-context floor the
58
58
  // earlier 200K Sonnet cap could not provide. We still clamp to a 1M ceiling so a
59
59
  // future registry value can't silently inflate the surface past what we verify.
@@ -35,7 +35,7 @@
35
35
  import { createHash } from "node:crypto";
36
36
  import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, rmSync, symlinkSync, unlinkSync, writeFileSync, } from "node:fs";
37
37
  import { homedir } from "node:os";
38
- import { join } from "node:path";
38
+ import { isAbsolute, join, win32 } from "node:path";
39
39
  /** Operator's real Claude config dir — the symlink-passthrough SOURCE. */
40
40
  export const CLAUDE_REAL_CONFIG_DIR = join(homedir(), ".claude");
41
41
  /** pi-owned overlay dir — the CLAUDE_CONFIG_DIR target for ACP child spawns. */
@@ -356,7 +356,11 @@ function cortexLinkIfExists(realPath, overlayPath) {
356
356
  * Returns the isolated HOME/SNOWFLAKE_HOME the spawn env must carry.
357
357
  */
358
358
  export function ensureCortexDualHomeOverlay(params) {
359
- if (!params.realHome || !params.realHome.startsWith("/")) {
359
+ // Absoluteness is judged in BOTH path flavors so the guard states the contract
360
+ // ("the parent captured an absolute HOME") instead of the host it happens to run
361
+ // on. This asserts nothing about native-Windows support; it only stops a POSIX
362
+ // host from silently accepting a drive/UNC path as "relative".
363
+ if (!params.realHome || !(isAbsolute(params.realHome) || win32.isAbsolute(params.realHome))) {
360
364
  throw new Error(`entwurf: cortex dual-HOME overlay requires an absolute realHome captured by the parent (got ${JSON.stringify(params.realHome)})`);
361
365
  }
362
366
  const overlaysRoot = params.overlaysRoot ?? CORTEX_OVERLAYS_ROOT;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@junghanacs/entwurf",
3
- "version": "0.19.0",
4
- "description": "Garden-citizen dispatch substrate and meta-bridge for Claude Code, Codex, Antigravity, and pi harnesses.",
3
+ "version": "0.20.0",
4
+ "description": "Garden-citizen dispatch substrate and meta-bridge for pi, Claude Code, Copilot CLI, OMP, and Antigravity; Claude and Snowflake Cortex Code ACP backends. Codex has verified delivery-probe evidence, not a managed native-citizen lane.",
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "name": "Junghan Kim",
@@ -14,7 +14,7 @@
14
14
  // registry (backend-adapter.ts), NOT a per-backend list spelled here. Adding a
15
15
  // backend therefore never edits this file. check-acp-provider-surface pins that
16
16
  // the compiled entry really registers the EXACT union
17
- // ([QK:CORTEX-PROVIDER-SIX-ROW-SURFACE]).
17
+ // ([QK:CORTEX-PROVIDER-EXACT-ROW-SURFACE]).
18
18
  //
19
19
  // Fence: this entry rides the emit-capable root tsconfig (it is not in the root
20
20
  // `exclude` list); its lib modules are imported with `.js` suffixes (the root
@@ -53,13 +53,13 @@ export const ENTWURF_ACP_NO_AUTH_SENTINEL = "entwurf-no-auth";
53
53
  // both axes (protocol smoke + agent interview) — do not extend casually.
54
54
  // Exported so the claude backend adapter (backend-adapter.ts) can answer
55
55
  // `routeModel` without re-deriving the set from curatedClaudeModels().
56
- export const SUPPORTED_ANTHROPIC_MODEL_IDS = ["claude-sonnet-5", "claude-opus-5"] as const;
56
+ export const SUPPORTED_ANTHROPIC_MODEL_IDS = ["claude-sonnet-5", "claude-opus-5", "claude-fable-5-1"] as const;
57
57
 
58
58
  /** The anchor model whose absence is a hard registry regression, not a soft skip. */
59
59
  export const CURATED_ANCHOR_MODEL_ID = "claude-opus-5";
60
60
 
61
- // Anthropic's registry reports 1M for both Sonnet 5 and Opus 5, and the
62
- // entwurf surface exposes the full 1M for BOTH. Sonnet 5's 1M window is the
61
+ // Anthropic's registry reports 1M for Sonnet 5, Opus 5 and Fable 5.1, and the
62
+ // entwurf surface exposes the full 1M for all three. Sonnet 5's 1M window is the
63
63
  // whole point of the 0.12.3 bump — it is the compact-free long-context floor the
64
64
  // earlier 200K Sonnet cap could not provide. We still clamp to a 1M ceiling so a
65
65
  // future registry value can't silently inflate the surface past what we verify.
@@ -46,7 +46,7 @@ import {
46
46
  writeFileSync,
47
47
  } from "node:fs";
48
48
  import { homedir } from "node:os";
49
- import { join } from "node:path";
49
+ import { isAbsolute, join, win32 } from "node:path";
50
50
 
51
51
  import type { AcpMcpServer } from "./config.js";
52
52
 
@@ -416,7 +416,11 @@ function cortexLinkIfExists(realPath: string, overlayPath: string): void {
416
416
  * Returns the isolated HOME/SNOWFLAKE_HOME the spawn env must carry.
417
417
  */
418
418
  export function ensureCortexDualHomeOverlay(params: CortexOverlayParams): CortexOverlayResult {
419
- if (!params.realHome || !params.realHome.startsWith("/")) {
419
+ // Absoluteness is judged in BOTH path flavors so the guard states the contract
420
+ // ("the parent captured an absolute HOME") instead of the host it happens to run
421
+ // on. This asserts nothing about native-Windows support; it only stops a POSIX
422
+ // host from silently accepting a drive/UNC path as "relative".
423
+ if (!params.realHome || !(isAbsolute(params.realHome) || win32.isAbsolute(params.realHome))) {
420
424
  throw new Error(
421
425
  `entwurf: cortex dual-HOME overlay requires an absolute realHome captured by the parent (got ${JSON.stringify(params.realHome)})`,
422
426
  );
@@ -1622,6 +1622,31 @@ export type MarkerOwnerVerdict = "live" | "dead" | "uncertain";
1622
1622
  * comparable to each other: `linux:<starttime ticks since boot>` and `ps:<lstart
1623
1623
  * wall-clock text>` describe the same process with different numbers, so a
1624
1624
  * mismatch ACROSS schemes says nothing about whether the process changed.
1625
+ *
1626
+ * They are also NOT equally resolved. `linux:` carries `/proc` clock ticks at
1627
+ * 10 ms granularity; `ps:` carries `lstart` wall-clock text at ONE-SECOND
1628
+ * granularity [measured, oracle 2026-09-09: two children spawned 50 ms apart
1629
+ * returned identical `lstart` strings, and widening to `lstart=,command=`
1630
+ * still collided when argv was identical]. Darwin has no `/proc`, so it ALWAYS
1631
+ * takes the `ps:` branch — there the pid-reuse defense window is 100x wider
1632
+ * than on Linux. 0.20.0 ships no key change anyway, and the numbers are why.
1633
+ * A same-second pid reuse on Darwin requires pid N to die, the whole
1634
+ * sequential pid space (PID_MAX 99999, wrapping after ~99,899 spawns and
1635
+ * skipping live pids) to wrap back around to N, and the replacement to start
1636
+ * in the SAME wall-clock second — a sustained ~99,900 spawns/second for a full
1637
+ * second. Measured on the reference host: 19.9 forks/second average under real
1638
+ * load, ~14,873 forks/second pathological synthetic peak (6.7x short even at
1639
+ * the synthetic peak), with Darwin's default `kern.maxproc` (~2,500) capping
1640
+ * churn in flight besides. The error direction is one-sided: a coarser clock
1641
+ * can only make more keys compare EQUAL, and {@link classifyMarkerOwner} grants
1642
+ * `live` on equal keys — coarsening can mint a false `live` (identity grant
1643
+ * fails OPEN) and can never mint a false `dead` (the generation cut stays
1644
+ * fail-CLOSED). The migration axis is empty by measurement, not argument: a
1645
+ * read-only scan of this host's real marker store found 1,248 marker files —
1646
+ * all `linux:`, zero `ps:` keys — because on Linux `/proc` always wins, so no
1647
+ * Linux install ever minted a `ps:` key; only a Darwin install can. A
1648
+ * Darwin-side hardening decision, if one is ever wanted, belongs with the
1649
+ * physical-Mac receipts (#78), not ahead of them.
1625
1650
  */
1626
1651
  export type StartKeyScheme = "linux" | "ps";
1627
1652
 
package/run.sh CHANGED
@@ -209,7 +209,7 @@ Usage:
209
209
 
210
210
  ./run.sh install-meta-bridge # INTERNAL part of `setup` (native-harness plugin) + doctor recovery path — prefer `setup`; stateful GLOBAL install (plugin + USER MCP + settings keyset, honest uninstall state)
211
211
  ./run.sh uninstall-meta-bridge # 1.0.0 meta-bridge Phase 2: stateful GLOBAL uninstall (restore only keys/items captured in install-state)
212
- ./run.sh doctor-meta-bridge # THE RELEASE ORACLE (#51, Linux-certified repair axis). exit 0 = every required layer was MEASURED on this Linux host: toolchain + state + plugin/MCP + resolved-artifact launch-form classification (all 3 owner hooks + doorbell static contract) + synthetic owner join + store scan + hook errors + SessionStart evidence + REQUIRED live MCP↔marker join + writer-version parity. Missing live evidence is NOT CERTIFIED (open a Claude session and re-run), never a pass; Darwin is not yet verified/certified and stays nonzero for this cut (future validation may reopen it). Detection power is held by check-meta-doctor-oracle
212
+ ./run.sh doctor-meta-bridge # THE RELEASE ORACLE (#51, Linux-certified repair axis). exit 0 = every required layer was MEASURED on this Linux host: toolchain + state + plugin/MCP + resolved-artifact launch-form classification (all 3 owner hooks + doorbell static contract) + synthetic owner join + store scan + hook errors + SessionStart evidence + REQUIRED live MCP↔marker join + writer-version parity. Missing live evidence is NOT CERTIFIED (open a Claude session and re-run), never a pass; Darwin is NOT CERTIFIED and stays nonzero, on ONE narrowed reason — start-key and ppid are portable there (`ps` fallback, same string the TS core mints), so what holds the lane closed is per-process environment DISCOVERY alone, pending physical-host evidence. Detection power is held by check-meta-doctor-oracle
213
213
  ./run.sh copilot [args...] # #82 RAIL 7: the MANAGED Copilot launch. exec()s the vendor CLI in THIS terminal (cwd/pid/exit preserved) with COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS set for that one invocation — entwurf owns no part of your shell and writes nothing to it, but it owns the process it is about to become. Without that flag Copilot skips the extension scan SILENTLY. Refuses to launch unless the receiver unit is actually installed. Injects `--model auto` when no --model was given and `--yolo` when no explicit permission/surface policy flag was given, both BEFORE any `--`; every argument you pass is forwarded byte-identical. RUNNING THIS IS YOUR CONSENT to that profile — use plain `copilot` for stock vendor behaviour. Not tmux, not fresh-call, mints no citizen (birth is still the first prompt)
214
214
  ./run.sh install-copilot-bridge # #82: GLOBAL install of the Copilot BIRTH plugin (own marketplace root; node+entry baked into the no-argv exec string). MCP wiring and the RECEIVER extension are separate install surfaces (install-copilot-mcp, install-copilot-receive). Also retires the stale Claude unit (--keep-stale-claude-unit opts out)
215
215
  ./run.sh uninstall-copilot-bridge # #86 C3a: honest inverse of install-copilot-bridge from the package-owned install-state (exact qualified id + exact marketplace name/path + recorded assembly only; state deleted LAST; a failing vendor list is UNKNOWN and refuses; never --force, never the stale Claude unit)
@@ -2667,8 +2667,8 @@ check_acp_provider_surface() {
2667
2667
  # provider lib modules AND compiles + drives the REAL entry against a fake pi,
2668
2668
  # asserting: one surface name, the no-auth sentinel shape, full
2669
2669
  # ProviderModelConfig rows on the curated claude anchor, the EXACT curated model
2670
- # set both adapters contribute (claude 2 + cortex 4 —
2671
- # [QK:CORTEX-PROVIDER-SIX-ROW-SURFACE], the claim that catches an entry which
2670
+ # set both adapters contribute (claude 3 + cortex 4 —
2671
+ # [QK:CORTEX-PROVIDER-EXACT-ROW-SURFACE], the claim that catches an entry which
2672
2672
  # silently drops a whole backend), and that streamSimple is the real
2673
2673
  # streamShellAcp backend (checked BY NAME, never invoked — invoking spawns an
2674
2674
  # ACP child). Pure, no pi runtime, no API.
@@ -3564,6 +3564,7 @@ _check_pack_install_impl() {
3564
3564
  local loader_ids loader_expected
3565
3565
  loader_ids=$(awk '$1 == "entwurf" { print $2 }' <<<"$loader_out" | LC_ALL=C sort)
3566
3566
  loader_expected=$(printf '%s\n' \
3567
+ claude-fable-5-1 \
3567
3568
  claude-opus-5 \
3568
3569
  claude-sonnet-5 \
3569
3570
  cortex-auto \
@@ -3571,7 +3572,7 @@ _check_pack_install_impl() {
3571
3572
  cortex-claude-sonnet-5 \
3572
3573
  cortex-openai-gpt-5.4 | LC_ALL=C sort)
3573
3574
  if [ "$loader_ids" != "$loader_expected" ]; then
3574
- fail "[check-pack-install] installed provider model set drifted — expected exactly 6 curated ids (claude 2 + cortex 4):"
3575
+ fail "[check-pack-install] installed provider model set drifted — expected exactly 7 curated ids (claude 3 + cortex 4):"
3575
3576
  echo " expected:" >&2
3576
3577
  echo "$loader_expected" | sed 's/^/ /' >&2
3577
3578
  echo " actual (entwurf rows):" >&2
@@ -3582,8 +3583,8 @@ _check_pack_install_impl() {
3582
3583
  fi
3583
3584
  # Name the set on SUCCESS too, not only in the failure branch — same principle as
3584
3585
  # the pinned-pi version assert above: a gate that cannot name what it proved has
3585
- # proved nothing, and "6 rows" without the ids cannot be audited from a CI log.
3586
- echo "[check-pack-install] pi loader smoke pass (entwurf registered; exact 6-row curated set: claude 2 + cortex 4):"
3586
+ # proved nothing, and a row COUNT without the ids cannot be audited from a CI log.
3587
+ echo "[check-pack-install] pi loader smoke pass (entwurf registered; exact curated set: claude 3 + cortex 4):"
3587
3588
  echo "$loader_ids" | sed 's/^/ /'
3588
3589
 
3589
3590
  # npm-managed neutral install regression — the README's PRIMARY install path is
@@ -4815,6 +4816,44 @@ setup_result() { # $1=component $2=PASS|SKIP|FAIL $3=detail
4815
4816
  esac
4816
4817
  }
4817
4818
 
4819
+ # ── platform rail certification (#78 D1) ─────────────────────────────────────
4820
+ # ONE place answers "are entwurf's HARNESS RAILS certified on this platform?".
4821
+ # Every detected-harness branch in setup_all asks it through setup_harness_result
4822
+ # below instead of re-deciding it per backend — a verdict that is honest for one
4823
+ # harness and cosmetic for the next is its own defect, not half a fix.
4824
+ #
4825
+ # Today the answer is Linux and nothing else, and that is an EVIDENCE fact, not a
4826
+ # taste: every shipped rail proves live ownership by reading the per-process
4827
+ # ENVIRONMENT of live harness children, no portable Darwin equivalent has been
4828
+ # MEASURED, and BASELINE.md/README record each rail as `NOT CERTIFIED — pending
4829
+ # physical host`. The harness doctors own that axis and refuse on Darwin.
4830
+ #
4831
+ # What moves this line: a physical-host receipt — a real harness doctor exiting 0
4832
+ # on that platform, recorded in BASELINE.md. A green INSTALLER never moves it;
4833
+ # installation portability and rail/runtime support are separate evidence axes
4834
+ # (Hard Rule 17). Do not widen this to make a CI job green.
4835
+ harness_rail_certified_platform() {
4836
+ [ "$(uname -s)" = "Linux" ]
4837
+ }
4838
+
4839
+ # setup_harness_result — the verdict for a detected harness unit whose INSTALL
4840
+ # COMPLETED. It exists because "the wiring was written" and "the rail works here"
4841
+ # are two different facts and setup measures only the first: setup runs no doctor
4842
+ # (that is the doctor commands' own job). On a platform whose rails carry no
4843
+ # receipt a completed install is therefore a detected-but-INCOMPLETE integration,
4844
+ # which Hard Rule 17 names non-green rather than cosmetic success. setup_result
4845
+ # has exactly three verdicts, so FAIL IS that named non-green — and the detail
4846
+ # must say so in the operator's own words: nothing failed to install, the rail is
4847
+ # simply uncertified here. The wording stays deliberately distinct from the
4848
+ # install-failure FAIL each branch keeps for a real refusal.
4849
+ setup_harness_result() { # $1=component $2=what got wired $3=doctor owning the rail axis
4850
+ if harness_rail_certified_platform; then
4851
+ setup_result "$1" PASS "$2 — verify: $3"
4852
+ return 0
4853
+ fi
4854
+ setup_result "$1" FAIL "$2 — the wiring WAS written and nothing failed to install, but this harness rail is NOT CERTIFIED — pending physical host on $(uname -s). setup runs no doctor; the rail axis is owned by '$3', which refuses on this platform. Tracking: #78."
4855
+ }
4856
+
4818
4857
  # Installed-vs-source is decided by PACKAGE LOCATION — the same `*/node_modules/*`
4819
4858
  # seam run_ts and the bridge launcher already branch on — never by which of
4820
4859
  # pnpm/pi happens to be missing (an accidental failure is not a mode gate).
@@ -4955,7 +4994,7 @@ setup_all() {
4955
4994
  if ! pi_version_in_range "${pi_ver:-0}" "$pi_range"; then
4956
4995
  setup_result pi FAIL "detected pi ${pi_ver:-<unreadable version>} is outside the supported range $pi_range — Pi wiring not written; align pi, then re-run setup"
4957
4996
  elif (install_local_package "$project_dir"); then
4958
- setup_result pi PASS "project + user-scope wiring complete (pi $pi_ver in $pi_range) — verify: ./run.sh doctor-pi-provider"
4997
+ setup_harness_result pi "project + user-scope wiring complete (pi $pi_ver in $pi_range)" "./run.sh doctor-pi-provider"
4959
4998
  else
4960
4999
  setup_result pi FAIL "pi wiring did not complete (see above) — repair, then re-run setup"
4961
5000
  fi
@@ -4965,16 +5004,20 @@ setup_all() {
4965
5004
  # setup ALSO wires the native-harness meta-bridge so a relocate/clone needs ONE
4966
5005
  # command. Detection-gated ("있으면 설정, 없으면 담아준다");
4967
5006
  # meta-bridge-install.sh is idempotent and enforces the Claude floor + its own
4968
- # named prerequisites itself, so a below-floor or refused host lands here as a
4969
- # detected FAIL, never a cosmetic green. CLAUDE_BIN pins the probe for the
4970
- # hermetic smoke; production leaves it unset.
5007
+ # named prerequisites itself, so a below-floor host lands here as a detected
5008
+ # FAIL. It no longer REFUSES ON PLATFORM NAME (0.20.0 opened Darwin: the
5009
+ # installer's own mechanism is portable), so the other half of that old
5010
+ # guarantee — "never a cosmetic green" — is now carried by setup_harness_result:
5011
+ # an install that completes where the RAIL has no receipt is the named
5012
+ # non-green, never a PASS pointing at a doctor that would refuse. CLAUDE_BIN
5013
+ # pins the probe for the hermetic smoke; production leaves it unset.
4971
5014
  local claude_bin="${CLAUDE_BIN:-claude}"
4972
5015
  if ! command -v "$claude_bin" >/dev/null 2>&1; then
4973
5016
  setup_result claude SKIP "claude not on PATH — zero meta-bridge wiring written"
4974
5017
  else
4975
5018
  section "meta-bridge install (native harness detected: Claude Code)"
4976
5019
  if (cd "$REPO_DIR" && bash scripts/meta-bridge-install.sh); then
4977
- setup_result claude PASS "meta-bridge wired — verify: ./run.sh doctor-meta-bridge"
5020
+ setup_harness_result claude "meta-bridge wired" "./run.sh doctor-meta-bridge"
4978
5021
  else
4979
5022
  setup_result claude FAIL "detected Claude Code, but the meta-bridge integration did not complete (see above) — repair, then re-run setup"
4980
5023
  fi
@@ -5017,19 +5060,19 @@ setup_all() {
5017
5060
  else
5018
5061
  agy_rc=0; wire_agy_bridge || agy_rc=$?
5019
5062
  if [ "$agy_rc" -eq 0 ]; then
5020
- setup_result agy-bridge PASS "MCP bridge wired — verify: ./run.sh doctor-agy-bridge"
5063
+ setup_harness_result agy-bridge "MCP bridge wired" "./run.sh doctor-agy-bridge"
5021
5064
  else
5022
5065
  setup_result agy-bridge FAIL "detected agy, but the MCP bridge integration did not complete (reason above) — repair, then re-run setup"
5023
5066
  fi
5024
5067
  agy_rc=0; wire_agy_statusline || agy_rc=$?
5025
5068
  if [ "$agy_rc" -eq 0 ]; then
5026
- setup_result agy-statusline PASS "statusLine wired — verify: ./run.sh doctor-agy-statusline"
5069
+ setup_harness_result agy-statusline "statusLine wired" "./run.sh doctor-agy-statusline"
5027
5070
  else
5028
5071
  setup_result agy-statusline FAIL "detected agy, but the statusLine integration did not complete (reason above) — repair, then re-run setup"
5029
5072
  fi
5030
5073
  agy_rc=0; wire_agy_hooks || agy_rc=$?
5031
5074
  if [ "$agy_rc" -eq 0 ]; then
5032
- setup_result agy-hooks PASS "birth imprint wired — verify: ./run.sh doctor-agy-hooks"
5075
+ setup_harness_result agy-hooks "birth imprint wired" "./run.sh doctor-agy-hooks"
5033
5076
  else
5034
5077
  setup_result agy-hooks FAIL "detected agy, but the birth-imprint integration did not complete (reason above) — repair, then re-run setup"
5035
5078
  fi
@@ -5053,13 +5096,13 @@ setup_all() {
5053
5096
  section "copilot units (native harness detected: GitHub Copilot CLI)"
5054
5097
  copilot_rc=0; (cd "$REPO_DIR" && bash scripts/copilot-bridge-install.sh) || copilot_rc=$?
5055
5098
  if [ "$copilot_rc" -eq 0 ]; then
5056
- setup_result copilot-birth PASS "birth plugin installed — verify: ./run.sh doctor-copilot-bridge"
5099
+ setup_harness_result copilot-birth "birth plugin installed" "./run.sh doctor-copilot-bridge"
5057
5100
  else
5058
5101
  setup_result copilot-birth FAIL "detected copilot, but the birth plugin install did not complete (see above) — repair, then re-run setup"
5059
5102
  fi
5060
5103
  copilot_rc=0; (cd "$REPO_DIR" && bash scripts/copilot-mcp-bridge.sh install) || copilot_rc=$?
5061
5104
  if [ "$copilot_rc" -eq 0 ]; then
5062
- setup_result copilot-mcp PASS "MCP server registered — verify: ./run.sh doctor-copilot-mcp"
5105
+ setup_harness_result copilot-mcp "MCP server registered" "./run.sh doctor-copilot-mcp"
5063
5106
  else
5064
5107
  setup_result copilot-mcp FAIL "detected copilot, but the MCP registration did not complete (see above) — repair, then re-run setup"
5065
5108
  fi
@@ -5077,14 +5120,14 @@ setup_all() {
5077
5120
  else
5078
5121
  copilot_rc=0; (cd "$REPO_DIR" && bash scripts/copilot-receive-bridge.sh install) || copilot_rc=$?
5079
5122
  if [ "$copilot_rc" -eq 0 ]; then
5080
- setup_result copilot-receive PASS "receiver extension installed — verify: ./run.sh doctor-copilot-receive"
5123
+ setup_harness_result copilot-receive "receiver extension installed" "./run.sh doctor-copilot-receive"
5081
5124
  else
5082
5125
  setup_result copilot-receive FAIL "detected copilot, but the receiver extension install did not complete (see above) — repair, then re-run setup"
5083
5126
  fi
5084
5127
  fi
5085
5128
  copilot_rc=0; (cd "$REPO_DIR" && bash scripts/copilot-statusline-bridge.sh install) || copilot_rc=$?
5086
5129
  if [ "$copilot_rc" -eq 0 ]; then
5087
- setup_result copilot-statusline PASS "visible footer wired — verify: ./run.sh doctor-copilot-statusline"
5130
+ setup_harness_result copilot-statusline "visible footer wired" "./run.sh doctor-copilot-statusline"
5088
5131
  else
5089
5132
  setup_result copilot-statusline FAIL "detected copilot, but the visible-footer integration did not complete (see above) — repair, then re-run setup"
5090
5133
  fi
@@ -5107,13 +5150,13 @@ setup_all() {
5107
5150
  section "omp units (native harness detected: oh-my-pi)"
5108
5151
  omp_rc=0; (cd "$REPO_DIR" && bash scripts/omp-bridge-install.sh) || omp_rc=$?
5109
5152
  if [ "$omp_rc" -eq 0 ]; then
5110
- setup_result omp-birth PASS "birth extension installed — verify: ./run.sh doctor-omp-bridge"
5153
+ setup_harness_result omp-birth "birth extension installed" "./run.sh doctor-omp-bridge"
5111
5154
  else
5112
5155
  setup_result omp-birth FAIL "detected omp, but the birth extension install did not complete (see above) — repair, then re-run setup"
5113
5156
  fi
5114
5157
  omp_rc=0; (cd "$REPO_DIR" && bash scripts/omp-mcp-bridge.sh install) || omp_rc=$?
5115
5158
  if [ "$omp_rc" -eq 0 ]; then
5116
- setup_result omp-mcp PASS "MCP server registered — verify: ./run.sh doctor-omp-mcp"
5159
+ setup_harness_result omp-mcp "MCP server registered" "./run.sh doctor-omp-mcp"
5117
5160
  else
5118
5161
  setup_result omp-mcp FAIL "detected omp, but the MCP registration did not complete (see above) — repair, then re-run setup"
5119
5162
  fi
@@ -5124,13 +5167,13 @@ setup_all() {
5124
5167
  # shipping a citizen whose tools nobody can call.
5125
5168
  omp_rc=0; (cd "$REPO_DIR" && bash scripts/omp-config-xdev.sh install) || omp_rc=$?
5126
5169
  if [ "$omp_rc" -eq 0 ]; then
5127
- setup_result omp-config PASS "tools.xdev: false written — verify: ./run.sh doctor-omp-mcp"
5170
+ setup_harness_result omp-config "tools.xdev: false written" "./run.sh doctor-omp-mcp"
5128
5171
  else
5129
5172
  setup_result omp-config FAIL "detected omp, but the tools.xdev operator setting did not land (see above) — resolve it, then re-run setup"
5130
5173
  fi
5131
5174
  omp_rc=0; (cd "$REPO_DIR" && bash scripts/omp-receive-install.sh) || omp_rc=$?
5132
5175
  if [ "$omp_rc" -eq 0 ]; then
5133
- setup_result omp-receive PASS "receiver extension installed — verify: ./run.sh doctor-omp-receive"
5176
+ setup_harness_result omp-receive "receiver extension installed" "./run.sh doctor-omp-receive"
5134
5177
  else
5135
5178
  setup_result omp-receive FAIL "detected omp, but the receiver extension install did not complete (see above) — repair, then re-run setup"
5136
5179
  fi
@@ -6202,10 +6245,12 @@ case "$cmd" in
6202
6245
  # XDG data dir ($XDG_DATA_HOME/entwurf/meta-bridge/.assembled — dev clone and
6203
6246
  # installed package alike, never the checkout) and runs marketplace add +
6204
6247
  # install --scope user, so every native Claude Code session auto-loads it.
6205
- # Idempotent; Linux is the only currently certified axis for the #51 repair cut.
6206
- # Darwin fails loud as not-yet-verified because the strict doctor cannot currently
6207
- # certify its live owner join; future validation may reopen it. Uninstall permits Darwin
6208
- # so an older macOS install is not stranded without an honest inverse.
6248
+ # Idempotent. Install accepts Linux | Darwin the fence that remains inside the
6249
+ # installer is the toolchain check (python3/node/claude presence), not the platform
6250
+ # name. Rail certification stays with doctor-meta-bridge: Darwin is NOT CERTIFIED
6251
+ # pending physical host, reason = per-process environment DISCOVERY. Uninstall
6252
+ # permits Darwin so an older macOS install is not stranded without an honest
6253
+ # inverse.
6209
6254
  (cd "$REPO_DIR" && bash scripts/meta-bridge-install.sh "$@")
6210
6255
  ;;
6211
6256
  uninstall-meta-bridge)
@@ -233,7 +233,7 @@ doctor_static_one() {
233
233
  # entwurf does NOT repair a failed launcher here: it may be owned by a foreign file.
234
234
  log " $label: configured → '$cmd' does NOT serve MCP with its configured args/env$link_note"
235
235
  log " $BOOT_DETAIL"
236
- log " Identify the launcher: command -v '$cmd'; readlink -f \"\$(command -v '$cmd')\""
236
+ log " Identify the launcher: command -v '$cmd'; ls -l \"\$(command -v '$cmd')\""
237
237
  log " If it is entwurf's managed dev link, restore it with ./run.sh expose-dev-bin (it REFUSES a foreign link)."
238
238
  log " If a foreign launcher owns the name, repair/remove it yourself or put a working one earlier on PATH."
239
239
  return 1 ;;
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env bash
2
2
  # Stable bin wrapper for Antigravity PreInvocation birth imprint.
3
3
  set -euo pipefail
4
- SELF="${BASH_SOURCE[0]}"
5
- if command -v readlink >/dev/null 2>&1; then
6
- RESOLVED="$(readlink -f "$SELF" 2>/dev/null || printf '%s' "$SELF")"
7
- else
8
- RESOLVED="$SELF"
9
- fi
10
- HERE="$(cd "$(dirname "$RESOLVED")" && pwd)"
4
+ SOURCE="${BASH_SOURCE[0]}"
5
+ while [ -L "$SOURCE" ]; do
6
+ DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
7
+ TARGET="$(readlink "$SOURCE")"
8
+ case "$TARGET" in
9
+ /*) SOURCE="$TARGET" ;;
10
+ *) SOURCE="$DIR/$TARGET" ;;
11
+ esac
12
+ done
13
+ HERE="$(cd -P "$(dirname "$SOURCE")" && pwd)"
11
14
  ROOT="$(cd "$HERE/.." && pwd)"
12
15
 
13
16
  # Node refuses --experimental-strip-types for raw .ts below node_modules. Dev
@@ -31,8 +31,9 @@ import { loadEngraving } from "../pi-extensions/lib/acp/engraving.ts";
31
31
  import { bridgeConfigSignature, contextMessageSignatures } from "../pi-extensions/lib/acp/session-store.ts";
32
32
  import { buildClaudeSessionMeta } from "../pi-extensions/lib/acp/tool-surface.ts";
33
33
  import { ENTWURF_PROJECT_CONTEXT_OPEN_TAG } from "../protocol.js";
34
+ import { reclaimOnExit } from "./lib/reclaim-on-exit.ts";
34
35
 
35
- const tmp = mkdtempSync(join(tmpdir(), "acp-carrier-augment-"));
36
+ const tmp = reclaimOnExit(mkdtempSync(join(tmpdir(), "acp-carrier-augment-")));
36
37
  const REPO_DIR = fileURLToPath(new URL("..", import.meta.url));
37
38
  const BRIDGE_MARK = "operating through entwurf";
38
39
 
@@ -241,8 +242,8 @@ function ctxWith(firstUser: string): Context {
241
242
  // absent → keep it. Home AGENTS.md always survives.
242
243
  // ===========================================================================
243
244
  {
244
- const home = mkdtempSync(join(tmpdir(), "acp-home-"));
245
- const proj = mkdtempSync(join(tmpdir(), "acp-proj-"));
245
+ const home = reclaimOnExit(mkdtempSync(join(tmpdir(), "acp-home-")));
246
+ const proj = reclaimOnExit(mkdtempSync(join(tmpdir(), "acp-proj-")));
246
247
  writeFileSync(join(home, "AGENTS.md"), "HOME-AGENTS-CONTENT");
247
248
  writeFileSync(join(proj, "AGENTS.md"), "CWD-AGENTS-CONTENT");
248
249
 
@@ -295,7 +296,7 @@ function ctxWith(firstUser: string): Context {
295
296
  assert.match(dateLine as string, /^Current date: \d{4}-\d{2}-\d{2}$/, "date is day-granularity only (no clock time)");
296
297
 
297
298
  // > 50KB cwd AGENTS.md → augment truncated with the marker.
298
- const bigHome = mkdtempSync(join(tmpdir(), "acp-big-"));
299
+ const bigHome = reclaimOnExit(mkdtempSync(join(tmpdir(), "acp-big-")));
299
300
  writeFileSync(join(bigHome, "AGENTS.md"), "X".repeat(80 * 1024));
300
301
  const big = buildPiContextAugment({ backend: "claude", cwd: tmp, mcpServerNames: [], homeDir: bigHome });
301
302
  assert.ok(Buffer.byteLength(big, "utf8") <= 50 * 1024, "augment is truncated to the 50KB cap");
@@ -313,7 +314,7 @@ function ctxWith(firstUser: string): Context {
313
314
  // remains an honest fallback; the maintained package prompt must not hit it.
314
315
  // ===========================================================================
315
316
  {
316
- const budgetHome = mkdtempSync(join(tmpdir(), "acp-budget-home-"));
317
+ const budgetHome = reclaimOnExit(mkdtempSync(join(tmpdir(), "acp-budget-home-")));
317
318
  writeFileSync(join(budgetHome, "AGENTS.md"), "H".repeat(12 * 1024));
318
319
  const actual = buildPiContextAugment({
319
320
  backend: "claude",