@junghanacs/entwurf 0.12.9 → 0.13.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 +135 -248
- package/BASELINE.md +46 -7
- package/CHANGELOG.md +35 -0
- package/CONTRIBUTING.md +4 -2
- package/DELIVERY.md +5 -4
- package/README.md +46 -18
- package/VERIFY.md +10 -6
- package/demo/demo.sh +7 -1
- package/docs/setup-clean-host.md +10 -4
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +159 -66
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +148 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +16 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +66 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +190 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +12 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +26 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +10 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +15 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +13 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +31 -41
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +8 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +32 -25
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +5 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +9 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +3 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +17 -20
- package/mcp/entwurf-bridge/src/index.ts +190 -82
- package/package.json +7 -3
- package/pi/settings.reference.json +1 -1
- package/pi-extensions/acp-provider.ts +20 -10
- package/pi-extensions/entwurf-control.ts +69 -27
- package/pi-extensions/lib/acp/augment.ts +60 -2
- package/pi-extensions/lib/acp/backend-adapter.ts +183 -8
- package/pi-extensions/lib/acp/backend.ts +5 -1
- package/pi-extensions/lib/acp/config.ts +19 -5
- package/pi-extensions/lib/acp/engraving.ts +3 -1
- package/pi-extensions/lib/acp/event-mapper.ts +10 -3
- package/pi-extensions/lib/acp/models.ts +69 -7
- package/pi-extensions/lib/acp/overlay.ts +234 -3
- package/pi-extensions/lib/acp/tool-surface.ts +12 -4
- package/pi-extensions/lib/entwurf-core.ts +26 -9
- package/pi-extensions/lib/entwurf-deliverability.ts +10 -6
- package/pi-extensions/lib/entwurf-fact-provider.ts +15 -17
- package/pi-extensions/lib/entwurf-facts.ts +13 -13
- package/pi-extensions/lib/entwurf-resume-args.ts +40 -46
- package/pi-extensions/lib/entwurf-self-address.ts +8 -9
- package/pi-extensions/lib/entwurf-v2-contract-schema.ts +7 -2
- package/pi-extensions/lib/entwurf-v2-contract.ts +32 -25
- package/pi-extensions/lib/entwurf-v2-decider.ts +8 -8
- package/pi-extensions/lib/entwurf-v2-lock.ts +5 -4
- package/pi-extensions/lib/entwurf-v2-production.ts +14 -11
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +3 -1
- package/pi-extensions/lib/meta-session.ts +17 -20
- package/run.sh +200 -62
- package/scripts/agy-bridge-config.py +249 -49
- package/scripts/agy-bridge.sh +59 -14
- package/scripts/check-acp-carrier-augment.ts +34 -2
- package/scripts/check-acp-cortex.ts +668 -0
- package/scripts/check-acp-provider-surface.ts +50 -6
- package/scripts/check-acp-sdk-surface.ts +22 -11
- package/scripts/check-acp-session-reuse.ts +64 -1
- package/scripts/check-agy-permission-matrix.py +655 -0
- package/scripts/check-entwurf-deliverability.ts +9 -6
- package/scripts/check-entwurf-fact-provider.ts +7 -7
- package/scripts/check-entwurf-facts.ts +12 -12
- package/scripts/check-entwurf-resume-args.ts +22 -60
- package/scripts/check-entwurf-self-address.ts +187 -4
- package/scripts/check-entwurf-v2-contract.ts +2 -2
- package/scripts/check-entwurf-v2-production.ts +5 -5
- package/scripts/check-entwurf-v2-spawn-production.ts +6 -2
- package/scripts/check-entwurf-v2-surface.ts +327 -14
- package/scripts/check-gate-qualification.ts +787 -0
- package/scripts/check-meta-identity-consumers.ts +1 -1
- package/scripts/check-probe-cli-shim.ts +879 -0
- package/scripts/check-probe-ordering.ts +2450 -0
- package/scripts/check-shell-quote.ts +5 -4
- package/scripts/fixtures/probe-cli-shim +20 -0
- package/scripts/fixtures/probe-mcp-server.ts +168 -12
- package/scripts/lib/mutation-qualify.ts +794 -0
- package/scripts/lib/probe-acp-turn.ts +207 -0
- package/scripts/lib/probe-cli-shim.ts +464 -0
- package/scripts/lib/probe-cli-target.ts +165 -0
- package/scripts/lib/probe-event-log.ts +383 -0
- package/scripts/lib/probe-verdict.ts +1213 -0
- package/scripts/mutants/acp-augment.json +30 -0
- package/scripts/mutants/acp-cortex.json +196 -0
- package/scripts/mutants/agy-permission.json +144 -0
- package/scripts/mutants/meta-identity.json +17 -0
- package/scripts/mutants/probe-ordering.json +1032 -0
- package/scripts/mutants/self-address.json +59 -0
- package/scripts/mutants/v2-surface.json +87 -0
- package/scripts/smoke-acp-cortex-live.ts +392 -0
- package/scripts/smoke-acp-ordering-probe-live.ts +848 -0
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-acp-v2-send-live.ts +33 -18
- package/scripts/smoke-agy-install-state.sh +205 -20
- package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -2
- package/pi-extensions/lib/entwurf-mailbox-guard.ts +0 -100
- package/scripts/check-entwurf-mailbox-guard.ts +0 -266
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Deterministic gate for the ACP provider registration surface (S0 loader/fence,
|
|
2
|
-
// updated S2c when the real backend replaced the fail-loud stub
|
|
2
|
+
// updated S2c when the real backend replaced the fail-loud stub, and again in
|
|
3
|
+
// 0.13 when cortex joined claude on the adapter rail).
|
|
3
4
|
//
|
|
4
5
|
// Three layers:
|
|
5
6
|
// (1 lib) loads the REAL lib modules and asserts the curated Claude
|
|
@@ -8,10 +9,13 @@
|
|
|
8
9
|
// imports resolve to real emitted `.js`), imports the compiled
|
|
9
10
|
// acp-provider.js, and drives its default export against a fake pi
|
|
10
11
|
// that captures registerProvider — real execution capture of the
|
|
11
|
-
// actual entry, idempotency included,
|
|
12
|
-
//
|
|
12
|
+
// actual entry, idempotency included, the EXACT curated model set
|
|
13
|
+
// BOTH adapters contribute, and that streamSimple is the real
|
|
14
|
+
// streamShellAcp backend (by name, NOT invoked — that spawns);
|
|
13
15
|
// (3 source) an auxiliary source-shape lock on acp-provider.ts.
|
|
14
16
|
//
|
|
17
|
+
// [QK:*] labels mark the claims kill-qualified by scripts/mutants/acp-cortex.json.
|
|
18
|
+
//
|
|
15
19
|
// Layer 2 is the GPT-reviewed resolution to a fence tension: acp-provider.ts
|
|
16
20
|
// imports its lib with `.js` suffixes (the root/jiti runtime convention), which
|
|
17
21
|
// plain `node --experimental-strip-types` cannot resolve to `.ts`. Rather than
|
|
@@ -22,7 +26,7 @@
|
|
|
22
26
|
|
|
23
27
|
import { strict as assert } from "node:assert";
|
|
24
28
|
import { execFileSync } from "node:child_process";
|
|
25
|
-
import { readFileSync, rmSync } from "node:fs";
|
|
29
|
+
import { readFileSync, rmdirSync, rmSync } from "node:fs";
|
|
26
30
|
import { resolve } from "node:path";
|
|
27
31
|
import { pathToFileURL } from "node:url";
|
|
28
32
|
import {
|
|
@@ -30,6 +34,8 @@ import {
|
|
|
30
34
|
curatedClaudeModels,
|
|
31
35
|
ENTWURF_ACP_NO_AUTH_SENTINEL,
|
|
32
36
|
PROVIDER_ID,
|
|
37
|
+
SUPPORTED_ANTHROPIC_MODEL_IDS,
|
|
38
|
+
SUPPORTED_CORTEX_MODEL_IDS,
|
|
33
39
|
} from "../pi-extensions/lib/acp/models.ts";
|
|
34
40
|
|
|
35
41
|
// ---------------------------------------------------------------------------
|
|
@@ -120,6 +126,32 @@ try {
|
|
|
120
126
|
for (const want of ["claude-sonnet-5", CURATED_ANCHOR_MODEL_ID]) {
|
|
121
127
|
assert.ok(capIds.includes(want), `entry model surface missing ${want} (got: ${capIds.join(", ") || "none"})`);
|
|
122
128
|
}
|
|
129
|
+
|
|
130
|
+
// The REAL entry must register the curated rows of EVERY adapter on the rail —
|
|
131
|
+
// claude's 2 unprefixed ids AND cortex's 4 `cortex-` ids. This is the JOIN
|
|
132
|
+
// claim, distinct from the per-backend data claims: check-acp-cortex pins the
|
|
133
|
+
// 4-row cortex curation in models.ts, but nothing there proves those rows
|
|
134
|
+
// actually reach `pi.registerProvider`. An entry that filtered `cortex-` out
|
|
135
|
+
// of `allCuratedModels()` would leave models.ts and check-acp-cortex fully
|
|
136
|
+
// green while the operator's model list silently lost the whole backend.
|
|
137
|
+
//
|
|
138
|
+
// Set comparison (sorted, exact) — not `includes`: a substring/anchor probe
|
|
139
|
+
// cannot see a row that VANISHED, and the cortex ids contain the claude ids as
|
|
140
|
+
// substrings. Expected is derived from the two source id constants so there is
|
|
141
|
+
// one SSOT; the literal 6 below is the independent floor that catches a
|
|
142
|
+
// curation list mutated to empty (which would move expected and captured
|
|
143
|
+
// together).
|
|
144
|
+
const expectedIds = [...SUPPORTED_ANTHROPIC_MODEL_IDS, ...SUPPORTED_CORTEX_MODEL_IDS].slice().sort();
|
|
145
|
+
assert.equal(
|
|
146
|
+
expectedIds.length,
|
|
147
|
+
6,
|
|
148
|
+
`curated id constants must total 6 rows (claude 2 + cortex 4) — got ${expectedIds.length}: ${expectedIds.join(", ")}`,
|
|
149
|
+
);
|
|
150
|
+
assert.deepEqual(
|
|
151
|
+
capIds.slice().sort(),
|
|
152
|
+
expectedIds,
|
|
153
|
+
`[QK:CORTEX-PROVIDER-SIX-ROW-SURFACE] compiled entry must register the EXACT curated set of both adapters (claude 2 + cortex 4) — got: ${capIds.join(", ") || "none"}`,
|
|
154
|
+
);
|
|
123
155
|
assert.equal(typeof cap.cfg.streamSimple, "function", "entry streamSimple must be a function");
|
|
124
156
|
// Regression guard: the entry must wire the REAL backend (streamShellAcp),
|
|
125
157
|
// not the removed S0 stub. We check by name rather than invoking — invoking
|
|
@@ -131,6 +163,17 @@ try {
|
|
|
131
163
|
);
|
|
132
164
|
} finally {
|
|
133
165
|
rmSync(TMP_EMIT, { recursive: true, force: true });
|
|
166
|
+
try {
|
|
167
|
+
// The emit created `.tmp-verify/` as TMP_EMIT's parent. This gate now carries
|
|
168
|
+
// a mutant lane, so it runs inside check-gate-qualification's PURITY-checked
|
|
169
|
+
// snapshot, whose tree manifest walks ignored paths too — a leftover empty
|
|
170
|
+
// parent dir reads as IMPURE drift. Remove it when empty; a concurrent
|
|
171
|
+
// sibling gate's emit keeps it alive and the rmdir just fails.
|
|
172
|
+
// (Same repair as check-acp-cortex / check-acp-session-reuse.)
|
|
173
|
+
rmdirSync(".tmp-verify");
|
|
174
|
+
} catch {
|
|
175
|
+
// non-empty or already gone — fine either way
|
|
176
|
+
}
|
|
134
177
|
}
|
|
135
178
|
|
|
136
179
|
// ---------------------------------------------------------------------------
|
|
@@ -154,6 +197,7 @@ assert.ok(!/backend-stub/.test(entrySrc), "entry must not import the removed S0
|
|
|
154
197
|
|
|
155
198
|
console.log(
|
|
156
199
|
`[check-acp-provider-surface] ok — compiled entry registers ${PROVIDER_ID} once (idempotent) with the no-auth ` +
|
|
157
|
-
`sentinel + curated
|
|
158
|
-
|
|
200
|
+
`sentinel + the EXACT curated set of both adapters (claude ${SUPPORTED_ANTHROPIC_MODEL_IDS.length} incl. ` +
|
|
201
|
+
`${CURATED_ANCHOR_MODEL_ID} + cortex ${SUPPORTED_CORTEX_MODEL_IDS.length}) + real streamShellAcp backend (S2c); ` +
|
|
202
|
+
`claude lib surface verified live (${models.length} model(s))`,
|
|
159
203
|
);
|
|
@@ -4,12 +4,23 @@
|
|
|
4
4
|
// the peer-resolution that makes the Claude ACP adapter satisfiable:
|
|
5
5
|
//
|
|
6
6
|
// @agentclientprotocol/sdk 1.3.0 wire SDK (acp-bridge import source)
|
|
7
|
-
// @agentclientprotocol/claude-agent-acp 0.
|
|
7
|
+
// @agentclientprotocol/claude-agent-acp 0.62.0 Claude adapter (spawn binary)
|
|
8
8
|
// @anthropic-ai/sdk 0.100.1 peer-resolution pin ONLY (see below)
|
|
9
9
|
//
|
|
10
|
+
// 2026-07-27 bump 0.61.0 → 0.62.0: the adapter's own `dist/` is byte-identical
|
|
11
|
+
// across the two releases; 0.62.0 moves only its declared deps
|
|
12
|
+
// (claude-agent-sdk 0.3.217 → 0.3.219; its devDep anthropic sdk, which does not
|
|
13
|
+
// reach us). So this bump is a dependency refresh that carries NO adapter-code
|
|
14
|
+
// change — and specifically NOT a fix for the bundled-MCP readiness race
|
|
15
|
+
// (ROADMAP 🔴): 0.62.0 adds no explicit readiness fence. Effective runtime
|
|
16
|
+
// behavior is NOT claimed identical: the transitive SDK moved, and MCP startup
|
|
17
|
+
// lives inside it, so timing may differ — what is established is only that no
|
|
18
|
+
// new fence was added.
|
|
19
|
+
//
|
|
10
20
|
// The anthropic SDK is NOT an API client / auth surface here. It is a direct
|
|
11
|
-
// dep solely to satisfy @anthropic-ai/claude-agent-sdk@0.3.
|
|
12
|
-
// (>=0.93.0
|
|
21
|
+
// dep solely to satisfy @anthropic-ai/claude-agent-sdk@0.3.219's peer floor
|
|
22
|
+
// (>=0.93.0 — re-measured at 0.3.219, unchanged from 0.3.217, so the 0.100.1
|
|
23
|
+
// pin stands rather than rising mechanically); drop it and the tree resolves a stale 0.91.1 so the peer goes
|
|
13
24
|
// unmet — a failure that would only surface at the first raw turn. The
|
|
14
25
|
// lockfile proves the same shape. Source-level import / API-client
|
|
15
26
|
// instantiation / credential use stays forbidden — asserted in layer (4).
|
|
@@ -43,7 +54,7 @@ const pkg = JSON.parse(read("package.json")) as { dependencies?: Record<string,
|
|
|
43
54
|
const deps = pkg.dependencies ?? {};
|
|
44
55
|
const PINS: Record<string, string> = {
|
|
45
56
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
46
|
-
"@agentclientprotocol/claude-agent-acp": "0.
|
|
57
|
+
"@agentclientprotocol/claude-agent-acp": "0.62.0",
|
|
47
58
|
[ANTHROPIC_SDK]: "0.100.1",
|
|
48
59
|
};
|
|
49
60
|
for (const [name, ver] of Object.entries(PINS)) {
|
|
@@ -63,13 +74,13 @@ for (const [name, ver] of Object.entries(PINS)) {
|
|
|
63
74
|
const lock = read("pnpm-lock.yaml");
|
|
64
75
|
assert.match(
|
|
65
76
|
lock,
|
|
66
|
-
/@agentclientprotocol\/claude-agent-acp@0\.
|
|
67
|
-
"pnpm-lock: claude-agent-acp@0.
|
|
77
|
+
/@agentclientprotocol\/claude-agent-acp@0\.62\.0\(@anthropic-ai\/sdk@0\.100\.1/,
|
|
78
|
+
"pnpm-lock: claude-agent-acp@0.62.0 must peer-resolve @anthropic-ai/sdk@0.100.1 (peer-pin), not the stale 0.91.1",
|
|
68
79
|
);
|
|
69
80
|
assert.match(
|
|
70
81
|
lock,
|
|
71
|
-
/@anthropic-ai\/claude-agent-sdk@0\.3\.
|
|
72
|
-
"pnpm-lock: claude-agent-sdk@0.3.
|
|
82
|
+
/@anthropic-ai\/claude-agent-sdk@0\.3\.219\(@anthropic-ai\/sdk@0\.100\.1/,
|
|
83
|
+
"pnpm-lock: claude-agent-sdk@0.3.219 must peer-resolve @anthropic-ai/sdk@0.100.1 — else its >=0.93.0 peer floor is unmet",
|
|
73
84
|
);
|
|
74
85
|
|
|
75
86
|
// ---------------------------------------------------------------------------
|
|
@@ -108,8 +119,8 @@ const casEntry = adapterRequire.resolve("@anthropic-ai/claude-agent-sdk");
|
|
|
108
119
|
const casInfo = pkgInfoFromEntry(casEntry);
|
|
109
120
|
assert.equal(
|
|
110
121
|
casInfo.version,
|
|
111
|
-
"0.3.
|
|
112
|
-
`@anthropic-ai/claude-agent-sdk must runtime-resolve to 0.3.
|
|
122
|
+
"0.3.219",
|
|
123
|
+
`@anthropic-ai/claude-agent-sdk must runtime-resolve to 0.3.219 from the adapter context (got ${casInfo.version})`,
|
|
113
124
|
);
|
|
114
125
|
const casRequire = createRequire(resolve(casInfo.dir, "package.json"));
|
|
115
126
|
const sdkEntry = casRequire.resolve(ANTHROPIC_SDK);
|
|
@@ -152,7 +163,7 @@ const mcpEntry = casRequire.resolve("@modelcontextprotocol/sdk/server/index.js")
|
|
|
152
163
|
const mcpInfo = pkgInfoFromEntry(mcpEntry);
|
|
153
164
|
assert.ok(
|
|
154
165
|
mcpInfo.version.startsWith("1.29."),
|
|
155
|
-
`@modelcontextprotocol/sdk must runtime-resolve to 1.29.x from the claude-agent-sdk context (got ${mcpInfo.version}) — claude-agent-sdk 0.3.
|
|
166
|
+
`@modelcontextprotocol/sdk must runtime-resolve to 1.29.x from the claude-agent-sdk context (got ${mcpInfo.version}) — claude-agent-sdk 0.3.219 declares a ^1.29.0 peer`,
|
|
156
167
|
);
|
|
157
168
|
|
|
158
169
|
// ---------------------------------------------------------------------------
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
import { strict as assert } from "node:assert";
|
|
28
28
|
import { execFileSync } from "node:child_process";
|
|
29
|
-
import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
29
|
+
import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmdirSync, rmSync, writeFileSync } from "node:fs";
|
|
30
30
|
import { tmpdir } from "node:os";
|
|
31
31
|
import { resolve } from "node:path";
|
|
32
32
|
import { pathToFileURL } from "node:url";
|
|
@@ -735,8 +735,71 @@ try {
|
|
|
735
735
|
"showToolNotifications is display-only — never perturbs the bridge config signature (no spurious rebuild)",
|
|
736
736
|
);
|
|
737
737
|
}
|
|
738
|
+
|
|
739
|
+
// ----------------------------------------------------------------------
|
|
740
|
+
// Section I — overlay scope wiring (P0-1, GPT review 2026-07-29): the turn
|
|
741
|
+
// loop hands adapter.ensureOverlay the AUTHORITATIVE resolveSessionKey value
|
|
742
|
+
// (opts.sessionId → PI_SESSION_ID → cwd). A session-scoped overlay (cortex)
|
|
743
|
+
// scopes its dir on this key, so two same-process/cwd sessions with
|
|
744
|
+
// different opts.sessionId must reach the adapter as two DIFFERENT keys —
|
|
745
|
+
// an ambient re-derivation (PI_SESSION_ID/cwd only) would alias them onto
|
|
746
|
+
// one overlay/mcp.json. Captured by wrapping the routed claudeAdapter's
|
|
747
|
+
// ensureOverlay on the compiled module (claude ignores the params, so a
|
|
748
|
+
// no-op stub is behavior-safe for these two turns).
|
|
749
|
+
// ----------------------------------------------------------------------
|
|
750
|
+
{
|
|
751
|
+
const captured: string[] = [];
|
|
752
|
+
const originalEnsureOverlay = adapterMod.claudeAdapter.ensureOverlay;
|
|
753
|
+
adapterMod.claudeAdapter.ensureOverlay = (p: { sessionKey: string }) => {
|
|
754
|
+
captured.push(p.sessionKey);
|
|
755
|
+
return { envOverrides: {} };
|
|
756
|
+
};
|
|
757
|
+
const savedPiSessionId = process.env.PI_SESSION_ID;
|
|
758
|
+
delete process.env.PI_SESSION_ID;
|
|
759
|
+
try {
|
|
760
|
+
const h = makeHarness(recordDir);
|
|
761
|
+
await collect(
|
|
762
|
+
backend.streamAcpTurn(
|
|
763
|
+
sonnet,
|
|
764
|
+
{ messages: [{ role: "user", content: "hi NONCE-I1", timestamp: 0 }] },
|
|
765
|
+
{ sessionId: "gate-I-one" },
|
|
766
|
+
h.deps,
|
|
767
|
+
) as Stream,
|
|
768
|
+
);
|
|
769
|
+
await collect(
|
|
770
|
+
backend.streamAcpTurn(
|
|
771
|
+
sonnet,
|
|
772
|
+
{ messages: [{ role: "user", content: "hi NONCE-I2", timestamp: 0 }] },
|
|
773
|
+
{ sessionId: "gate-I-two" },
|
|
774
|
+
h.deps,
|
|
775
|
+
) as Stream,
|
|
776
|
+
);
|
|
777
|
+
assert.deepEqual(
|
|
778
|
+
captured,
|
|
779
|
+
["pi:gate-I-one", "pi:gate-I-two"],
|
|
780
|
+
"the turn loop must pass adapter.ensureOverlay the AUTHORITATIVE resolveSessionKey value (opts.sessionId " +
|
|
781
|
+
"first) — two sessions in one process/cwd must arrive as two DIFFERENT overlay scope keys " +
|
|
782
|
+
"[QK:ACP-OVERLAY-SESSIONKEY-WIRED]",
|
|
783
|
+
);
|
|
784
|
+
} finally {
|
|
785
|
+
adapterMod.claudeAdapter.ensureOverlay = originalEnsureOverlay;
|
|
786
|
+
if (savedPiSessionId === undefined) delete process.env.PI_SESSION_ID;
|
|
787
|
+
else process.env.PI_SESSION_ID = savedPiSessionId;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
738
790
|
} finally {
|
|
739
791
|
rmSync(TMP_EMIT, { recursive: true, force: true });
|
|
792
|
+
try {
|
|
793
|
+
// The emit created `.tmp-verify/` as TMP_EMIT's parent. This gate now runs
|
|
794
|
+
// inside check-gate-qualification's PURITY-checked snapshot (it is the gate
|
|
795
|
+
// for the ACP-OVERLAY-SESSIONKEY-WIRED mutant), and the snapshot tree
|
|
796
|
+
// manifest walks ignored paths too — a leftover empty parent dir reads as
|
|
797
|
+
// IMPURE drift. Remove it when empty; a concurrent sibling gate's emit
|
|
798
|
+
// keeps it alive and the rmdir just fails.
|
|
799
|
+
rmdirSync(".tmp-verify");
|
|
800
|
+
} catch {
|
|
801
|
+
// non-empty or already gone — fine either way
|
|
802
|
+
}
|
|
740
803
|
rmSync(recordDir, { recursive: true, force: true });
|
|
741
804
|
}
|
|
742
805
|
|