@junghanacs/entwurf 0.12.3 → 0.12.4

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/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.12.4 — 2026-07-01
8
+
9
+ ### Fixed
10
+
11
+ - **Installed `doctor-meta-bridge` no longer false-fails on node_modules strip-types.** The doctor previously ran `scripts/meta-bridge-store-doctor.ts` and `scripts/check-entwurf-v2-surface.ts` through Node strip-types even from an npm/pnpm-installed package. Node refuses type stripping under `node_modules` (`ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`), so real floor hosts reported false store-scan / v2-surface failures while development clones stayed green. The doctor now branches by package location: installed packages run the prebuilt `mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js` with plain `node` and defer the repo-only v2 source-shape gate after confirming the shipped source and runtime wiring; development clones keep the raw `.ts` gates.
12
+ - **The store-doctor helper now ships as a node_modules-safe dist artifact.** The bridge build emits `dist/scripts/meta-bridge-store-doctor.js` alongside the MCP bridge closure, reusing the already-shipped `meta-session.js` dependency without adding a new runtime package lane. `check-pack` / `check-pack-install` require the artifact in the tarball and prove it scans a real fixture store under `node_modules` with plain `node`.
13
+ - **Clean-host install docs call out the 0.12.4 doctor floor check.** The walkthrough now tells operators exactly which doctor lines prove the installed-vs-dev split and flags any `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING` as a pre-0.12.4 or broken-tarball signal.
14
+
15
+ ### Verification
16
+
17
+ - `pnpm check` passed on 2026-07-01 after the doctor/install-floor fix.
18
+ - `./run.sh check-pack-install` passed with the new installed store-doctor scan and doctor-dispatch lock assertions.
19
+ - Release-gate prep evidence: `LIVE=1 ./run.sh release-gate /tmp/psa-release-gate-0.12.4.PliLsd` passed on 2026-07-01; log `/tmp/pi-tmux-entwurf-release-gate-0124.log`; summary `MUST: PASS=17 FAIL=0 SKIP=0`, advisory `BEHAVIOR: PASS=0 FAIL=1` (`smoke-resident-garden-guard` post-`/gnew` autonomous `entwurf_self` identity turn; non-blocking).
20
+ - `hejdev6` real floor host reproduced the pre-fix strip-types failure from an installed package and passed after installing the patched tarball: compiled store-doctor scanned `1 record(s)` with plain `node`, and installed `doctor-meta-bridge` reported store-scan ok plus v2-surface deferred.
21
+
7
22
  ## 0.12.3 — 2026-07-01
8
23
 
9
24
  ### Changed
package/README.md CHANGED
@@ -181,6 +181,12 @@ entwurf install-meta-bridge
181
181
  entwurf doctor-meta-bridge
182
182
  ```
183
183
 
184
+ On npm/pnpm-installed packages, `doctor-meta-bridge` must use prebuilt JS for its
185
+ store scan and defer repo-only source-shape gates; Node refuses strip-types for
186
+ raw `.ts` helpers under `node_modules`. If the doctor reports
187
+ `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`, reinstall a current package before
188
+ trusting the floor result.
189
+
184
190
  For manual configuration, [`pi/settings.reference.json`](./pi/settings.reference.json)
185
191
  shows the pi adapter settings shape, and the external-host examples below show
186
192
  plain MCP registrations.
@@ -4,9 +4,11 @@ End-to-end install of **entwurf** on a host with only `git` available — no
4
4
  node, no npm package, no pi binary, no dotfiles. The point is to validate the
5
5
  public install surface as an outside user would experience it.
6
6
 
7
- > **Scope.** This is the entwurf 0.12.1 install recipe. The base package install
7
+ > **Scope.** This is the entwurf 0.12.4 install recipe. The base package install
8
8
  > is **neutral npm**, not `pi install npm:...`. Pi is an optional adapter lane for
9
- > the ACP provider / control-socket runtime.
9
+ > the ACP provider / control-socket runtime. The 0.12.4 floor fix is explicitly
10
+ > covered here: installed packages under `node_modules` must not run raw `.ts`
11
+ > doctor helpers through Node strip-types.
10
12
 
11
13
  `entwurf` is a garden-citizen dispatch substrate and meta-bridge. It does not
12
14
  provide, copy, or mediate backend credentials — it lets the official backend CLI
@@ -72,9 +74,11 @@ MCP bridge can boot in Claude Code / Codex / Antigravity without pi present.
72
74
  ## Stage 2 — auth-free bridge boot
73
75
 
74
76
  Prove the installed MCP server answers `tools/list` from inside `node_modules`.
75
- This is the regression that 0.12.0 missed: Node refuses `--experimental-strip-types`
76
- for `.ts` under `node_modules`, so the installed package must boot the prebuilt
77
- JS under `mcp/entwurf-bridge/dist/`.
77
+ This is the first `node_modules` strip-types regression fixed in 0.12.0: Node
78
+ refuses `--experimental-strip-types` for `.ts` under `node_modules`, so the
79
+ installed package must boot the prebuilt JS under `mcp/entwurf-bridge/dist/`.
80
+ The 0.12.4 doctor fix below applies the same installed-vs-dev split to
81
+ `doctor-meta-bridge` helper checks.
78
82
 
79
83
  ```bash
80
84
  node --input-type=module <<'JS'
@@ -141,6 +145,19 @@ entwurf install-meta-bridge
141
145
  entwurf doctor-meta-bridge
142
146
  ```
143
147
 
148
+ On an installed package (`.../node_modules/@junghanacs/entwurf`), the doctor must
149
+ not try to strip-types-run raw `.ts` helpers. In the output, check for these two
150
+ 0.12.4 floor-regression signals:
151
+
152
+ ```text
153
+ ok full store scan: no corrupt records, duplicate nativeSessionId, body/filename drift, or backend↔wakeMode contradiction
154
+ ok check-entwurf-v2-surface: shipped surface source present; exhaustive source-shape gate is a repo/release invariant (not run under node_modules)
155
+ ```
156
+
157
+ If either section reports `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`, the host
158
+ is still running a pre-0.12.4 package or a broken tarball. Reinstall the current
159
+ package and re-run `entwurf install-meta-bridge && entwurf doctor-meta-bridge`.
160
+
144
161
  A plain external MCP host can call tools but is non-replyable. A garden-native
145
162
  meta-session has a garden id, a mailbox, and a trusted sender marker; it can call
146
163
  `entwurf_self`, receive mailbox wakeups, and be replied to by garden id.
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * meta-bridge-store-doctor — fail-loud full scan for meta-session records.
4
+ *
5
+ * The store is the authority for native→garden lookup. Doctor must therefore
6
+ * refuse corrupt records, duplicate nativeSessionId authorities, and body ↔
7
+ * filename drift instead of auto-pruning or silently picking one.
8
+ */
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ import { parseMetaIdentity } from "../pi-extensions/lib/meta-session.js";
12
+ const dir = process.argv[2];
13
+ if (!dir) {
14
+ console.error("usage: node --experimental-strip-types scripts/meta-bridge-store-doctor.ts <meta-sessions-dir>");
15
+ process.exit(2);
16
+ }
17
+ const failures = [];
18
+ const nativeToFiles = new Map();
19
+ let scanned = 0;
20
+ if (!fs.existsSync(dir)) {
21
+ console.log(`meta-store scan ok: ${dir} does not exist yet (0 records)`);
22
+ process.exit(0);
23
+ }
24
+ for (const filename of fs.readdirSync(dir).sort()) {
25
+ if (!filename.endsWith(".meta.json"))
26
+ continue;
27
+ scanned += 1;
28
+ const file = path.join(dir, filename);
29
+ try {
30
+ // dual-read (3D-4 commit1): parseMetaIdentity reads v1 AND v2 and normalizes,
31
+ // so doctor's gardenId/nativeSessionId checks survive the v2 cut.
32
+ const id = parseMetaIdentity(fs.readFileSync(file, "utf8"));
33
+ const expectedFilename = `${id.gardenId}.meta.json`;
34
+ if (filename !== expectedFilename) {
35
+ failures.push(`${filename}: body/filename drift — body gardenId=${id.gardenId}, expected filename ${expectedFilename}`);
36
+ }
37
+ const files = nativeToFiles.get(id.nativeSessionId) ?? [];
38
+ files.push(filename);
39
+ nativeToFiles.set(id.nativeSessionId, files);
40
+ }
41
+ catch (err) {
42
+ failures.push(`${filename}: ${err instanceof Error ? err.message : String(err)}`);
43
+ }
44
+ }
45
+ for (const [nativeSessionId, files] of nativeToFiles.entries()) {
46
+ if (files.length > 1) {
47
+ failures.push(`duplicate nativeSessionId ${JSON.stringify(nativeSessionId)} in ${files.join(", ")} — authority ambiguity; prune manually`);
48
+ }
49
+ }
50
+ if (failures.length > 0) {
51
+ for (const failure of failures)
52
+ console.error(`FAIL: ${failure}`);
53
+ process.exit(1);
54
+ }
55
+ console.log(`meta-store scan ok: ${scanned} record(s) scanned, no corrupt/duplicate/drift records`);
@@ -33,10 +33,18 @@
33
33
  // Clear the root `exclude` (it filters out every `.ts`-extension lib file the
34
34
  // bridge graph needs). Only node_modules must stay excluded.
35
35
  "exclude": ["../../node_modules"],
36
- // Just the bridge entry (+ the dependency-free protocol.js it reaches via an
37
- // explicit `.js` import). tsc auto-follows the import graph STATIC imports
38
- // AND the lazy `await import("./entwurf-preflight.ts")` and emits exactly the
39
- // boot closure, nothing more. This tracks graph drift automatically and keeps
40
- // the pi-lane-only acp/* (unreached at boot) out of the tarball.
41
- "include": ["./src/index.ts", "../../protocol.js"]
36
+ // The bridge boot entry (+ the dependency-free protocol.js it reaches via an
37
+ // explicit `.js` import) PLUS the doctor's store-scan helper. tsc auto-follows
38
+ // the import graphSTATIC imports AND the lazy
39
+ // `await import("./entwurf-preflight.ts")` and emits exactly that closure,
40
+ // nothing more (the pi-lane-only acp/* stays out of the tarball).
41
+ //
42
+ // WHY store-doctor rides THIS build: meta-bridge-doctor.sh's full store scan
43
+ // must run from an INSTALLED package (under node_modules, where strip-types is
44
+ // refused) — the same node_modules boundary start.sh crosses. Its only repo
45
+ // import is pi-extensions/lib/meta-session.ts, which the bridge graph ALREADY
46
+ // emits here, so it adds ONE leaf JS (dist/scripts/meta-bridge-store-doctor.js)
47
+ // and ZERO new deps. It is NOT in index.ts's boot closure, so
48
+ // check-entwurf-bridge-pi-free (which walks the index eager closure) is unaffected.
49
+ "include": ["./src/index.ts", "../../protocol.js", "../../scripts/meta-bridge-store-doctor.ts"]
42
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junghanacs/entwurf",
3
- "version": "0.12.3",
3
+ "version": "0.12.4",
4
4
  "description": "Garden-citizen dispatch substrate and meta-bridge for Claude Code, Codex, Antigravity, and pi harnesses.",
5
5
  "license": "MIT",
6
6
  "author": {
package/run.sh CHANGED
@@ -1731,6 +1731,10 @@ check_pack() {
1731
1731
  # this dist JS when present (the .ts source can't strip-types under
1732
1732
  # node_modules). prepack runs on `npm pack --dry-run`, so it is in this gate.
1733
1733
  "mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js"
1734
+ # 0.12.4 — the doctor's node_modules-safe store-scan artifact. meta-bridge-
1735
+ # doctor.sh runs this prebuilt JS when installed under node_modules (strip-types
1736
+ # refuses the .ts there), same boundary start.sh crosses. build-bridge emits it.
1737
+ "mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
1734
1738
  "scripts/postinstall-chmod.cjs"
1735
1739
  "pi/entwurf-capabilities.json"
1736
1740
  "pi/entwurf-targets.json"
@@ -1880,6 +1884,9 @@ check_pack_install() {
1880
1884
  "mcp/entwurf-bridge/src/index.ts"
1881
1885
  # 0.12.1 C — prepack-built node_modules-safe boot artifact (see check-pack).
1882
1886
  "mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js"
1887
+ # 0.12.4 — prebuilt node_modules-safe store-scan artifact for the doctor
1888
+ # (see check-pack). The installed-scan smoke below runs exactly this file.
1889
+ "mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
1883
1890
  "scripts/postinstall-chmod.cjs"
1884
1891
  "pi/entwurf-capabilities.json"
1885
1892
  "pi/entwurf-targets.json"
@@ -2127,6 +2134,52 @@ JS
2127
2134
  fi
2128
2135
  echo "[check-pack-install] installed bridge boot pass (dist boots under node_modules, pi-free: $boot_out)"
2129
2136
 
2137
+ # 0.12.4 — installed STORE-DOCTOR regression. meta-bridge-doctor.sh's full store
2138
+ # scan runs the prebuilt dist JS when it lives under node_modules (strip-types
2139
+ # refuses the .ts there — the same class as the bridge boot above). Before the dist
2140
+ # split the doctor ran the raw .ts and reported a FALSE "corrupt records" FAIL on
2141
+ # EVERY installed host. Prove the shipped dist JS scans a fixture store with PLAIN
2142
+ # node (a strip-types fallback would crash with the exact
2143
+ # ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING) AND that its rewritten import of the
2144
+ # emitted meta-session.js resolves — a real record exercises parseMetaIdentity.
2145
+ local installed_store_doctor="$npm_pkg/mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
2146
+ if [ ! -f "$installed_store_doctor" ]; then
2147
+ fail "[check-pack-install] installed store-doctor missing prebuilt dist (prepack did not emit it into the tarball?): $installed_store_doctor"
2148
+ return 1
2149
+ fi
2150
+ local sd_fixture="$npm_tmp/store-fixture"
2151
+ mkdir -p "$sd_fixture"
2152
+ # One valid v2 record: filename == "${gardenId}.meta.json" (no drift), unique
2153
+ # nativeSessionId (no dupe). gardenId must match YYYYMMDDTHHMMSS-[0-9a-f]{6}.
2154
+ printf '%s\n' '{"schemaVersion":2,"gardenId":"20990101T000000-abcdef","backend":"claude-code","nativeSessionId":"native-store-doctor-fixture","cwd":"/tmp/entwurf-fixture","model":null,"transcriptPath":null,"parentGardenId":null,"isEntwurf":false,"createdAt":"2099-01-01T00:00:00.000Z","recordUpdatedAt":"2099-01-01T00:00:00.000Z"}' \
2155
+ > "$sd_fixture/20990101T000000-abcdef.meta.json"
2156
+ local sd_out
2157
+ if ! sd_out=$(node "$installed_store_doctor" "$sd_fixture" 2>&1); then
2158
+ fail "[check-pack-install] installed store-doctor FAILED to scan under node_modules (strip-types-under-node_modules regression, or the emitted meta-session import broke):"
2159
+ echo "$sd_out" | tail -15 | sed 's/^/ /' >&2
2160
+ return 1
2161
+ fi
2162
+ if ! grep -q "1 record(s) scanned" <<<"$sd_out"; then
2163
+ fail "[check-pack-install] installed store-doctor scanned but did not report the fixture record (parseMetaIdentity path not exercised?): $sd_out"
2164
+ return 1
2165
+ fi
2166
+ echo "[check-pack-install] installed store-doctor scan pass (dist JS scans under node_modules with plain node: $sd_out)"
2167
+
2168
+ # 0.12.4 — installed DOCTOR DISPATCH lock. The artifact above proves the store-scan
2169
+ # target runs under node_modules; this proves the doctor SCRIPT actually routes to
2170
+ # it (store scan → dist JS) and defers the strip-types-only source-shape gate
2171
+ # (v2-surface) when installed, instead of running raw .ts and false-failing.
2172
+ local installed_doctor="$npm_pkg/scripts/meta-bridge-doctor.sh"
2173
+ if ! grep -q 'dist/scripts/meta-bridge-store-doctor.js' "$installed_doctor"; then
2174
+ fail "[check-pack-install] installed doctor does not dispatch the store scan to the dist JS under node_modules: $installed_doctor"
2175
+ return 1
2176
+ fi
2177
+ if ! grep -q 'shipped surface source present' "$installed_doctor"; then
2178
+ fail "[check-pack-install] installed doctor does not defer the v2-surface source-shape gate on installed hosts: $installed_doctor"
2179
+ return 1
2180
+ fi
2181
+ echo "[check-pack-install] installed doctor dispatch lock pass (store-scan → dist JS, v2-surface deferred)"
2182
+
2130
2183
  ok "[check-pack-install] publish install smoke pass"
2131
2184
  return 0
2132
2185
  }
@@ -147,10 +147,36 @@ echo "[meta-record store]"
147
147
  mkdir -p "$META_SESSIONS" 2>/dev/null || true
148
148
  if [ -d "$META_SESSIONS" ] && [ -w "$META_SESSIONS" ]; then ok "writable: $META_SESSIONS"; else bad "meta-sessions dir not writable: $META_SESSIONS"; fi
149
149
  if command -v node >/dev/null; then
150
- if node --experimental-strip-types "$REPO/scripts/meta-bridge-store-doctor.ts" "$META_SESSIONS" >/dev/null 2>&1; then
151
- ok "full store scan: no corrupt records, duplicate nativeSessionId, body/filename drift, or backend↔wakeMode contradiction"
152
- else
153
- bad "full store scan failed corrupt/duplicate/drift meta-record(s) present. Inspect with: node --experimental-strip-types $REPO/scripts/meta-bridge-store-doctor.ts $META_SESSIONS"
150
+ # Full store scan — mode by LOCATION (mirror mcp/entwurf-bridge/start.sh). Node
151
+ # REFUSES --experimental-strip-types for a .ts under node_modules
152
+ # (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING), so an INSTALLED package must scan
153
+ # via the prebuilt dist JS (build-bridge emits it; files:["mcp/"] ships it); a DEV
154
+ # CLONE lives outside node_modules and runs the .ts source. Before this split the
155
+ # doctor always ran the .ts and reported a FALSE "corrupt records" FAIL on every
156
+ # installed host (the 0.12.0 strip-types-under-node_modules class the bridge boot
157
+ # already fixed, but this doctor helper still ran raw .ts).
158
+ case "$REPO" in
159
+ */node_modules/*)
160
+ store_doctor="$REPO/mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
161
+ if [ -f "$store_doctor" ]; then
162
+ store_scan=(node "$store_doctor" "$META_SESSIONS")
163
+ else
164
+ bad "installed under node_modules but prebuilt store-doctor missing: $store_doctor — the tarball ships it via prepack; reinstall @junghanacs/entwurf"
165
+ store_scan=()
166
+ fi
167
+ ;;
168
+ *)
169
+ store_scan=(node --experimental-strip-types "$REPO/scripts/meta-bridge-store-doctor.ts" "$META_SESSIONS")
170
+ ;;
171
+ esac
172
+ # Guard the expansion: bash 3.2 (macOS) + set -u errors on "${arr[@]}" for a
173
+ # zero-length array, so only run/print when the command was actually built.
174
+ if [ "${#store_scan[@]}" -gt 0 ]; then
175
+ if "${store_scan[@]}" >/dev/null 2>&1; then
176
+ ok "full store scan: no corrupt records, duplicate nativeSessionId, body/filename drift, or backend↔wakeMode contradiction"
177
+ else
178
+ bad "full store scan failed — corrupt/duplicate/drift meta-record(s) present. Inspect with: ${store_scan[*]}"
179
+ fi
154
180
  fi
155
181
  else
156
182
  bad "cannot scan meta-record store without node"
@@ -297,11 +323,30 @@ if [ -f "$V2_MCP_SRC" ] && grep -q 'server.tool(' "$V2_MCP_SRC" && grep -q '"ent
297
323
  else
298
324
  bad "MCP entwurf_v2 verb not found in entwurf-bridge"
299
325
  fi
300
- if [ -f "$V2_SURFACE_SRC" ] && (cd "$REPO" && node --experimental-strip-types scripts/check-entwurf-v2-surface.ts >/dev/null 2>&1); then
301
- ok "check-entwurf-v2-surface gate passes (surface adapter + pi-native/MCP wiring)"
302
- else
303
- bad "check-entwurf-v2-surface gate FAILED or surface adapter missingrun: ./run.sh check-entwurf-v2-surface"
304
- fi
326
+ # check-entwurf-v2-surface is a SOURCE-SHAPE gate: it strip-types-runs a .ts gate
327
+ # (which imports typebox, a dev dep) to assert the surface source shape. Under
328
+ # node_modules that cannot run (strip-types refused + dev deps absent), AND its
329
+ # subject the shipped surface source shapeis a repo/release invariant already
330
+ # enforced by the release gate. So on an INSTALLED host, confirm the surface source
331
+ # SHIPPED and defer the exhaustive gate; the live runtime wiring (flag/tool/MCP verb)
332
+ # is already proven by the grep checks just above. Running the full .ts gate here
333
+ # produced a FALSE "gate FAILED" on every installed host.
334
+ case "$REPO" in
335
+ */node_modules/*)
336
+ if [ -f "$V2_SURFACE_SRC" ]; then
337
+ ok "check-entwurf-v2-surface: shipped surface source present; exhaustive source-shape gate is a repo/release invariant (not run under node_modules)"
338
+ else
339
+ bad "entwurf-v2-surface.ts missing from the installed package — the v2 surface source did not ship"
340
+ fi
341
+ ;;
342
+ *)
343
+ if [ -f "$V2_SURFACE_SRC" ] && (cd "$REPO" && node --experimental-strip-types scripts/check-entwurf-v2-surface.ts >/dev/null 2>&1); then
344
+ ok "check-entwurf-v2-surface gate passes (surface adapter + pi-native/MCP wiring)"
345
+ else
346
+ bad "check-entwurf-v2-surface gate FAILED or surface adapter missing — run: ./run.sh check-entwurf-v2-surface"
347
+ fi
348
+ ;;
349
+ esac
305
350
  # prefixRoots operator policy (5d-4b): the shared env SSOT both v2 surfaces read. Display
306
351
  # ONLY — the parser SSOT lives in entwurf-v2-surface.ts (proven by check-entwurf-v2-surface);
307
352
  # the doctor does NOT re-implement parsing. Unset ⇒ no prefix promotion (the safe default).