@junghanacs/entwurf 0.12.8 → 0.12.10

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 (96) hide show
  1. package/AGENTS.md +134 -248
  2. package/BASELINE.md +1 -1
  3. package/CHANGELOG.md +39 -1
  4. package/DELIVERY.md +5 -4
  5. package/README.md +148 -23
  6. package/VERIFY.md +3 -2
  7. package/demo/README.md +2 -2
  8. package/demo/demo.sh +7 -1
  9. package/docs/setup-clean-host.md +24 -7
  10. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +168 -81
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +12 -12
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +5 -3
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +26 -9
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +10 -6
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +16 -18
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +13 -13
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +31 -41
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +8 -9
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +32 -25
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +4 -4
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +5 -4
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +14 -13
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +11 -3
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +15 -4
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +500 -54
  26. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +8 -3
  27. package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +14 -2
  28. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +155 -29
  29. package/mcp/entwurf-bridge/src/index.ts +200 -94
  30. package/package.json +11 -9
  31. package/pi-extensions/entwurf-control.ts +81 -39
  32. package/pi-extensions/lib/acp/models.ts +12 -12
  33. package/pi-extensions/lib/acp/overlay.ts +5 -3
  34. package/pi-extensions/lib/entwurf-core.ts +26 -9
  35. package/pi-extensions/lib/entwurf-deliverability.ts +10 -6
  36. package/pi-extensions/lib/entwurf-fact-provider.ts +24 -19
  37. package/pi-extensions/lib/entwurf-facts.ts +13 -13
  38. package/pi-extensions/lib/entwurf-resume-args.ts +40 -46
  39. package/pi-extensions/lib/entwurf-self-address.ts +8 -9
  40. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +7 -2
  41. package/pi-extensions/lib/entwurf-v2-contract.ts +32 -25
  42. package/pi-extensions/lib/entwurf-v2-decider.ts +8 -8
  43. package/pi-extensions/lib/entwurf-v2-lock.ts +5 -4
  44. package/pi-extensions/lib/entwurf-v2-production.ts +22 -13
  45. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +11 -3
  46. package/pi-extensions/lib/meta-sender-identity.ts +15 -5
  47. package/pi-extensions/lib/meta-session.ts +543 -58
  48. package/pi-extensions/meta-bridge-hook.ts +8 -2
  49. package/run.sh +78 -67
  50. package/scripts/agy-bridge-config.py +249 -49
  51. package/scripts/agy-bridge.sh +59 -14
  52. package/scripts/agy-imprint.ts +15 -1
  53. package/scripts/check-acp-carrier-augment.ts +34 -2
  54. package/scripts/check-acp-sdk-surface.ts +22 -11
  55. package/scripts/check-acp-session-reuse.ts +1 -1
  56. package/scripts/check-acp-session-store.ts +3 -3
  57. package/scripts/check-agy-permission-matrix.py +655 -0
  58. package/scripts/check-agy-sender-identity.ts +83 -0
  59. package/scripts/check-entwurf-control-rpc.ts +2 -2
  60. package/scripts/check-entwurf-deliverability.ts +9 -6
  61. package/scripts/check-entwurf-fact-provider.ts +16 -8
  62. package/scripts/check-entwurf-facts.ts +13 -13
  63. package/scripts/check-entwurf-resume-args.ts +25 -63
  64. package/scripts/check-entwurf-self-address.ts +187 -4
  65. package/scripts/check-entwurf-session-identity.ts +7 -6
  66. package/scripts/check-entwurf-v2-contract.ts +2 -2
  67. package/scripts/check-entwurf-v2-production.ts +9 -7
  68. package/scripts/check-entwurf-v2-spawn-production.ts +8 -4
  69. package/scripts/check-entwurf-v2-surface.ts +327 -14
  70. package/scripts/check-fresh-cut-gate.sh +305 -4
  71. package/scripts/check-gate-qualification.ts +785 -0
  72. package/scripts/check-meta-identity-consumers.ts +501 -1
  73. package/scripts/check-meta-listing.ts +91 -9
  74. package/scripts/check-meta-receiver-marker.ts +54 -0
  75. package/scripts/check-model-lock.ts +1 -1
  76. package/scripts/check-shell-quote.ts +2 -1
  77. package/scripts/lib/mutation-qualify.ts +794 -0
  78. package/scripts/meta-bridge-fresh-cut.ts +164 -28
  79. package/scripts/mutants/acp-augment.json +30 -0
  80. package/scripts/mutants/agy-permission.json +144 -0
  81. package/scripts/mutants/meta-identity.json +17 -0
  82. package/scripts/mutants/self-address.json +59 -0
  83. package/scripts/mutants/v2-surface.json +87 -0
  84. package/scripts/pi_settings_io.py +65 -0
  85. package/scripts/register-pi-package.py +183 -37
  86. package/scripts/register-pi-provider.py +68 -10
  87. package/scripts/smoke-acp-raw-turn-live.ts +1 -1
  88. package/scripts/smoke-acp-socket-citizen-live.ts +2 -2
  89. package/scripts/smoke-acp-v2-send-live.ts +33 -18
  90. package/scripts/smoke-agy-install-state.sh +205 -20
  91. package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -2
  92. package/scripts/smoke-meta-install-state.sh +1 -1
  93. package/scripts/smoke-pi-attach.ts +7 -2
  94. package/scripts/smoke-user-scope-citizen.sh +177 -0
  95. package/pi-extensions/lib/entwurf-mailbox-guard.ts +0 -100
  96. package/scripts/check-entwurf-mailbox-guard.ts +0 -262
@@ -18,6 +18,7 @@ import { strict as assert } from "node:assert";
18
18
  import { mkdtempSync, writeFileSync } from "node:fs";
19
19
  import { tmpdir } from "node:os";
20
20
  import { join } from "node:path";
21
+ import { fileURLToPath } from "node:url";
21
22
  import type { Context } from "@earendil-works/pi-ai";
22
23
  import {
23
24
  buildPiContextAugment,
@@ -32,6 +33,7 @@ import { buildClaudeSessionMeta } from "../pi-extensions/lib/acp/tool-surface.ts
32
33
  import { ENTWURF_PROJECT_CONTEXT_OPEN_TAG } from "../protocol.js";
33
34
 
34
35
  const tmp = mkdtempSync(join(tmpdir(), "acp-carrier-augment-"));
36
+ const REPO_DIR = fileURLToPath(new URL("..", import.meta.url));
35
37
  const BRIDGE_MARK = "operating through entwurf";
36
38
 
37
39
  // ===========================================================================
@@ -285,7 +287,37 @@ function ctxWith(firstUser: string): Context {
285
287
  writeFileSync(join(bigHome, "AGENTS.md"), "X".repeat(80 * 1024));
286
288
  const big = buildPiContextAugment({ backend: "claude", cwd: tmp, mcpServerNames: [], homeDir: bigHome });
287
289
  assert.ok(Buffer.byteLength(big, "utf8") <= 50 * 1024, "augment is truncated to the 50KB cap");
288
- assert.match(big, /context augment truncated to \d+ bytes/, "truncation leaves an honest marker");
290
+ assert.match(
291
+ big,
292
+ /context augment truncated to \d+ bytes/,
293
+ "truncation leaves an honest marker [QK:AUGMENT-TRUNC-MARKER]",
294
+ );
295
+ }
296
+
297
+ // ===========================================================================
298
+ // 9) The shipped repo AGENTS.md fits with a realistic operator-global budget.
299
+ // This guards the real 2026-07-27 failure: project AGENTS.md alone exceeded
300
+ // the cap, tail-cutting its own later rules plus Current date/cwd. The cap
301
+ // remains an honest fallback; the maintained package prompt must not hit it.
302
+ // ===========================================================================
303
+ {
304
+ const budgetHome = mkdtempSync(join(tmpdir(), "acp-budget-home-"));
305
+ writeFileSync(join(budgetHome, "AGENTS.md"), "H".repeat(12 * 1024));
306
+ const actual = buildPiContextAugment({
307
+ backend: "claude",
308
+ cwd: REPO_DIR,
309
+ mcpServerNames: ["entwurf-bridge"],
310
+ homeDir: budgetHome,
311
+ });
312
+ assert.doesNotMatch(
313
+ actual,
314
+ /context augment truncated/,
315
+ "repo AGENTS.md + 12KB global baseline fits without truncation [QK:AUGMENT-BUDGET-FITS]",
316
+ );
317
+ assert.ok(
318
+ actual.includes(`Current working directory: ${REPO_DIR}`),
319
+ "non-truncated augment retains the trailing cwd fact",
320
+ );
289
321
  }
290
322
 
291
323
  console.log(
@@ -293,5 +325,5 @@ console.log(
293
325
  "empty/whitespace/missing → null, shipped-default → non-empty v1 lever (preset replaced), carrier absent → no _meta.systemPrompt key, carrier change → " +
294
326
  "signature change (stable carrier → stable signature); augment: prepended on `new` only (reuse delta has none), " +
295
327
  "wire-only so it never enters contextMessageSignatures, entwurf cwd/AGENTS.md de-dup (present → drop only that " +
296
- "section, home kept; absent → kept), day-granularity date, 50KB truncation marker",
328
+ "section, home kept; absent → kept), day-granularity date, 50KB truncation marker, shipped AGENTS budget",
297
329
  );
@@ -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.61.0 Claude adapter (spawn binary)
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.217's peer floor
12
- // (>=0.93.0); drop it and the tree resolves a stale 0.91.1 so the peer goes
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.61.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\.61\.0\(@anthropic-ai\/sdk@0\.100\.1/,
67
- "pnpm-lock: claude-agent-acp@0.61.0 must peer-resolve @anthropic-ai/sdk@0.100.1 (peer-pin), not the stale 0.91.1",
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\.217\(@anthropic-ai\/sdk@0\.100\.1/,
72
- "pnpm-lock: claude-agent-sdk@0.3.217 must peer-resolve @anthropic-ai/sdk@0.100.1 — else its >=0.93.0 peer floor is unmet",
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.217",
112
- `@anthropic-ai/claude-agent-sdk must runtime-resolve to 0.3.217 from the adapter context (got ${casInfo.version})`,
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.217 declares a ^1.29.0 peer`,
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
  // ---------------------------------------------------------------------------
@@ -33,7 +33,7 @@ import { pathToFileURL } from "node:url";
33
33
  import type { Api, AssistantMessageEvent, Context, Message, Model } from "@earendil-works/pi-ai";
34
34
 
35
35
  const sonnet = { id: "claude-sonnet-5" } as unknown as Model<Api>;
36
- const opus = { id: "claude-opus-4-8" } as unknown as Model<Api>;
36
+ const opus = { id: "claude-opus-5" } as unknown as Model<Api>;
37
37
 
38
38
  type Stream = AsyncIterable<AssistantMessageEvent> & {
39
39
  result: () => Promise<{ stopReason: string; errorMessage?: string }>;
@@ -85,7 +85,7 @@ const baseInput = (): BridgeConfigInput => ({
85
85
  );
86
86
  // Model drift → different signature.
87
87
  assert.notEqual(
88
- bridgeConfigSignature({ ...baseInput(), modelId: "claude-opus-4-8" }),
88
+ bridgeConfigSignature({ ...baseInput(), modelId: "claude-opus-5" }),
89
89
  bridgeConfigSignature(baseInput()),
90
90
  "model drift changes the signature",
91
91
  );
@@ -186,7 +186,7 @@ const baseInput = (): BridgeConfigInput => ({
186
186
  const params = facts({ contextMessageSignatures: ["user:text:a", "assistant:text:b"] });
187
187
  assert.ok(isCompatible(facts(), params), "prefix history + same cfg → compatible");
188
188
  assert.ok(!isCompatible(facts({ cwd: "/other" }), params), "cwd drift → incompatible");
189
- assert.ok(!isCompatible(facts({ modelId: "claude-opus-4-8" }), params), "model drift → incompatible");
189
+ assert.ok(!isCompatible(facts({ modelId: "claude-opus-5" }), params), "model drift → incompatible");
190
190
  assert.ok(!isCompatible(facts({ bridgeConfigSignature: "different" }), params), "signature drift → incompatible");
191
191
  assert.ok(
192
192
  !isCompatible(facts({ contextMessageSignatures: ["user:text:EDITED"] }), params),
@@ -292,7 +292,7 @@ const baseInput = (): BridgeConfigInput => ({
292
292
  assert.throws(
293
293
  () =>
294
294
  decideBootstrap(params("process-scoped"), {
295
- existing: { ...aliveCompat, modelId: "claude-opus-4-8" },
295
+ existing: { ...aliveCompat, modelId: "claude-opus-5" },
296
296
  }),
297
297
  SessionModelLockedError,
298
298
  "live model mismatch throws SessionModelLockedError",