@junghanacs/entwurf 0.12.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 (183) hide show
  1. package/AGENTS.md +240 -0
  2. package/BASELINE.md +227 -0
  3. package/CHANGELOG.md +1210 -0
  4. package/CONTRIBUTING.md +63 -0
  5. package/DELIVERY.md +209 -0
  6. package/LICENSE +21 -0
  7. package/README.md +504 -0
  8. package/VERIFY.md +260 -0
  9. package/demo/README.md +188 -0
  10. package/demo/demo-baseline.sh +156 -0
  11. package/demo/demo.sh +183 -0
  12. package/docs/assets/entwurf-demo.gif +0 -0
  13. package/docs/assets/entwurf-doomemacs.gif +0 -0
  14. package/docs/assets/entwurf-entwurf.gif +0 -0
  15. package/docs/assets/entwurf-hero.jpg +0 -0
  16. package/docs/setup-clean-host.md +305 -0
  17. package/mcp/entwurf-bridge/src/index.ts +513 -0
  18. package/mcp/entwurf-bridge/start.sh +25 -0
  19. package/mcp/entwurf-bridge/test.sh +54 -0
  20. package/mcp/tsconfig.json +29 -0
  21. package/package.json +130 -0
  22. package/pi/entwurf-capabilities.json +9 -0
  23. package/pi/entwurf-targets.json +20 -0
  24. package/pi/meta-bridge/.claude-plugin/marketplace.json +12 -0
  25. package/pi/meta-bridge/entwurf-meta-receive/.claude-plugin/plugin.json +5 -0
  26. package/pi/meta-bridge/entwurf-meta-receive/hooks/hooks.json +50 -0
  27. package/pi/meta-bridge/entwurf-meta-receive/scripts/doorbell.sh +54 -0
  28. package/pi/settings.reference.json +43 -0
  29. package/pi/skill-plugin-example/.claude-plugin/plugin.json +4 -0
  30. package/pi/skill-plugin-example/skills/hello/SKILL.md +18 -0
  31. package/pi-extensions/acp-provider.ts +63 -0
  32. package/pi-extensions/entwurf-control.ts +1692 -0
  33. package/pi-extensions/lib/acp/acp-client.ts +90 -0
  34. package/pi-extensions/lib/acp/augment.ts +238 -0
  35. package/pi-extensions/lib/acp/backend-adapter.ts +319 -0
  36. package/pi-extensions/lib/acp/backend.ts +873 -0
  37. package/pi-extensions/lib/acp/config.ts +552 -0
  38. package/pi-extensions/lib/acp/context.ts +177 -0
  39. package/pi-extensions/lib/acp/engraving.ts +123 -0
  40. package/pi-extensions/lib/acp/event-mapper.ts +339 -0
  41. package/pi-extensions/lib/acp/models.ts +102 -0
  42. package/pi-extensions/lib/acp/overlay.ts +220 -0
  43. package/pi-extensions/lib/acp/prompts/engraving.md +1 -0
  44. package/pi-extensions/lib/acp/session-store.ts +418 -0
  45. package/pi-extensions/lib/acp/tool-surface.ts +184 -0
  46. package/pi-extensions/lib/entwurf-control-rpc.ts +208 -0
  47. package/pi-extensions/lib/entwurf-core.ts +2033 -0
  48. package/pi-extensions/lib/entwurf-deliverability.ts +123 -0
  49. package/pi-extensions/lib/entwurf-fact-provider.ts +158 -0
  50. package/pi-extensions/lib/entwurf-facts.ts +251 -0
  51. package/pi-extensions/lib/entwurf-mailbox-guard.ts +100 -0
  52. package/pi-extensions/lib/entwurf-peers-render.ts +154 -0
  53. package/pi-extensions/lib/entwurf-preflight.ts +247 -0
  54. package/pi-extensions/lib/entwurf-resume-args.ts +88 -0
  55. package/pi-extensions/lib/entwurf-self-address.ts +117 -0
  56. package/pi-extensions/lib/entwurf-v2-contract.ts +427 -0
  57. package/pi-extensions/lib/entwurf-v2-decider.ts +441 -0
  58. package/pi-extensions/lib/entwurf-v2-lock.ts +412 -0
  59. package/pi-extensions/lib/entwurf-v2-mailbox.ts +87 -0
  60. package/pi-extensions/lib/entwurf-v2-production.ts +326 -0
  61. package/pi-extensions/lib/entwurf-v2-release.ts +149 -0
  62. package/pi-extensions/lib/entwurf-v2-resume-marker.ts +34 -0
  63. package/pi-extensions/lib/entwurf-v2-runner.ts +196 -0
  64. package/pi-extensions/lib/entwurf-v2-send-fallback.ts +166 -0
  65. package/pi-extensions/lib/entwurf-v2-send.ts +271 -0
  66. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +337 -0
  67. package/pi-extensions/lib/entwurf-v2-spawn.ts +323 -0
  68. package/pi-extensions/lib/entwurf-v2-surface.ts +205 -0
  69. package/pi-extensions/lib/meta-mailbox-body.ts +80 -0
  70. package/pi-extensions/lib/meta-session.ts +1951 -0
  71. package/pi-extensions/lib/project-trust-handler.ts +154 -0
  72. package/pi-extensions/lib/session-id.js +57 -0
  73. package/pi-extensions/lib/socket-discovery.ts +346 -0
  74. package/pi-extensions/lib/socket-probe.ts +92 -0
  75. package/pi-extensions/meta-bridge-hook.ts +250 -0
  76. package/pi-extensions/model-lock.ts +235 -0
  77. package/prompts/engraving.md +27 -0
  78. package/protocol.js +31 -0
  79. package/run.sh +2832 -0
  80. package/scripts/check-acp-backend-preflight.ts +130 -0
  81. package/scripts/check-acp-carrier-augment.ts +297 -0
  82. package/scripts/check-acp-config.ts +322 -0
  83. package/scripts/check-acp-event-mapper.ts +253 -0
  84. package/scripts/check-acp-overlay.ts +154 -0
  85. package/scripts/check-acp-prompt-builder.ts +191 -0
  86. package/scripts/check-acp-provider-surface.ts +159 -0
  87. package/scripts/check-acp-sdk-surface.ts +211 -0
  88. package/scripts/check-acp-session-reuse.ts +756 -0
  89. package/scripts/check-acp-session-store.ts +387 -0
  90. package/scripts/check-acp-tool-surface.ts +159 -0
  91. package/scripts/check-entwurf-bridge-boot.ts +199 -0
  92. package/scripts/check-entwurf-capabilities.ts +123 -0
  93. package/scripts/check-entwurf-control-rpc.ts +187 -0
  94. package/scripts/check-entwurf-deliverability.ts +158 -0
  95. package/scripts/check-entwurf-fact-provider.ts +316 -0
  96. package/scripts/check-entwurf-facts.ts +358 -0
  97. package/scripts/check-entwurf-mailbox-guard.ts +264 -0
  98. package/scripts/check-entwurf-peers-surface.ts +235 -0
  99. package/scripts/check-entwurf-resume-args.ts +149 -0
  100. package/scripts/check-entwurf-self-address.ts +209 -0
  101. package/scripts/check-entwurf-session-identity.ts +703 -0
  102. package/scripts/check-entwurf-v2-contract.ts +536 -0
  103. package/scripts/check-entwurf-v2-decider.ts +795 -0
  104. package/scripts/check-entwurf-v2-lock.ts +368 -0
  105. package/scripts/check-entwurf-v2-mailbox.ts +228 -0
  106. package/scripts/check-entwurf-v2-matrix.ts +437 -0
  107. package/scripts/check-entwurf-v2-production.ts +406 -0
  108. package/scripts/check-entwurf-v2-release.ts +245 -0
  109. package/scripts/check-entwurf-v2-runner.ts +452 -0
  110. package/scripts/check-entwurf-v2-send-fallback.ts +371 -0
  111. package/scripts/check-entwurf-v2-send.ts +454 -0
  112. package/scripts/check-entwurf-v2-spawn-production.ts +452 -0
  113. package/scripts/check-entwurf-v2-spawn.ts +398 -0
  114. package/scripts/check-entwurf-v2-surface.ts +352 -0
  115. package/scripts/check-keyset-overlap.py +120 -0
  116. package/scripts/check-mailbox-receipt-state.ts +170 -0
  117. package/scripts/check-meta-capability-source.ts +112 -0
  118. package/scripts/check-meta-dual-consumers.ts +154 -0
  119. package/scripts/check-meta-dual-read.ts +158 -0
  120. package/scripts/check-meta-listing.ts +138 -0
  121. package/scripts/check-meta-mailbox-state-write.ts +135 -0
  122. package/scripts/check-meta-migration.ts +212 -0
  123. package/scripts/check-meta-receiver-marker.ts +185 -0
  124. package/scripts/check-meta-record-v2.ts +191 -0
  125. package/scripts/check-meta-session.ts +673 -0
  126. package/scripts/check-model-lock.ts +408 -0
  127. package/scripts/check-package-source-routing.ts +253 -0
  128. package/scripts/check-pi-preflight.ts +304 -0
  129. package/scripts/check-project-trust-handler.ts +265 -0
  130. package/scripts/check-shell-quote.ts +121 -0
  131. package/scripts/check-socket-discovery.ts +428 -0
  132. package/scripts/check-socket-probe.ts +106 -0
  133. package/scripts/fixtures/probe-mcp-server.ts +33 -0
  134. package/scripts/gnew-rpc-drive.ts +211 -0
  135. package/scripts/lib/acp-child-cleanup.ts +116 -0
  136. package/scripts/meta-bridge-doctor.sh +315 -0
  137. package/scripts/meta-bridge-hook-log.sh +26 -0
  138. package/scripts/meta-bridge-install.sh +135 -0
  139. package/scripts/meta-bridge-prune.ts +199 -0
  140. package/scripts/meta-bridge-state.py +549 -0
  141. package/scripts/meta-bridge-statusline.sh +192 -0
  142. package/scripts/meta-bridge-store-doctor.ts +64 -0
  143. package/scripts/meta-bridge-uninstall.sh +39 -0
  144. package/scripts/new-session-id.ts +25 -0
  145. package/scripts/postinstall-chmod.cjs +58 -0
  146. package/scripts/raw-async-delivery/README.md +258 -0
  147. package/scripts/raw-async-delivery/cc-enqueue-addressed.sh +35 -0
  148. package/scripts/raw-async-delivery/cc-mailbox-rewake.sh +38 -0
  149. package/scripts/raw-async-delivery/cc-watch-filechanged.sh +19 -0
  150. package/scripts/raw-async-delivery/cc-watch-sessionstart.sh +15 -0
  151. package/scripts/raw-async-delivery/codex-local-appserver.sh +39 -0
  152. package/scripts/raw-async-delivery/plugin-entwurf-receive/.claude-plugin/plugin.json +5 -0
  153. package/scripts/raw-async-delivery/plugin-entwurf-receive/hooks/hooks.json +28 -0
  154. package/scripts/raw-async-delivery/plugin-entwurf-receive/scripts/watch-filechanged.sh +28 -0
  155. package/scripts/raw-async-delivery/plugin-entwurf-receive/scripts/watch-sessionstart.sh +27 -0
  156. package/scripts/raw-async-delivery/raw-agy-send.sh +29 -0
  157. package/scripts/raw-async-delivery/raw-claude-enqueue.sh +30 -0
  158. package/scripts/raw-async-delivery/raw-codex-ws-turn-start.py +164 -0
  159. package/scripts/raw-async-delivery/repro-addressed-routing.sh +96 -0
  160. package/scripts/raw-async-delivery/repro-plugin-idle-wake.sh +104 -0
  161. package/scripts/resolve-acp-bridge.ts +25 -0
  162. package/scripts/smoke-acp-bundled-mcp-live.ts +292 -0
  163. package/scripts/smoke-acp-carrier-augment-live.ts +192 -0
  164. package/scripts/smoke-acp-mcp-live.ts +129 -0
  165. package/scripts/smoke-acp-memory-containment-live.ts +389 -0
  166. package/scripts/smoke-acp-overlay-live.ts +314 -0
  167. package/scripts/smoke-acp-provider-live.ts +162 -0
  168. package/scripts/smoke-acp-raw-turn-live.ts +261 -0
  169. package/scripts/smoke-acp-session-reuse-live.ts +172 -0
  170. package/scripts/smoke-acp-skill-live.ts +144 -0
  171. package/scripts/smoke-acp-socket-citizen-live.ts +168 -0
  172. package/scripts/smoke-claude-native-resume-live.sh +198 -0
  173. package/scripts/smoke-entwurf-v2-matrix-live.ts +398 -0
  174. package/scripts/smoke-entwurf-v2-spawn-live.ts +175 -0
  175. package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +428 -0
  176. package/scripts/smoke-meta-async-drift.sh +171 -0
  177. package/scripts/smoke-meta-honesty.sh +147 -0
  178. package/scripts/smoke-meta-install-state.sh +403 -0
  179. package/scripts/smoke-meta-keyset-guard.sh +111 -0
  180. package/scripts/smoke-meta-prune.sh +174 -0
  181. package/scripts/smoke-resident-garden-guard.sh +433 -0
  182. package/scripts/smoke-session-id-name.ts +187 -0
  183. package/scripts/tsconfig.json +34 -0
@@ -0,0 +1,191 @@
1
+ /**
2
+ * check-meta-record-v2 — deterministic golden gate for 0.11 Stage 0 step 3A:
3
+ * the v1→v2 identity normalize seam. Pure functions; no fs, no backend, no API.
4
+ * Safe in the `pnpm check` static floor.
5
+ *
6
+ * THE golden: a synthetic, SANITIZED v1 fixture (no real cwd/transcriptPath —
7
+ * never commit a real disk meta-record to a public repo) normalizes to a
8
+ * hand-written v2 identity literal. The golden is a literal, NOT derived from
9
+ * the same mapping under test, so a drift in `normalizeMetaIdentity` fails here.
10
+ *
11
+ * This gate is kept SEPARATE from check-meta-session (the v1 record-authority
12
+ * gate) on purpose (NEXT.md "dual-read 경로엔 v1 fixture 게이트를 별도 유지"):
13
+ * when step 3D rewrites the v1 mint/write gates, this v1→v2 compat golden must
14
+ * survive untouched as the back-compat proof for the 10+ disk v1 records.
15
+ *
16
+ * Scope is 3A ONLY: readers (parseMetaRecordV1/V2) + normalizer. There is no v2
17
+ * writer yet by design — do not add serialize/upsert assertions here until the
18
+ * golden + its GPT review have landed (NEXT.md 끊을 지점 ①).
19
+ */
20
+
21
+ import assert from "node:assert/strict";
22
+ import {
23
+ MetaRecordError,
24
+ normalizeMetaIdentity,
25
+ parseMetaRecordV1,
26
+ parseMetaRecordV2,
27
+ } from "../pi-extensions/lib/meta-session.ts";
28
+
29
+ let passed = 0;
30
+ function ok(label: string, cond: boolean): void {
31
+ assert.ok(cond, label);
32
+ console.log(` ok ${label}`);
33
+ passed++;
34
+ }
35
+ function golden(label: string, actual: unknown, expected: unknown): void {
36
+ assert.deepStrictEqual(actual, expected, label);
37
+ console.log(` ok ${label}`);
38
+ passed++;
39
+ }
40
+ function throws(label: string, fn: () => unknown): void {
41
+ assert.throws(fn, MetaRecordError, label);
42
+ console.log(` ok ${label}`);
43
+ passed++;
44
+ }
45
+
46
+ // --- Synthetic, sanitized v1 fixture (golden source) ------------------------
47
+ // gardenId obeys the SSOT grammar YYYYMMDDTHHMMSS-[0-9a-f]{6}. Paths are
48
+ // synthetic. delivery carries non-null receipts to prove they are DROPPED (not
49
+ // silently carried) by identity normalize.
50
+ const V1_FIXTURE_JSON = JSON.stringify({
51
+ schemaVersion: 1,
52
+ gardenId: "20260101T000000-0a1b2c",
53
+ backend: "claude-code",
54
+ nativeSessionId: "n-fixture-0001",
55
+ transcriptPath: "/synthetic/project/.transcript.jsonl",
56
+ cwd: "/synthetic/project",
57
+ createdAt: "2026-01-01T00:00:00.000Z",
58
+ lastSeen: "2026-01-02T03:04:05.000Z",
59
+ delivery: {
60
+ wakeMode: "self-fetch",
61
+ deliveryLevel: "D6",
62
+ lastEnqueuedAt: null,
63
+ lastDeliveredAt: "2026-01-02T03:00:00.000Z",
64
+ lastReadAt: "2026-01-02T03:04:05.000Z",
65
+ },
66
+ });
67
+
68
+ // THE golden — hand-written v2 identity (not derived from the mapping).
69
+ const GOLDEN_V2_IDENTITY = {
70
+ schemaVersion: 2,
71
+ gardenId: "20260101T000000-0a1b2c",
72
+ backend: "claude-code",
73
+ nativeSessionId: "n-fixture-0001",
74
+ cwd: "/synthetic/project",
75
+ model: null,
76
+ transcriptPath: "/synthetic/project/.transcript.jsonl",
77
+ parentGardenId: null,
78
+ isEntwurf: false,
79
+ createdAt: "2026-01-01T00:00:00.000Z",
80
+ recordUpdatedAt: "2026-01-02T03:04:05.000Z", // = v1 lastSeen (renamed)
81
+ };
82
+
83
+ // A v2 fixture exercising the deltas: pi backend, null transcriptPath/model,
84
+ // a parent garden id, isEntwurf=true.
85
+ const V2_PI_FIXTURE_JSON = JSON.stringify({
86
+ schemaVersion: 2,
87
+ gardenId: "20260301T120000-abc123",
88
+ backend: "pi",
89
+ nativeSessionId: "pi-sess-xyz",
90
+ cwd: "/synthetic/pi-proj",
91
+ model: null,
92
+ transcriptPath: null,
93
+ parentGardenId: "20260301T115900-aaaaaa",
94
+ isEntwurf: true,
95
+ createdAt: "2026-03-01T12:00:00.000Z",
96
+ recordUpdatedAt: "2026-03-01T12:30:00.000Z",
97
+ });
98
+
99
+ // 1. v1 fixture parses (round-trips to a v1 record carrying delivery).
100
+ const v1 = parseMetaRecordV1(V1_FIXTURE_JSON);
101
+ ok(
102
+ "parseMetaRecordV1: synthetic v1 fixture parses with delivery intact",
103
+ v1.schemaVersion === 1 && v1.delivery.lastReadAt === "2026-01-02T03:04:05.000Z",
104
+ );
105
+
106
+ // 2. THE golden — v1 normalizes to the hand-written v2 identity, byte-for-byte.
107
+ golden(
108
+ "normalizeMetaIdentity(v1) === golden v2 identity (lastSeen→recordUpdatedAt, delivery dropped)",
109
+ normalizeMetaIdentity(v1),
110
+ GOLDEN_V2_IDENTITY,
111
+ );
112
+
113
+ // 3. v1 identity is LOSSLESS: every identity field survives; only delivery is
114
+ // intentionally absent (proven by the golden having no delivery key).
115
+ const norm = normalizeMetaIdentity(v1);
116
+ ok(
117
+ "v1 identity lossless: gardenId/backend/nativeSessionId/cwd/createdAt preserved, transcriptPath carried",
118
+ norm.gardenId === v1.gardenId &&
119
+ norm.backend === v1.backend &&
120
+ norm.nativeSessionId === v1.nativeSessionId &&
121
+ norm.cwd === v1.cwd &&
122
+ norm.createdAt === v1.createdAt &&
123
+ norm.transcriptPath === v1.transcriptPath,
124
+ );
125
+ ok(
126
+ "v1 recordUpdatedAt is the renamed lastSeen (not createdAt)",
127
+ norm.recordUpdatedAt === v1.lastSeen && norm.recordUpdatedAt !== norm.createdAt,
128
+ );
129
+ ok("normalized identity carries no delivery aspect", !("delivery" in norm) && !("lastSeen" in norm));
130
+ ok(
131
+ "new v2 identity fields default at v1→v2 birth",
132
+ norm.model === null && norm.parentGardenId === null && norm.isEntwurf === false,
133
+ );
134
+
135
+ // 4. normalize is idempotent: normalize(normalize(v1)) === normalize(v1).
136
+ golden("normalize is idempotent (normalize∘normalize == normalize)", normalizeMetaIdentity(norm), norm);
137
+
138
+ // 5. v2 fixture parses (the +=pi, nullable transcriptPath/model, parentGardenId,
139
+ // isEntwurf deltas all accepted).
140
+ const v2 = parseMetaRecordV2(V2_PI_FIXTURE_JSON);
141
+ ok(
142
+ "parseMetaRecordV2: pi backend + null transcriptPath/model + parent + isEntwurf parses",
143
+ v2.backend === "pi" &&
144
+ v2.transcriptPath === null &&
145
+ v2.model === null &&
146
+ v2.parentGardenId === "20260301T115900-aaaaaa" &&
147
+ v2.isEntwurf === true,
148
+ );
149
+
150
+ // 6. normalize on an already-v2 record is identity (fresh copy, same values).
151
+ golden("normalizeMetaIdentity(v2) === v2 (already identity, returned as stable copy)", normalizeMetaIdentity(v2), v2);
152
+
153
+ // 7. version fences hold both ways — neither parser accepts the other's version.
154
+ throws("parseMetaRecordV1 rejects a schemaVersion-2 body", () => parseMetaRecordV1(V2_PI_FIXTURE_JSON));
155
+ throws("parseMetaRecordV2 rejects a schemaVersion-1 body", () => parseMetaRecordV2(V1_FIXTURE_JSON));
156
+
157
+ // 8. v2 validation crashes (not warns) on the new-field contracts.
158
+ throws("parseMetaRecordV2 rejects non-boolean isEntwurf", () =>
159
+ parseMetaRecordV2(JSON.stringify({ ...JSON.parse(V2_PI_FIXTURE_JSON), isEntwurf: "yes" })),
160
+ );
161
+ throws("parseMetaRecordV2 rejects an unknown backend", () =>
162
+ parseMetaRecordV2(JSON.stringify({ ...JSON.parse(V2_PI_FIXTURE_JSON), backend: "gemini" })),
163
+ );
164
+ throws("parseMetaRecordV2 rejects a malformed parentGardenId (non-null, bad grammar)", () =>
165
+ parseMetaRecordV2(JSON.stringify({ ...JSON.parse(V2_PI_FIXTURE_JSON), parentGardenId: "not-a-garden-id" })),
166
+ );
167
+
168
+ // 9. strict keyset — a v2 body carrying stale v1 fields is half-migrated/corrupt
169
+ // and must fail-fast, NOT be silently normalized away (GPT review blocker).
170
+ throws("parseMetaRecordV2 rejects a stale v1 `delivery` field", () =>
171
+ parseMetaRecordV2(
172
+ JSON.stringify({
173
+ ...JSON.parse(V2_PI_FIXTURE_JSON),
174
+ delivery: {
175
+ wakeMode: "self-fetch",
176
+ deliveryLevel: "D6",
177
+ lastEnqueuedAt: null,
178
+ lastDeliveredAt: null,
179
+ lastReadAt: null,
180
+ },
181
+ }),
182
+ ),
183
+ );
184
+ throws("parseMetaRecordV2 rejects a stale v1 `lastSeen` field", () =>
185
+ parseMetaRecordV2(JSON.stringify({ ...JSON.parse(V2_PI_FIXTURE_JSON), lastSeen: "2026-03-01T12:30:00.000Z" })),
186
+ );
187
+ throws("parseMetaRecordV2 rejects an unknown/extra field", () =>
188
+ parseMetaRecordV2(JSON.stringify({ ...JSON.parse(V2_PI_FIXTURE_JSON), tmuxTarget: "psa:3.1" })),
189
+ );
190
+
191
+ console.log(`[check-meta-record-v2] ${passed} assertions ok`);