@junghanacs/entwurf 0.12.6 → 0.12.7
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 +31 -17
- package/BASELINE.md +42 -8
- package/CHANGELOG.md +22 -0
- package/DELIVERY.md +71 -14
- package/README.md +77 -45
- package/VERIFY.md +18 -13
- package/docs/setup-clean-host.md +80 -22
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +90 -66
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +54 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +153 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +436 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/context.js +157 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +105 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +90 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +194 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +153 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +42 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +49 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +104 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +30 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-native-push.js +57 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +10 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +9 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +21 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +5 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +17 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +125 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/adapter.js +158 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +61 -0
- package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +166 -0
- package/mcp/entwurf-bridge/dist/scripts/doctor-pi-provider.js +130 -0
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js +178 -0
- package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +24 -0
- package/mcp/entwurf-bridge/src/index.ts +101 -67
- package/mcp/entwurf-bridge/test.sh +1 -1
- package/mcp/entwurf-bridge/tsconfig.build.json +23 -3
- package/package.json +10 -5
- package/pi-extensions/lib/entwurf-deliverability.ts +62 -9
- package/pi-extensions/lib/entwurf-self-address.ts +58 -15
- package/pi-extensions/lib/entwurf-v2-contract.ts +120 -12
- package/pi-extensions/lib/entwurf-v2-decider.ts +60 -0
- package/pi-extensions/lib/entwurf-v2-native-push.ts +86 -0
- package/pi-extensions/lib/entwurf-v2-production.ts +20 -0
- package/pi-extensions/lib/entwurf-v2-release.ts +9 -0
- package/pi-extensions/lib/entwurf-v2-runner.ts +29 -1
- package/pi-extensions/lib/entwurf-v2-send.ts +7 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +17 -0
- package/pi-extensions/lib/meta-sender-identity.ts +154 -0
- package/pi-extensions/lib/native-push/adapter.ts +255 -0
- package/pi-extensions/lib/native-push/register.ts +99 -0
- package/run.sh +756 -214
- package/scripts/agy-bridge-config.py +446 -0
- package/scripts/agy-bridge.sh +359 -0
- package/scripts/agy-hooks-bridge.sh +193 -0
- package/scripts/agy-hooks-config.py +257 -0
- package/scripts/agy-imprint.sh +28 -0
- package/scripts/agy-imprint.ts +193 -0
- package/scripts/agy-statusline-bridge.sh +176 -0
- package/scripts/agy-statusline-config.py +213 -0
- package/scripts/agy-statusline.sh +256 -0
- package/scripts/build-bridge.sh +20 -0
- package/scripts/check-agy-sender-identity.ts +364 -0
- package/scripts/check-entwurf-bridge-boot.ts +8 -2
- package/scripts/check-entwurf-deliverability.ts +34 -0
- package/scripts/check-entwurf-self-address.ts +78 -11
- package/scripts/check-entwurf-v2-contract.ts +136 -1
- package/scripts/check-entwurf-v2-decider.ts +95 -1
- package/scripts/check-entwurf-v2-matrix.ts +14 -3
- package/scripts/check-entwurf-v2-native-push.ts +193 -0
- package/scripts/check-entwurf-v2-production.ts +68 -1
- package/scripts/check-entwurf-v2-runner.ts +58 -0
- package/scripts/check-entwurf-v2-surface.ts +35 -0
- package/scripts/check-install-surface.ts +357 -0
- package/scripts/check-native-push-adapter.ts +319 -0
- package/scripts/check-native-push-register.ts +130 -0
- package/scripts/dev-bin.sh +195 -0
- package/scripts/doctor-pi-provider.ts +140 -0
- package/scripts/meta-bridge-doctor.sh +36 -2
- package/scripts/register-pi-package.py +37 -3
- package/scripts/register-pi-provider.py +287 -0
- package/scripts/smoke-agy-hooks-state.sh +172 -0
- package/scripts/smoke-agy-install-state.sh +660 -0
- package/scripts/smoke-agy-native-push-live.ts +243 -0
- package/scripts/smoke-agy-statusline-state.sh +300 -0
- package/scripts/smoke-meta-async-drift.sh +9 -2
- package/scripts/smoke-meta-install-state.sh +20 -0
- package/scripts/smoke-pi-provider-state.sh +182 -0
- package/scripts/smoke-user-scope-citizen.sh +62 -0
- package/scripts/with-dist-lock.sh +81 -0
- package/scripts/__pycache__/meta-bridge-state.cpython-312.pyc +0 -0
- package/scripts/__pycache__/meta-bridge-state.cpython-313.pyc +0 -0
- package/scripts/__pycache__/register-pi-package.cpython-313.pyc +0 -0
package/run.sh
CHANGED
|
@@ -38,6 +38,37 @@ PACKAGE_NAME="@junghanacs/entwurf"
|
|
|
38
38
|
# saved session anchor.
|
|
39
39
|
PROVIDER_ID="entwurf"
|
|
40
40
|
|
|
41
|
+
# THE strip-types fence, in one place. Node REFUSES `--experimental-strip-types`
|
|
42
|
+
# for any .ts below node_modules (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING), so
|
|
43
|
+
# an installed package MUST run the prepack-emitted JS twin — the same boundary
|
|
44
|
+
# start.sh (0.12.1), the store-doctor (0.12.4), the plugin hook (0.12.5), and the
|
|
45
|
+
# agy imprint (0.12.7) each cross. Every .ts entrypoint routes through here so a
|
|
46
|
+
# NEW one cannot silently reintroduce the class: it was hand-written per surface
|
|
47
|
+
# before, and three operator commands (doctor-pi-provider / new-session-id /
|
|
48
|
+
# meta-bridge-prune) shipped dead under node_modules because of exactly that.
|
|
49
|
+
#
|
|
50
|
+
# A dev-only gate has no emitted twin by design (check-*/smoke-* are not shipped
|
|
51
|
+
# surfaces). Under an installed package it REFUSES rather than falling back to raw
|
|
52
|
+
# .ts — a fallback would just re-raise the fence error with a worse message.
|
|
53
|
+
# check-install-surface pins both halves statically.
|
|
54
|
+
run_ts() {
|
|
55
|
+
local rel="$1"; shift
|
|
56
|
+
case "$REPO_DIR" in
|
|
57
|
+
*/node_modules/*)
|
|
58
|
+
local dist="$REPO_DIR/mcp/entwurf-bridge/dist/${rel%.ts}.js"
|
|
59
|
+
if [ ! -f "$dist" ]; then
|
|
60
|
+
echo "entwurf: '$rel' is a dev-clone-only surface — the installed package ships no compiled twin." >&2
|
|
61
|
+
echo " (Node cannot strip types below node_modules; run this from a checkout.)" >&2
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
(cd "$REPO_DIR" && node "$dist" "$@")
|
|
65
|
+
;;
|
|
66
|
+
*)
|
|
67
|
+
(cd "$REPO_DIR" && node --experimental-strip-types "$rel" "$@")
|
|
68
|
+
;;
|
|
69
|
+
esac
|
|
70
|
+
}
|
|
71
|
+
|
|
41
72
|
usage() {
|
|
42
73
|
cat <<'EOF'
|
|
43
74
|
Usage:
|
|
@@ -76,6 +107,7 @@ Usage:
|
|
|
76
107
|
./run.sh smoke-entwurf-v2-spawn-live # LIVE phase gate (0.11 Stage 0 step 5c-3c, D5) — OUT of pnpm check, needs LIVE=1. Exercises the production SpawnBgResumeDeps against REAL OS objects: S1 real unix socket → awaitSocketAlive resolves (real lstat+probe), symlink→forged, absent→abort settles; S2 real child → spawn-event resolve + SIGTERM kill + exit-code capture; S3 watcher integration → real timeout→kill→child-exited→release ×1. Does NOT spawn a real pi resume (that=5d matrix). Run before 5d: LIVE=1 ./run.sh smoke-entwurf-v2-spawn-live
|
|
77
108
|
./run.sh smoke-entwurf-v2-spawn-resume-live # 0.11.0 (A) ACCEPTANCE gate — OUT of pnpm check, needs LIVE=1. The FULL spawn-bg resident lifecycle: mint backend=pi identity → seed a REAL dormant pi session (one-shot into ~/.pi/agent/sessions) → runEntwurfV2(owned-outcome) routes dormant→spawn-bg resume → a REAL detached pi --entwurf-control child stands its socket up, resumes, DOES a model turn. Asserts executed/spawn-bg/socket-alive/released + lock released ×1 + no lock file + pid alive + socket connectable + resume USER & assistant OK nonces in the session JSONL. Model-in-loop IN. The gate v1 deprecation (0.12) is predicated on. Model: ENTWURF_LIVE_TARGET=<provider>/<model> (default openai-codex/gpt-5.4). LIVE=1 ./run.sh smoke-entwurf-v2-spawn-resume-live
|
|
78
109
|
./run.sh smoke-entwurf-v2-matrix-live # LIVE sentinel (0.11 Stage 0 step 5d-5, D4-b) — OUT of pnpm check, needs LIVE=1. Drives REAL production runEntwurfV2 deps over REAL OS objects, 4 cells: C1 control-socket (real pi --entwurf-control resident → RPC send → lock acquire→release ×1), C1b socket-only (record-less live pi → control-socket sent / owned→bad-target, A1 narrow), C2 meta-mailbox deliverable (armed self-fetch citizen → real .msg enqueue, lock-free), C3 meta-mailbox guard (no armed receiver → reject, no garbage). Model-in-loop OUT (transport/lock/enqueue gate, GPT Q2); negative/timeout stay deterministic. Model: ENTWURF_LIVE_TARGET=<provider>/<model> (default openai-codex/gpt-5.4). LIVE=1 ./run.sh smoke-entwurf-v2-matrix-live
|
|
110
|
+
./run.sh smoke-agy-native-push-live # 봉인 8 LIVE acceptance for the native-push (agy) rail — OUT of pnpm check, needs LIVE=1 + AGY_CONVERSATION_ID (a live agy conversation). Drives the REAL antigravity adapter + register core + runEntwurfV2 (production deps): doctor-static preflight (dangling→FAIL, the ③ gate), probe route, register create/attach idempotency, fire→native-push delivered, post-send re-probe (D7 partial), owned-outcome→native-push-no-resume-authority, bogus-conv→native-push-probe-indeterminate. Meta-store isolated to a temp dir (only the agy round-trip is real; no real-store residue). LIVE=1 AGY_CONVERSATION_ID=<convId> ./run.sh smoke-agy-native-push-live
|
|
79
111
|
./run.sh check-entwurf-facts # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 1+2): PURE PeerFact core + resolveFactList union — R1 out-of-domain→unsupported, R3b pi 4-value, facts-only keyset; union: PeerFact+SocketOnlyFact by gardenId, dormant→dead, F3 indeterminate preserved, non-pi+socket fail-loud; pure, no IO
|
|
80
112
|
./run.sh check-socket-discovery # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 3): SOCKET-axis scanSocketProbes — probes (dir sockets) ∪ (in-domain citizen canonical paths) 3-valued; dormant citizen no-file → dead (resumable, not unprobed), stall → indeterminate (F3), dir hygiene/dedup/missing-dir + e2e → resolveFactList; readdir/probe injected, no IO
|
|
81
113
|
./run.sh check-meta-listing # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 4a): META-STORE axis listAllMetaIdentities — explicit-partial: parse failure / body-filename drift → explicit {filename,message} error (verbatim, no synthetic fields), valid records still listed (corrupt doesn't blind); mode strict throws / collect partial; entries/readRecord injected, no IO
|
|
@@ -84,6 +116,9 @@ Usage:
|
|
|
84
116
|
./run.sh check-entwurf-self-address # deterministic gate (SE-1/SE-2 slice 1): self-addressability honesty predicate computeSelfAddressability — pi replyable ⟺ live socket; meta ⟺ recordBacked ∧ ownerAlive ∧ watchArmed (regression-proof record-present rows); SOURCE GUARD buildStrictPiSenderEnvelope drops hardcoded replyable:true + existsSync-probes socket, entwurf_self renders alive vs expected. meta watchArmed wired in slice 2 (same release block)
|
|
85
117
|
./run.sh check-entwurf-deliverability # deterministic gate (SE-1/SE-2 slice 2c): conversational-mailbox deliverability predicate — computeMetaReceiverActive (recordBacked ∧ ownerAlive ∧ watchArmed) + mailboxConversationalDeliverable (self-fetch AND active); direct-inject pi refused (SE-1), self-fetch dead/unarmed refused (SE-2); self-address shares the same atom
|
|
86
118
|
./run.sh check-entwurf-mailbox-guard # deterministic gate (SE-1/SE-2 slice 2d): guarded mailbox enqueue — PURE 0-call (undeliverable target leaves injected enqueue uncalled) + TMPDIR snapshot (refused send leaves mailbox byte-identical, accepted writes one .msg) + fact gathering from record/capability/receiver-marker
|
|
119
|
+
./run.sh check-native-push-adapter # deterministic gate (봉인 3/8): native-push adapter leaf (antigravity) via a FAKE runner — FULL pid scan (not head -1), dead vs indeterminate, VOLATILE route re-discovery (no cache), send argv+ANTIGRAVITY_LS_ADDRESS env, non-zero exit throws, NO adapter-level retry (executor-owned), resolveNativePushAdapter fail-fast
|
|
120
|
+
./run.sh check-native-push-register # deterministic gate (봉인 5): registerNativeConversation (entwurf_register_native core) via fake adapter + isolated mkdtemp store — live probe→CREATE, re-register→ATTACH (same gid, cwd refreshed, no dup), not-live probe→REFUSE (throws, no record), receiver-marker abstinence (보정① source guard)
|
|
121
|
+
./run.sh check-agy-sender-identity # deterministic gate (#46 sender lane): WHO is calling the bridge — real agy hook as a child process writes an antigravity sender marker keyed by its PARENT pid (never on upsert failure), and resolveTrustedMetaSenderIdentity over isolated stores yields 0→null / 1→identity on EITHER backend / two distinct live identities on one owner pid→THROW (never guess, never downgrade to anonymous). This is what turns an agy send from external-mcp/unknown-host into a replyable garden citizen
|
|
87
122
|
./run.sh check-package-source-routing # deterministic gate (#29): package-source -> install-root mapping + fail-fast routing (local/git/npm/missing/project/no-source × local+remote, self-root, resume), no backend
|
|
88
123
|
./run.sh smoke-session-id-name # live 3-turn substrate smoke (Phase 3a): Pi 0.78 --session-id/--name through the bridge — header id/cwd, session_info name, append-not-recreate, spawn-only name, wrong-cwd footgun evidence
|
|
89
124
|
./run.sh new-session-id # print one fresh garden-native session id for operator launchers (--session-id)
|
|
@@ -91,6 +126,9 @@ Usage:
|
|
|
91
126
|
./run.sh smoke-meta-async-drift # 1.0.0 meta-bridge step 1: drift sentinel — version pins + Claude binary undocumented-behavior markers (LIVE=1 adds plugin watch-arm probe)
|
|
92
127
|
./run.sh smoke-meta-honesty # 1.0.0 meta-bridge: honesty regression gate (#30 blockers) — doorbell counts ALL msgs honestly + hook logs failures as ERROR (best-effort, no scream). Offline/deterministic (deps: bash+node+python3)
|
|
93
128
|
./run.sh smoke-meta-install-state # 1.0.0 meta-bridge Phase 2: stateful install/uninstall + store-doctor regression gate. Offline/deterministic (deps: bash+node+python3)
|
|
129
|
+
./run.sh smoke-agy-install-state # agy MCP + exact permission ownership regression (120): isolated HOME+XDG, adopt/state/inverse, symlink refuse, setup degrade. Offline/deterministic
|
|
130
|
+
./run.sh smoke-agy-statusline-state # agy ambient garden-id statusLine install/doctor/inverse regression (62). Offline/deterministic
|
|
131
|
+
./run.sh smoke-agy-hooks-state # agy PreInvocation birth/sender hook install/doctor/inverse + direct stdin→meta-record regression (37). Offline/deterministic
|
|
94
132
|
./run.sh smoke-user-scope-citizen # 0.12.6 install-boundary: pi packages[] registration SSOT (register-pi-package.py) — idempotent + preserves unrelated + normalizes stale + remove symmetry + fails loud. Offline/hermetic (deps: bash+python3)
|
|
95
133
|
./run.sh smoke-meta-prune # 1.0.0 meta-bridge Phase 4: listing-only store janitor regression gate — classify keep/orphan/stale/ambiguous, delete nothing. Offline/deterministic (deps: bash+node)
|
|
96
134
|
./run.sh smoke-meta-keyset-guard # 0.10.0 meta-bridge: keyset-owner guard regression — check-keyset-overlap + managed-keys SSOT (disjoint passes, collisions fail). Offline/hermetic (deps: bash+python3)
|
|
@@ -100,6 +138,15 @@ Usage:
|
|
|
100
138
|
./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)
|
|
101
139
|
./run.sh uninstall-meta-bridge # 1.0.0 meta-bridge Phase 2: stateful GLOBAL uninstall (restore only keys/items captured in install-state)
|
|
102
140
|
./run.sh doctor-meta-bridge # 1.0.0 meta-bridge Phase 2: fail-loud doctor — toolchain + state + plugin/MCP + store scan + hook errors + SessionStart evidence + writer-version parity (source↔assembled↔installed: FAIL on a stale deployed meta-record writer)
|
|
141
|
+
./run.sh install-agy-bridge # 봉인 7: agy MCP install adapter — register ONE entwurf-bridge server in the agy mcp_config (adopt file / create / REFUSE symlink), stable bin command, install-state under $XDG_DATA_HOME/entwurf/agy-bridge/
|
|
142
|
+
./run.sh uninstall-agy-bridge # 봉인 7: honest inverse of install-agy-bridge from install-state (restore preimage / remove key; refuse if config became a symlink)
|
|
143
|
+
./run.sh doctor-agy-bridge # fail-loud doctor: MCP config + exact permission rule + state + live probe label
|
|
144
|
+
./run.sh install-agy-statusline # own the agy statusLine subtree with bare entwurf-agy-statusline; preserve unrelated settings
|
|
145
|
+
./run.sh uninstall-agy-statusline # honest inverse from statusline install-state
|
|
146
|
+
./run.sh doctor-agy-statusline # fail-loud statusLine config/bin/state doctor + honest live SKIP
|
|
147
|
+
./run.sh install-agy-hooks # #46 agy birth imprint hook — named PreInvocation hook running bare entwurf-agy-imprint, preserving other hooks
|
|
148
|
+
./run.sh uninstall-agy-hooks # honest inverse of install-agy-hooks from install-state
|
|
149
|
+
./run.sh doctor-agy-hooks # fail-loud doctor for agy hooks.json imprint wiring
|
|
103
150
|
./run.sh meta-bridge-prune # 1.0.0 meta-bridge Phase 4: LISTING-ONLY store hygiene — classify orphan/stale/ambiguous/keep, print manual rm commands, delete NOTHING ([dir] [--ttl-days N])
|
|
104
151
|
./run.sh meta-bridge-managed-keys # 0.10.0 meta-bridge: print the SSOT of settings keys entwurf OWNS (consumers read this to stay disjoint — keyset-owner invariant)
|
|
105
152
|
./run.sh check-keyset-overlap <fragment.json...> # 0.10.0 meta-bridge: PREVENTIVE keyset guard — fail if a consumer fragment collides with any pi-owned key (cross-repo; not in pnpm check)
|
|
@@ -109,7 +156,8 @@ Usage:
|
|
|
109
156
|
./run.sh sync-auth # copy ~/.pi/agent/auth.json anthropic OAuth credentials to entwurf alias
|
|
110
157
|
./run.sh install [project-dir] # INTERNAL part of `setup` (project .pi/settings.json wiring) + npm-consumer entry — prefer `setup`, don't call directly for dev
|
|
111
158
|
./run.sh setup:links [--force] # repair ~/.pi/agent/entwurf-targets.json link (use --force to replace a stale operator file or wrong symlink; a .bak is taken)
|
|
112
|
-
./run.sh remove [project-dir] # remove entwurf entries from project .pi/settings.json
|
|
159
|
+
./run.sh remove [project-dir] # remove entwurf entries from project .pi/settings.json (project scope only; global user-scope citizen left intact)
|
|
160
|
+
./run.sh remove-user-scope # explicit GLOBAL inverse of install's user-scope citizen: drop entwurf from ~/.pi/agent/settings.json packages[] (affects ALL cwds — shared entry, not per-project)
|
|
113
161
|
|
|
114
162
|
Notes:
|
|
115
163
|
- project-dir defaults to current directory
|
|
@@ -299,82 +347,11 @@ install_local_package() {
|
|
|
299
347
|
# packages[] registration via the shared SSOT — same is_entwurf_source
|
|
300
348
|
# predicate + idempotency as user-scope and remove (not a substring match).
|
|
301
349
|
python3 "$REPO_DIR/scripts/register-pi-package.py" "$project_dir/.pi/settings.json" "$REPO_DIR"
|
|
302
|
-
# entwurfProvider.mcpServers
|
|
303
|
-
#
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
settings_path = Path(sys.argv[1])
|
|
309
|
-
repo_dir = str(Path(sys.argv[2]).resolve())
|
|
310
|
-
settings_path.parent.mkdir(parents=True, exist_ok=True)
|
|
311
|
-
if settings_path.exists():
|
|
312
|
-
data = json.loads(settings_path.read_text())
|
|
313
|
-
if not isinstance(data, dict):
|
|
314
|
-
raise SystemExit("settings.json is not an object")
|
|
315
|
-
else:
|
|
316
|
-
data = {}
|
|
317
|
-
|
|
318
|
-
# --- entwurfProvider.mcpServers bundled entries ---------------------------
|
|
319
|
-
# Ship the two in-repo MCP adapters pre-wired so `pi install` produces a
|
|
320
|
-
# working setup without the consumer hand-editing settings.json. User-authored
|
|
321
|
-
# overrides (different command/args) are preserved untouched.
|
|
322
|
-
provider = data.setdefault("entwurfProvider", {})
|
|
323
|
-
if not isinstance(provider, dict):
|
|
324
|
-
raise SystemExit("entwurfProvider is not an object")
|
|
325
|
-
servers = provider.setdefault("mcpServers", {})
|
|
326
|
-
if not isinstance(servers, dict):
|
|
327
|
-
raise SystemExit("entwurfProvider.mcpServers is not an object")
|
|
328
|
-
|
|
329
|
-
BUNDLED = ("entwurf-bridge",)
|
|
330
|
-
# 0.4.14: session-bridge MCP was retracted (issue #7 — unified entwurf surface).
|
|
331
|
-
# Install path now only wires entwurf-bridge. Existing operator settings that
|
|
332
|
-
# carry the old bundled session-bridge entry are pruned below during install;
|
|
333
|
-
# `./run.sh remove` also keeps session-bridge in its cleanup tuple so legacy
|
|
334
|
-
# entries are removed on uninstall too.
|
|
335
|
-
for name in BUNDLED:
|
|
336
|
-
desired_cmd = f"{repo_dir}/mcp/{name}/start.sh"
|
|
337
|
-
desired = {"command": desired_cmd, "args": []}
|
|
338
|
-
existing = servers.get(name)
|
|
339
|
-
if existing is None:
|
|
340
|
-
servers[name] = desired
|
|
341
|
-
print(f"install: added entwurfProvider.mcpServers.{name}")
|
|
342
|
-
elif isinstance(existing, dict) and existing.get("command") == desired_cmd:
|
|
343
|
-
# Already managed by us at the current repo path. Add the default args
|
|
344
|
-
# field when missing, but never overwrite user-customized args.
|
|
345
|
-
if "args" not in existing:
|
|
346
|
-
existing["args"] = []
|
|
347
|
-
print(f"install: normalized entwurfProvider.mcpServers.{name}.args -> []")
|
|
348
|
-
elif existing.get("args") != []:
|
|
349
|
-
print(f"install: preserved entwurfProvider.mcpServers.{name}.args (custom args)")
|
|
350
|
-
else:
|
|
351
|
-
cmd_repr = existing.get("command") if isinstance(existing, dict) else existing
|
|
352
|
-
print(f"install: preserved entwurfProvider.mcpServers.{name} (user override: {cmd_repr})")
|
|
353
|
-
|
|
354
|
-
# Legacy-bundled MCP names that prior versions of this installer wrote and that
|
|
355
|
-
# the current cutover supersedes. One-shot install-time prune (NOT a runtime
|
|
356
|
-
# alias): only remove entries whose command matches the bundled start.sh path,
|
|
357
|
-
# so user-customized commands are left alone.
|
|
358
|
-
# - session-bridge: retracted in 0.4.14 (issue #7, unified entwurf surface).
|
|
359
|
-
# - pi-tools-bridge: renamed to entwurf-bridge in 0.11 S2 cutover.
|
|
360
|
-
LEGACY_BUNDLED = {
|
|
361
|
-
"session-bridge": "retracted in 0.4.14, issue #7",
|
|
362
|
-
"pi-tools-bridge": "renamed to entwurf-bridge in 0.11 S2 cutover",
|
|
363
|
-
}
|
|
364
|
-
for name, reason in LEGACY_BUNDLED.items():
|
|
365
|
-
existing = servers.get(name)
|
|
366
|
-
if not isinstance(existing, dict):
|
|
367
|
-
continue
|
|
368
|
-
cmd = existing.get("command")
|
|
369
|
-
if not isinstance(cmd, str):
|
|
370
|
-
continue
|
|
371
|
-
if cmd == f"{repo_dir}/mcp/{name}/start.sh" or cmd.endswith(f"/entwurf/mcp/{name}/start.sh"):
|
|
372
|
-
del servers[name]
|
|
373
|
-
print(f"install: pruned legacy entwurfProvider.mcpServers.{name} ({reason})")
|
|
374
|
-
|
|
375
|
-
settings_path.write_text(json.dumps(data, indent=2) + "\n")
|
|
376
|
-
print(f"install: updated {settings_path}")
|
|
377
|
-
PY
|
|
350
|
+
# entwurfProvider.mcpServers.entwurf-bridge (project scope — checkout-local, NO state; #46
|
|
351
|
+
# Task 2) via the shared register-pi-provider SSOT: normalize the command to the bare stable
|
|
352
|
+
# bin `entwurf-bridge` (ownership-classified: absent/managed-current/managed-legacy adopt, a
|
|
353
|
+
# true user-override is left untouched) + prune legacy bundles. project remove is the inverse.
|
|
354
|
+
python3 "$REPO_DIR/scripts/register-pi-provider.py" install "$project_dir/.pi/settings.json" "$REPO_DIR" --scope project
|
|
378
355
|
ensure_agent_dir_symlinks
|
|
379
356
|
register_user_scope_citizen
|
|
380
357
|
}
|
|
@@ -393,6 +370,31 @@ register_user_scope_citizen() {
|
|
|
393
370
|
local agent_dir="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
|
|
394
371
|
# Shared idempotent implementation (also driven by smoke-user-scope-citizen).
|
|
395
372
|
python3 "$REPO_DIR/scripts/register-pi-package.py" "$agent_dir/settings.json" "$REPO_DIR"
|
|
373
|
+
# #46 Task 2: own entwurfProvider.mcpServers.entwurf-bridge as the bare stable bin at USER scope
|
|
374
|
+
# (GLOBAL/durable →파급s to every cwd), so its inverse needs an install-state honest inverse
|
|
375
|
+
# under $XDG_DATA_HOME/entwurf/pi-provider/ (Task 0/1 discipline). project scope is checkout-
|
|
376
|
+
# local and covered by `run.sh remove` (no state) — deliberate, reasoned asymmetry.
|
|
377
|
+
local pp_state="${XDG_DATA_HOME:-$HOME/.local/share}/entwurf/pi-provider/install-state.json"
|
|
378
|
+
python3 "$REPO_DIR/scripts/register-pi-provider.py" install "$agent_dir/settings.json" "$REPO_DIR" --scope user --state "$pp_state"
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
# The honest inverse of register_user_scope_citizen: drop entwurf from the GLOBAL
|
|
382
|
+
# ~/.pi/agent/settings.json packages[]. Deliberately NOT folded into `run.sh remove`
|
|
383
|
+
# (project scope): the user-scope citizen is a single GLOBAL entry keyed on this
|
|
384
|
+
# checkout and SHARED by every project + every foreign cwd, so tearing it down as a
|
|
385
|
+
# side effect of one project's remove would break `--entwurf-control` everywhere else
|
|
386
|
+
# (the exact "install → just works from any cwd" invariant register_user_scope_citizen
|
|
387
|
+
# exists to hold). Same explicit-global-lifecycle shape as install/uninstall-meta-bridge.
|
|
388
|
+
# Uses the same is_entwurf_source SSOT + --remove, so it never over-deletes a look-alike
|
|
389
|
+
# (entwurf-notes, openclaw-entwurf) and preserves every other package/key. Idempotent:
|
|
390
|
+
# no entwurf entry → no-op.
|
|
391
|
+
remove_user_scope_citizen() {
|
|
392
|
+
local agent_dir="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
|
|
393
|
+
python3 "$REPO_DIR/scripts/register-pi-package.py" "$agent_dir/settings.json" "$REPO_DIR" --remove
|
|
394
|
+
# #46 Task 2: honest inverse of the user-scope entwurfProvider ownership — the install-state
|
|
395
|
+
# drives it (absent/managed-* → remove OUR key; a user-override we never owned is untouched).
|
|
396
|
+
local pp_state="${XDG_DATA_HOME:-$HOME/.local/share}/entwurf/pi-provider/install-state.json"
|
|
397
|
+
python3 "$REPO_DIR/scripts/register-pi-provider.py" remove "$agent_dir/settings.json" "$REPO_DIR" --scope user --state "$pp_state"
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
# Ensure agent-level resources that entwurf code reads from
|
|
@@ -488,55 +490,21 @@ remove_local_package() {
|
|
|
488
490
|
# install, so remove never over-deletes a look-alike repo (entwurf-notes, …)
|
|
489
491
|
# that install would never have registered.
|
|
490
492
|
python3 "$REPO_DIR/scripts/register-pi-package.py" "$project_dir/.pi/settings.json" "$REPO_DIR" --remove
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
if
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
# Only remove entries that look like they came from ./run.sh install: either
|
|
507
|
-
# the command matches the current $REPO_DIR anchor exactly, or it ends with
|
|
508
|
-
# the bundled "/entwurf/mcp/<name>/start.sh" pattern (covers a rebuilt
|
|
509
|
-
# checkout under a different directory). Anything else is treated as a user
|
|
510
|
-
# override and left in place.
|
|
511
|
-
BUNDLED = ("entwurf-bridge", "session-bridge", "pi-tools-bridge")
|
|
512
|
-
provider = data.get("entwurfProvider")
|
|
513
|
-
mcp_removed = 0
|
|
514
|
-
if isinstance(provider, dict):
|
|
515
|
-
servers = provider.get("mcpServers")
|
|
516
|
-
if isinstance(servers, dict):
|
|
517
|
-
for name in BUNDLED:
|
|
518
|
-
existing = servers.get(name)
|
|
519
|
-
if not isinstance(existing, dict):
|
|
520
|
-
continue
|
|
521
|
-
cmd = existing.get("command")
|
|
522
|
-
if not isinstance(cmd, str):
|
|
523
|
-
continue
|
|
524
|
-
exact = cmd == f"{repo_dir}/mcp/{name}/start.sh"
|
|
525
|
-
pattern = cmd.endswith(f"/entwurf/mcp/{name}/start.sh")
|
|
526
|
-
if exact or pattern:
|
|
527
|
-
del servers[name]
|
|
528
|
-
mcp_removed += 1
|
|
529
|
-
print(f"remove: removed entwurfProvider.mcpServers.{name}")
|
|
530
|
-
else:
|
|
531
|
-
print(f"remove: preserved entwurfProvider.mcpServers.{name} (user override: {cmd})")
|
|
532
|
-
if not servers:
|
|
533
|
-
provider.pop("mcpServers", None)
|
|
534
|
-
if not provider:
|
|
535
|
-
data.pop("entwurfProvider", None)
|
|
536
|
-
|
|
537
|
-
settings_path.write_text(json.dumps(data, indent=2) + "\n")
|
|
538
|
-
print(f"remove: removed {mcp_removed} mcpServers entries from {settings_path}")
|
|
539
|
-
PY
|
|
493
|
+
# entwurfProvider.mcpServers.entwurf-bridge cleanup (project scope) via the shared SSOT: strip
|
|
494
|
+
# our-managed shapes (the bare stable bin AND the legacy repo start.sh path — a true user
|
|
495
|
+
# override is left in place) + prune legacy bundles. Mirrors install's ownership predicate so it
|
|
496
|
+
# never over-deletes a look-alike, and now also catches the bare bin the Task-2 install writes.
|
|
497
|
+
python3 "$REPO_DIR/scripts/register-pi-provider.py" remove "$project_dir/.pi/settings.json" "$REPO_DIR" --scope project
|
|
498
|
+
# `remove` is project-scope only. The GLOBAL user-scope citizen in
|
|
499
|
+
# ~/.pi/agent/settings.json (written by install's register_user_scope_citizen)
|
|
500
|
+
# is shared across every project + foreign cwd, so it is left intact here to
|
|
501
|
+
# avoid breaking `--entwurf-control` elsewhere. Point the operator at the
|
|
502
|
+
# explicit global inverse so the install↔remove asymmetry is never silent.
|
|
503
|
+
local agent_settings="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}/settings.json"
|
|
504
|
+
if python3 "$REPO_DIR/scripts/register-pi-package.py" "$agent_settings" "$REPO_DIR" --remove --dry-run 2>/dev/null | grep -q 'would remove'; then
|
|
505
|
+
log "note: global user-scope citizen still registered in $agent_settings"
|
|
506
|
+
log " run './run.sh remove-user-scope' to remove it (affects ALL cwds)"
|
|
507
|
+
fi
|
|
540
508
|
}
|
|
541
509
|
|
|
542
510
|
check_model_lock() {
|
|
@@ -544,7 +512,7 @@ check_model_lock() {
|
|
|
544
512
|
# No pi process, no network, no API cost. Mocks ExtensionAPI/Context and
|
|
545
513
|
# drives the model_select handler through every quadrant + edge case
|
|
546
514
|
# (see scripts/check-model-lock.ts header for the full matrix).
|
|
547
|
-
|
|
515
|
+
run_ts scripts/check-model-lock.ts
|
|
548
516
|
}
|
|
549
517
|
|
|
550
518
|
check_shell_quote() {
|
|
@@ -553,7 +521,7 @@ check_shell_quote() {
|
|
|
553
521
|
# across the two duplication sites AND behavioral correctness on the
|
|
554
522
|
# payload classes that caused the 2026-05-18 remote entwurf incident
|
|
555
523
|
# (backtick / $(...) / $VAR / korean tokens). No process spawn, no SSH.
|
|
556
|
-
|
|
524
|
+
run_ts scripts/check-shell-quote.ts
|
|
557
525
|
}
|
|
558
526
|
|
|
559
527
|
check_entwurf_session_identity() {
|
|
@@ -563,7 +531,7 @@ check_entwurf_session_identity() {
|
|
|
563
531
|
# models, titleSlug canonicalization, registry exact-tuple membership, name=
|
|
564
532
|
# info-only invariants, and header-scan collision pre-check. Isolates registry
|
|
565
533
|
# + sessions base to a temp dir. No backend, no API, no spawn.
|
|
566
|
-
|
|
534
|
+
run_ts scripts/check-entwurf-session-identity.ts
|
|
567
535
|
}
|
|
568
536
|
|
|
569
537
|
check_meta_session() {
|
|
@@ -573,7 +541,7 @@ check_meta_session() {
|
|
|
573
541
|
# real temp dir), idempotent existence-keyed decideUpsert + identity-drift
|
|
574
542
|
# refusal, and the pre-drilled read-receipt mutators. Pure functions; no
|
|
575
543
|
# backend, no hook, no API.
|
|
576
|
-
|
|
544
|
+
run_ts scripts/check-meta-session.ts
|
|
577
545
|
}
|
|
578
546
|
|
|
579
547
|
check_meta_record_v2() {
|
|
@@ -583,7 +551,7 @@ check_meta_record_v2() {
|
|
|
583
551
|
# and v2 field-contract crashes. Reader/normalizer only — no v2 writer yet.
|
|
584
552
|
# Kept separate from check-meta-session so 3D's v1-gate rewrites leave this
|
|
585
553
|
# back-compat golden untouched. Pure functions; no backend, no hook, no API.
|
|
586
|
-
|
|
554
|
+
run_ts scripts/check-meta-record-v2.ts
|
|
587
555
|
}
|
|
588
556
|
|
|
589
557
|
check_mailbox_receipt_state() {
|
|
@@ -593,7 +561,7 @@ check_mailbox_receipt_state() {
|
|
|
593
561
|
# keyset, then the fs store (stamp → persist → read-back) in a temp mailbox
|
|
594
562
|
# dir. Schema/store only — no live enqueue/read dual-write (that is 3D). No
|
|
595
563
|
# backend, no hook, no API.
|
|
596
|
-
|
|
564
|
+
run_ts scripts/check-mailbox-receipt-state.ts
|
|
597
565
|
}
|
|
598
566
|
|
|
599
567
|
check_entwurf_capabilities() {
|
|
@@ -604,7 +572,7 @@ check_entwurf_capabilities() {
|
|
|
604
572
|
# META_BACKEND_DESCRIPTORS for the three existing backends (drift guard), and
|
|
605
573
|
# strict keyset/coverage/field crashes. Parser/gate only — no live routing,
|
|
606
574
|
# no record/descriptor consumer change (that is 3D). No backend, no API.
|
|
607
|
-
|
|
575
|
+
run_ts scripts/check-entwurf-capabilities.ts
|
|
608
576
|
}
|
|
609
577
|
|
|
610
578
|
check_meta_dual_read() {
|
|
@@ -614,7 +582,7 @@ check_meta_dual_read() {
|
|
|
614
582
|
# unknown-version crash. Pure functions only — no fs upsert wiring, no
|
|
615
583
|
# readMetaInbox/enqueueMetaMessage change, no record.delivery removal (3D-2/3/4).
|
|
616
584
|
# No backend, no hook, no API.
|
|
617
|
-
|
|
585
|
+
run_ts scripts/check-meta-dual-read.ts
|
|
618
586
|
}
|
|
619
587
|
|
|
620
588
|
check_meta_mailbox_state_write() {
|
|
@@ -626,7 +594,7 @@ check_meta_mailbox_state_write() {
|
|
|
626
594
|
# carries lastEnqueuedAt/lastReadAt with field isolation, lastDeliveredAt is never
|
|
627
595
|
# invented, an empty inbox is a no-op on BOTH record and state (⑥), and a state
|
|
628
596
|
# drift surfaces fail-loud. v2 citizen seeded via upsertMetaSession. No API.
|
|
629
|
-
|
|
597
|
+
run_ts scripts/check-meta-mailbox-state-write.ts
|
|
630
598
|
}
|
|
631
599
|
|
|
632
600
|
check_meta_receiver_marker() {
|
|
@@ -639,7 +607,7 @@ check_meta_receiver_marker() {
|
|
|
639
607
|
# from "no marker"); armProvenance constrained to the arm-capable events so
|
|
640
608
|
# UserPromptSubmit cannot mint presence; reader does NOT gate on record existence
|
|
641
609
|
# (recordBacked is the deliverability predicate's fact). Real tmpdir, no API.
|
|
642
|
-
|
|
610
|
+
run_ts scripts/check-meta-receiver-marker.ts
|
|
643
611
|
}
|
|
644
612
|
|
|
645
613
|
check_meta_migration() {
|
|
@@ -649,7 +617,7 @@ check_meta_migration() {
|
|
|
649
617
|
# state.json). Crash-order: a v1 record's receipts migrate to state BEFORE the v2
|
|
650
618
|
# rewrite (proven via upsert attach), and a drift'd state makes migrate throw with
|
|
651
619
|
# the record STILL v1 (recoverable: next attach re-migrates). Temp dir, no API.
|
|
652
|
-
|
|
620
|
+
run_ts scripts/check-meta-migration.ts
|
|
653
621
|
}
|
|
654
622
|
|
|
655
623
|
check_meta_dual_consumers() {
|
|
@@ -661,7 +629,7 @@ check_meta_dual_consumers() {
|
|
|
661
629
|
# authority ambiguity → throw, so the v2 upsert never duplicate-mints) + v1 normalize +
|
|
662
630
|
# body/filename drift fail-fast. The v1-only raw readers remain for v1-fixture gates.
|
|
663
631
|
# Temp dir, no API.
|
|
664
|
-
|
|
632
|
+
run_ts scripts/check-meta-dual-consumers.ts
|
|
665
633
|
}
|
|
666
634
|
|
|
667
635
|
check_meta_capability_source() {
|
|
@@ -674,7 +642,7 @@ check_meta_capability_source() {
|
|
|
674
642
|
# 3 backends). The record.delivery.wakeMode SLOT stays (removal is 3D-4); only the
|
|
675
643
|
# SOURCE moves. check-entwurf-capabilities still owns the registry ≡ const drift
|
|
676
644
|
# guard. Pure — no fs writes, no backend, no hook, no API.
|
|
677
|
-
|
|
645
|
+
run_ts scripts/check-meta-capability-source.ts
|
|
678
646
|
}
|
|
679
647
|
|
|
680
648
|
check_socket_probe() {
|
|
@@ -685,7 +653,7 @@ check_socket_probe() {
|
|
|
685
653
|
# invariant. Listing lists alive only. Pure classify + GC/listing policy +
|
|
686
654
|
# a two-socket integration (live listener → alive survives; nonexistent →
|
|
687
655
|
# dead GC-eligible). No wire timeout fixture, no backend, no API.
|
|
688
|
-
|
|
656
|
+
run_ts scripts/check-socket-probe.ts
|
|
689
657
|
}
|
|
690
658
|
|
|
691
659
|
check_project_trust_handler() {
|
|
@@ -697,7 +665,7 @@ check_project_trust_handler() {
|
|
|
697
665
|
# never undefined. Plus the thin adapter: fake ctx.ui.select, single-writer
|
|
698
666
|
# (handler never calls store.set — pi persists on remember:true), F5a evidence
|
|
699
667
|
# in the prompt title. No real UI, no backend, no API.
|
|
700
|
-
|
|
668
|
+
run_ts scripts/check-project-trust-handler.ts
|
|
701
669
|
}
|
|
702
670
|
|
|
703
671
|
check_entwurf_v2_contract() {
|
|
@@ -711,7 +679,7 @@ check_entwurf_v2_contract() {
|
|
|
711
679
|
# Q2 owned-outcome+live never auto-sends. R5 taxonomy covers table reasons +
|
|
712
680
|
# pre-claims bad-target/untrusted-fail-fast/target-locked (bucket B F2). Plus
|
|
713
681
|
# a schema↔types drift guard on the TypeBox input/receipt. Pure, no API.
|
|
714
|
-
|
|
682
|
+
run_ts scripts/check-entwurf-v2-contract.ts
|
|
715
683
|
}
|
|
716
684
|
|
|
717
685
|
check_entwurf_v2_lock() {
|
|
@@ -726,7 +694,7 @@ check_entwurf_v2_lock() {
|
|
|
726
694
|
# fail-closed to conflict. Empty/corrupt lockfile = conflict, never
|
|
727
695
|
# auto-deleted. F2-P1: a malformed gid throws before any path is built. Real
|
|
728
696
|
# temp dir (wx atomicity under test); clock/nonce/pid/host/kill injected.
|
|
729
|
-
|
|
697
|
+
run_ts scripts/check-entwurf-v2-lock.ts
|
|
730
698
|
}
|
|
731
699
|
|
|
732
700
|
check_entwurf_v2_decider() {
|
|
@@ -740,7 +708,7 @@ check_entwurf_v2_decider() {
|
|
|
740
708
|
# takes NO lock (?7); resume plan has no mode/wantsReply/provider/model but has
|
|
741
709
|
# expectedSocketPath/observeTimeoutMs/releaseWhen; an invalid gid throws before
|
|
742
710
|
# any lookup (F2-P1). Pure, no IO, no API.
|
|
743
|
-
|
|
711
|
+
run_ts scripts/check-entwurf-v2-decider.ts
|
|
744
712
|
}
|
|
745
713
|
|
|
746
714
|
check_entwurf_v2_matrix() {
|
|
@@ -754,7 +722,7 @@ check_entwurf_v2_matrix() {
|
|
|
754
722
|
# FAILS if any transport / lock class / pre-probe reject is missing — a dropped
|
|
755
723
|
# decider cell cannot pass silently. Thin coverage, NOT a decider re-impl; surface
|
|
756
724
|
# parity stays in check-entwurf-v2-surface. Pure, no IO, no API.
|
|
757
|
-
|
|
725
|
+
run_ts scripts/check-entwurf-v2-matrix.ts
|
|
758
726
|
}
|
|
759
727
|
|
|
760
728
|
check_entwurf_v2_release() {
|
|
@@ -766,7 +734,7 @@ check_entwurf_v2_release() {
|
|
|
766
734
|
# release on the FIRST observed transition (socket-alive ∨ child-exited any code)
|
|
767
735
|
# or a failed start; socket↔exit race idempotent (single release either order);
|
|
768
736
|
# decideReleasePolicy enforces the lock-nullness invariant (?7). Pure, no IO.
|
|
769
|
-
|
|
737
|
+
run_ts scripts/check-entwurf-v2-release.ts
|
|
770
738
|
}
|
|
771
739
|
|
|
772
740
|
check_entwurf_v2_send() {
|
|
@@ -778,7 +746,7 @@ check_entwurf_v2_send() {
|
|
|
778
746
|
# indeterminate->failed+rethrow with deadFallback+mailbox NEVER called (no
|
|
779
747
|
# double-delivery on an alive-but-stalled socket). Release fires exactly once per
|
|
780
748
|
# send-final; a releaseLock throw never masks the send failure (5b). IO-via-dep.
|
|
781
|
-
|
|
749
|
+
run_ts scripts/check-entwurf-v2-send.ts
|
|
782
750
|
}
|
|
783
751
|
|
|
784
752
|
check_entwurf_v2_send_fallback() {
|
|
@@ -791,7 +759,7 @@ check_entwurf_v2_send_fallback() {
|
|
|
791
759
|
# / bad-target + address-conflict->reject pre-probe. Mis-wire (plan/lock gid) fails loud
|
|
792
760
|
# before IO; inspect/probe throws PROPAGATE (the hand owns failed+release); the resolver
|
|
793
761
|
# has NO release seam; every execute plan keeps the held gid and is never spawn-bg.
|
|
794
|
-
|
|
762
|
+
run_ts scripts/check-entwurf-v2-send-fallback.ts
|
|
795
763
|
}
|
|
796
764
|
|
|
797
765
|
check_entwurf_v2_mailbox() {
|
|
@@ -808,7 +776,19 @@ check_entwurf_v2_mailbox() {
|
|
|
808
776
|
# every access throws still resolves). Source guard: the lib code has NO release seam
|
|
809
777
|
# and NO routing seam (no releaseLock / inspect / probe / resolve) — a lock leak or
|
|
810
778
|
# re-route is structurally impossible.
|
|
811
|
-
|
|
779
|
+
run_ts scripts/check-entwurf-v2-mailbox.ts
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
check_entwurf_v2_native_push() {
|
|
783
|
+
# Deterministic gate for 봉인 3/4: the native-push SEND hand (deliverViaNativePush +
|
|
784
|
+
# makeNativePushSend), the executor half of the native-push rail — where the 1-shot retry
|
|
785
|
+
# lives (moved out of the adapter leaf). Proves over a fake adapter (no agy/socket): success
|
|
786
|
+
# first try -> {retried:false}, ONE send over the planted route, ZERO re-probe; fail ->
|
|
787
|
+
# re-probe alive -> re-send success -> {retried:true}, TWO sends, the 2nd over the RE-
|
|
788
|
+
# DISCOVERED route; re-send FAIL -> throws (no 3rd attempt); re-probe dead/indeterminate ->
|
|
789
|
+
# throws (not retried), NO second send. makeNativePushSend resolves the adapter from
|
|
790
|
+
# plan.backend and IGNORES the lock (lock-free rail).
|
|
791
|
+
run_ts scripts/check-entwurf-v2-native-push.ts
|
|
812
792
|
}
|
|
813
793
|
|
|
814
794
|
check_entwurf_v2_runner() {
|
|
@@ -822,7 +802,7 @@ check_entwurf_v2_runner() {
|
|
|
822
802
|
# SendDeliveredReleaseFailedError -> execution-failed{finalizedOutcome, releaseFailed,
|
|
823
803
|
# retrySafe:false}; a plain hand throw -> execution-failed{retrySafe:false} with no
|
|
824
804
|
# finalizedOutcome. Exactly one hand runs per execute.
|
|
825
|
-
|
|
805
|
+
run_ts scripts/check-entwurf-v2-runner.ts
|
|
826
806
|
}
|
|
827
807
|
|
|
828
808
|
check_entwurf_v2_surface() {
|
|
@@ -833,7 +813,7 @@ check_entwurf_v2_surface() {
|
|
|
833
813
|
# lock-retained, N1 delivered-but-dirty) / surface ctx-free source guard / entwurf-control
|
|
834
814
|
# registers entwurf_v2 + reaches the fence via a NON-LITERAL dynamic import (no static fence
|
|
835
815
|
# import → TS5097 stays closed) + decorates sender origin:pi-session/replyable:true.
|
|
836
|
-
|
|
816
|
+
run_ts scripts/check-entwurf-v2-surface.ts
|
|
837
817
|
}
|
|
838
818
|
|
|
839
819
|
check_entwurf_bridge_boot() {
|
|
@@ -844,7 +824,7 @@ check_entwurf_bridge_boot() {
|
|
|
844
824
|
# registered on the runtime surface with its schema (G1b). tools/list only → no tools/call,
|
|
845
825
|
# no lock/fs side effect, no auth → safe in pnpm check. Broad protocol/negative suite stays
|
|
846
826
|
# in check-bridge/test.sh (D1=A안).
|
|
847
|
-
|
|
827
|
+
run_ts scripts/check-entwurf-bridge-boot.ts
|
|
848
828
|
}
|
|
849
829
|
|
|
850
830
|
check_entwurf_bridge_pi_free() {
|
|
@@ -855,7 +835,7 @@ check_entwurf_bridge_pi_free() {
|
|
|
855
835
|
# value-imports @earendil-works/pi-*. Type-only imports and dynamic `await import()`
|
|
856
836
|
# (the intended lazy preflight boundary) are excluded — the runtime boot smoke is the
|
|
857
837
|
# final authority that peers/self/list/mailbox-deliver come up pi-free.
|
|
858
|
-
|
|
838
|
+
run_ts scripts/check-entwurf-bridge-pi-free.ts
|
|
859
839
|
}
|
|
860
840
|
|
|
861
841
|
check_entwurf_v2_production() {
|
|
@@ -866,7 +846,7 @@ check_entwurf_v2_production() {
|
|
|
866
846
|
# lockDir / QB3 the spawn watcher releases via the SHARED lockDir release (not the spawn
|
|
867
847
|
# factory default) / the mailbox hand enqueues onto the wired dirs / a dead control send
|
|
868
848
|
# re-resolves to the SAME sendViaMailbox instance on the SAME dirs (Q3+Q5 no drift).
|
|
869
|
-
|
|
849
|
+
run_ts scripts/check-entwurf-v2-production.ts
|
|
870
850
|
}
|
|
871
851
|
|
|
872
852
|
check_entwurf_control_rpc() {
|
|
@@ -877,7 +857,7 @@ check_entwurf_control_rpc() {
|
|
|
877
857
|
# sendRpcCommand from the lib and no longer defines its own / real short unix-socket round-trip
|
|
878
858
|
# (write command -> matched {type:response,command,success:true} -> resolve) / close-before-
|
|
879
859
|
# response rejects 'connection closed before response'. net.Server only, no model/pi process.
|
|
880
|
-
|
|
860
|
+
run_ts scripts/check-entwurf-control-rpc.ts
|
|
881
861
|
}
|
|
882
862
|
|
|
883
863
|
check_entwurf_v2_spawn() {
|
|
@@ -891,7 +871,7 @@ check_entwurf_v2_spawn() {
|
|
|
891
871
|
# obtainable (grace elapses, or a post-spawn watch dep throws and the exit can't be
|
|
892
872
|
# observed) -> lock-retained fail-closed (released:false, pid/socket/lockPath surfaced) —
|
|
893
873
|
# there is NO direct-release hatch; deps.releaseLock is reached ONLY via reduceRelease.
|
|
894
|
-
|
|
874
|
+
run_ts scripts/check-entwurf-v2-spawn.ts
|
|
895
875
|
}
|
|
896
876
|
|
|
897
877
|
check_entwurf_resume_args() {
|
|
@@ -904,7 +884,7 @@ check_entwurf_resume_args() {
|
|
|
904
884
|
# and the prompt-as-turn positional (`-p` NOT dropped in v2); explicitExtensionArgs
|
|
905
885
|
# preserved exactly once (provider-resolution footgun #29); v2 includes plan.launchArgs
|
|
906
886
|
# (--approve) before the prompt; null provider emits no --provider; no cross-contamination.
|
|
907
|
-
|
|
887
|
+
run_ts scripts/check-entwurf-resume-args.ts
|
|
908
888
|
}
|
|
909
889
|
|
|
910
890
|
check_entwurf_v2_spawn_production() {
|
|
@@ -918,7 +898,7 @@ check_entwurf_v2_spawn_production() {
|
|
|
918
898
|
# (symlink) rejects without connecting, dead→wait→alive, abort clears the sleep. awaitChildExit
|
|
919
899
|
# resolves the code + removes the listener on abort. awaitTimeout schedules + abort-clears.
|
|
920
900
|
# killChild=SIGTERM; releaseLock delegates; a proc-less child fails loud (mis-wire).
|
|
921
|
-
|
|
901
|
+
run_ts scripts/check-entwurf-v2-spawn-production.ts
|
|
922
902
|
}
|
|
923
903
|
|
|
924
904
|
|
|
@@ -934,7 +914,7 @@ smoke_entwurf_v2_spawn_live() {
|
|
|
934
914
|
echo "[smoke-entwurf-v2-spawn-live] skipped — set LIVE=1 to run (spawns real children + opens a real unix socket)."
|
|
935
915
|
return 0
|
|
936
916
|
fi
|
|
937
|
-
|
|
917
|
+
run_ts scripts/smoke-entwurf-v2-spawn-live.ts
|
|
938
918
|
}
|
|
939
919
|
|
|
940
920
|
smoke_acp_socket_citizen_live() {
|
|
@@ -947,7 +927,7 @@ smoke_acp_socket_citizen_live() {
|
|
|
947
927
|
# citizenship, never a backend turn (that is S2). Honest skip when LIVE!=1.
|
|
948
928
|
# Model override: ENTWURF_S1_MODEL (default claude-opus-4-8).
|
|
949
929
|
# LIVE=1 ./run.sh smoke-acp-socket-citizen-live
|
|
950
|
-
|
|
930
|
+
run_ts scripts/smoke-acp-socket-citizen-live.ts
|
|
951
931
|
}
|
|
952
932
|
|
|
953
933
|
smoke_acp_raw_turn_live() {
|
|
@@ -961,7 +941,7 @@ smoke_acp_raw_turn_live() {
|
|
|
961
941
|
# fails acceptance unless ENTWURF_ACP_RAW_TURN_ALLOW_PATH_FALLBACK=1, debug).
|
|
962
942
|
# Model override: ENTWURF_ACP_RAW_TURN_MODEL (default claude-sonnet-5).
|
|
963
943
|
# LIVE=1 ./run.sh smoke-acp-raw-turn-live
|
|
964
|
-
|
|
944
|
+
run_ts scripts/smoke-acp-raw-turn-live.ts
|
|
965
945
|
}
|
|
966
946
|
|
|
967
947
|
smoke_acp_overlay_live() {
|
|
@@ -979,7 +959,7 @@ smoke_acp_overlay_live() {
|
|
|
979
959
|
# fallback fails acceptance unless ENTWURF_ACP_OVERLAY_ALLOW_PATH_FALLBACK=1).
|
|
980
960
|
# Model override: ENTWURF_ACP_OVERLAY_MODEL (default claude-sonnet-5).
|
|
981
961
|
# LIVE=1 ./run.sh smoke-acp-overlay-live
|
|
982
|
-
|
|
962
|
+
run_ts scripts/smoke-acp-overlay-live.ts
|
|
983
963
|
}
|
|
984
964
|
|
|
985
965
|
smoke_acp_memory_containment_live() {
|
|
@@ -994,7 +974,7 @@ smoke_acp_memory_containment_live() {
|
|
|
994
974
|
# fallback fails acceptance unless ENTWURF_ACP_MEMORY_ALLOW_PATH_FALLBACK=1).
|
|
995
975
|
# Model override: ENTWURF_ACP_MEMORY_MODEL (default claude-sonnet-5).
|
|
996
976
|
# LIVE=1 ./run.sh smoke-acp-memory-containment-live
|
|
997
|
-
|
|
977
|
+
run_ts scripts/smoke-acp-memory-containment-live.ts
|
|
998
978
|
}
|
|
999
979
|
|
|
1000
980
|
smoke_acp_provider_live() {
|
|
@@ -1009,7 +989,7 @@ smoke_acp_provider_live() {
|
|
|
1009
989
|
# event-mapper gate owns the tool→notice contract.
|
|
1010
990
|
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-5).
|
|
1011
991
|
# LIVE=1 ./run.sh smoke-acp-provider-live
|
|
1012
|
-
|
|
992
|
+
run_ts scripts/smoke-acp-provider-live.ts
|
|
1013
993
|
}
|
|
1014
994
|
|
|
1015
995
|
smoke_acp_session_reuse_live() {
|
|
@@ -1023,7 +1003,7 @@ smoke_acp_session_reuse_live() {
|
|
|
1023
1003
|
# smoke-acp-provider-live.
|
|
1024
1004
|
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-5).
|
|
1025
1005
|
# LIVE=1 ./run.sh smoke-acp-session-reuse-live
|
|
1026
|
-
|
|
1006
|
+
run_ts scripts/smoke-acp-session-reuse-live.ts
|
|
1027
1007
|
}
|
|
1028
1008
|
|
|
1029
1009
|
smoke_acp_carrier_augment_live() {
|
|
@@ -1035,7 +1015,7 @@ smoke_acp_carrier_augment_live() {
|
|
|
1035
1015
|
# check via SMOKE_ACP_CARRIER_PRESENT=1 (non-blocking).
|
|
1036
1016
|
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-5).
|
|
1037
1017
|
# LIVE=1 ./run.sh smoke-acp-carrier-augment-live
|
|
1038
|
-
|
|
1018
|
+
run_ts scripts/smoke-acp-carrier-augment-live.ts
|
|
1039
1019
|
}
|
|
1040
1020
|
|
|
1041
1021
|
smoke_acp_mcp_live() {
|
|
@@ -1048,7 +1028,7 @@ smoke_acp_mcp_live() {
|
|
|
1048
1028
|
# fix). Isolated probe (not entwurf-bridge) so a failure does not blur into
|
|
1049
1029
|
# identity/env wiring. Model override: ENTWURF_ACP_PROVIDER_MODEL.
|
|
1050
1030
|
# LIVE=1 ./run.sh smoke-acp-mcp-live
|
|
1051
|
-
|
|
1031
|
+
run_ts scripts/smoke-acp-mcp-live.ts
|
|
1052
1032
|
}
|
|
1053
1033
|
|
|
1054
1034
|
smoke_acp_skill_live() {
|
|
@@ -1060,7 +1040,7 @@ smoke_acp_skill_live() {
|
|
|
1060
1040
|
# the Skill/Skill(*) auto-add reach the live session (the other half of the GLG
|
|
1061
1041
|
# baseline). Model override: ENTWURF_ACP_PROVIDER_MODEL.
|
|
1062
1042
|
# LIVE=1 ./run.sh smoke-acp-skill-live
|
|
1063
|
-
|
|
1043
|
+
run_ts scripts/smoke-acp-skill-live.ts
|
|
1064
1044
|
}
|
|
1065
1045
|
|
|
1066
1046
|
smoke_acp_bundled_mcp_live() {
|
|
@@ -1076,7 +1056,7 @@ smoke_acp_bundled_mcp_live() {
|
|
|
1076
1056
|
# diagnostic backlog, not the 0.11.0 release circuit). Model override:
|
|
1077
1057
|
# ENTWURF_ACP_PROVIDER_MODEL.
|
|
1078
1058
|
# LIVE=1 ./run.sh smoke-acp-bundled-mcp-live
|
|
1079
|
-
|
|
1059
|
+
run_ts scripts/smoke-acp-bundled-mcp-live.ts
|
|
1080
1060
|
}
|
|
1081
1061
|
|
|
1082
1062
|
smoke_acp_rgg_live() {
|
|
@@ -1113,7 +1093,7 @@ smoke_entwurf_v2_matrix_live() {
|
|
|
1113
1093
|
echo "[smoke-entwurf-v2-matrix-live] skipped — set LIVE=1 to run (spawns a real pi --entwurf-control + opens a real socket)."
|
|
1114
1094
|
return 0
|
|
1115
1095
|
fi
|
|
1116
|
-
|
|
1096
|
+
run_ts scripts/smoke-entwurf-v2-matrix-live.ts
|
|
1117
1097
|
}
|
|
1118
1098
|
|
|
1119
1099
|
smoke_entwurf_v2_spawn_resume_live() {
|
|
@@ -1135,7 +1115,7 @@ smoke_entwurf_v2_spawn_resume_live() {
|
|
|
1135
1115
|
echo "[smoke-entwurf-v2-spawn-resume-live] skipped — set LIVE=1 to run (spawns a real pi resume child + opens a real socket)."
|
|
1136
1116
|
return 0
|
|
1137
1117
|
fi
|
|
1138
|
-
|
|
1118
|
+
run_ts scripts/smoke-entwurf-v2-spawn-resume-live.ts
|
|
1139
1119
|
}
|
|
1140
1120
|
|
|
1141
1121
|
check_entwurf_facts() {
|
|
@@ -1147,7 +1127,7 @@ check_entwurf_facts() {
|
|
|
1147
1127
|
# (no proof ≠ dead). facts-only keyset: identity facts + liveness, NO
|
|
1148
1128
|
# verb-routing (resumable/sendable/transport/dispatch/action) and NO
|
|
1149
1129
|
# transcriptPath (동결결정 10). Pure, no IO, no API.
|
|
1150
|
-
|
|
1130
|
+
run_ts scripts/check-entwurf-facts.ts
|
|
1151
1131
|
}
|
|
1152
1132
|
|
|
1153
1133
|
check_socket_discovery() {
|
|
@@ -1159,7 +1139,7 @@ check_socket_discovery() {
|
|
|
1159
1139
|
# indeterminate (F3), never folded to dead by an alive-only listing. Dir
|
|
1160
1140
|
# hygiene (non-.sock / malformed names ignored), dedup, missing-dir, sort, and
|
|
1161
1141
|
# an end-to-end scanSocketProbes→resolveFactList. readdir/probe injected, no IO.
|
|
1162
|
-
|
|
1142
|
+
run_ts scripts/check-socket-discovery.ts
|
|
1163
1143
|
}
|
|
1164
1144
|
|
|
1165
1145
|
check_meta_listing() {
|
|
@@ -1170,7 +1150,7 @@ check_meta_listing() {
|
|
|
1170
1150
|
# becomes an explicit error carrying ONLY {filename, message}, verbatim (a
|
|
1171
1151
|
# salvaged gid string as a fact = synthetic backdoor). mode strict throws on
|
|
1172
1152
|
# any error, collect returns partial. entries/readRecord injected, no IO.
|
|
1173
|
-
|
|
1153
|
+
run_ts scripts/check-meta-listing.ts
|
|
1174
1154
|
}
|
|
1175
1155
|
|
|
1176
1156
|
check_entwurf_fact_provider() {
|
|
@@ -1182,7 +1162,7 @@ check_entwurf_fact_provider() {
|
|
|
1182
1162
|
# survives; impossible wiring invariant (resolveFactList duplicate/unprobed) →
|
|
1183
1163
|
# throw, never swallowed. A collision quarantines BOTH the PeerFact and the
|
|
1184
1164
|
# socket (gid is the universal address). meta + socket deps injected, no IO.
|
|
1185
|
-
|
|
1165
|
+
run_ts scripts/check-entwurf-fact-provider.ts
|
|
1186
1166
|
}
|
|
1187
1167
|
|
|
1188
1168
|
check_entwurf_peers_surface() {
|
|
@@ -1196,7 +1176,7 @@ check_entwurf_peers_surface() {
|
|
|
1196
1176
|
# diagnostics in both surfaces; empty → "(none)"; unsupported shown; enrich null
|
|
1197
1177
|
# → "(not enriched)". WIRING guard: bridge calls listEntwurfFacts+renderEntwurfPeers,
|
|
1198
1178
|
# getLiveSessions gone. Facts fabricated, no IO (only static source read).
|
|
1199
|
-
|
|
1179
|
+
run_ts scripts/check-entwurf-peers-surface.ts
|
|
1200
1180
|
}
|
|
1201
1181
|
|
|
1202
1182
|
|
|
@@ -1213,7 +1193,7 @@ check_entwurf_self_address() {
|
|
|
1213
1193
|
# probes the socket, and entwurf_self renders alive vs expected (no path lie).
|
|
1214
1194
|
# Slice boundary: meta watchArmed is wired from the slice-2 presence marker; do NOT
|
|
1215
1195
|
# claim slice 1 green standalone (1+2 close in the same release block).
|
|
1216
|
-
|
|
1196
|
+
run_ts scripts/check-entwurf-self-address.ts
|
|
1217
1197
|
}
|
|
1218
1198
|
|
|
1219
1199
|
check_entwurf_deliverability() {
|
|
@@ -1225,7 +1205,7 @@ check_entwurf_deliverability() {
|
|
|
1225
1205
|
# (pi) refused even when active (SE-1, no mailbox drain), self-fetch + dead-owner/unarmed
|
|
1226
1206
|
# refused (SE-2, would rot); WIRING that the self-addressability predicate shares the
|
|
1227
1207
|
# SAME active-receiver atom (one source of truth). Pure, no IO.
|
|
1228
|
-
|
|
1208
|
+
run_ts scripts/check-entwurf-deliverability.ts
|
|
1229
1209
|
}
|
|
1230
1210
|
|
|
1231
1211
|
check_entwurf_mailbox_guard() {
|
|
@@ -1236,7 +1216,47 @@ check_entwurf_mailbox_guard() {
|
|
|
1236
1216
|
# one calls it exactly once; TMPDIR SNAPSHOT with the real enqueueMetaMessage — a refused
|
|
1237
1217
|
# send leaves the mailbox tree byte-identical (file list + content hash, not just mtime),
|
|
1238
1218
|
# an accepted send writes exactly one .msg; plus fact gathering from record/capability/marker.
|
|
1239
|
-
|
|
1219
|
+
run_ts scripts/check-entwurf-mailbox-guard.ts
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
check_native_push_adapter() {
|
|
1223
|
+
# Deterministic gate for the native-push adapter LEAF (봉인 3/8). Drives
|
|
1224
|
+
# createAntigravityAdapter with a FAKE runner (no real agy/ss/pgrep). Asserts: FULL pid
|
|
1225
|
+
# scan (only the 2nd host pid serves the conv → probe still finds the route; raw-agy-send
|
|
1226
|
+
# head -1 corrected); dead (no host) vs indeterminate (host alive, no LS port served the
|
|
1227
|
+
# conv, never coerced to dead); VOLATILE route / no cache (a repeated probe re-discovers a
|
|
1228
|
+
# CHANGED route); send argv === [binary,agentapi,send-message,conv,body] with
|
|
1229
|
+
# ANTIGRAVITY_LS_ADDRESS env, non-zero exit THROWS; NO retry in the adapter (single send,
|
|
1230
|
+
# no re-probe — retry is the executor hand's job, step ⑥); resolveNativePushAdapter fail-fast.
|
|
1231
|
+
run_ts scripts/check-native-push-adapter.ts
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
check_native_push_register() {
|
|
1235
|
+
# Deterministic gate for 봉인 5: registerNativeConversation (the core of the
|
|
1236
|
+
# entwurf_register_native MCP tool). Drives it with a FAKE adapter + an ISOLATED mkdtemp
|
|
1237
|
+
# store (never the real ~/.pi). Asserts: live probe -> CREATE (record carries backend/
|
|
1238
|
+
# nativeSessionId/caller-cwd); re-register -> ATTACH (SAME garden id, cwd refreshed, ONE
|
|
1239
|
+
# record, no duplicate mint); dead/indeterminate probe -> REFUSE (throws, NO record written);
|
|
1240
|
+
# RECEIVER-MARKER ABSTINENCE (보정①) — the register source references no receiver-marker
|
|
1241
|
+
# writer (writeMetaReceiverMarker / armProvenance / META_RECEIVER_ARM_PROVENANCES).
|
|
1242
|
+
run_ts scripts/check-native-push-register.ts
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
check_agy_sender_identity() {
|
|
1246
|
+
# Deterministic gate for the #46 sender-identity lane — WHO is calling the bridge.
|
|
1247
|
+
# A birthed agy conversation could already CALL entwurf_v2 for real, yet its message
|
|
1248
|
+
# landed as external-mcp/unknown-host (non-replyable): the hook wrote only the
|
|
1249
|
+
# meta-record, and the bridge's resolver looked markers up under `claude-code` alone.
|
|
1250
|
+
# Behavioral, not source-regex: the real hook runs as a child process (so the marker's
|
|
1251
|
+
# ownerPid is the gate's own pid — the same parent-pid join production performs), and
|
|
1252
|
+
# the resolver runs against isolated marker/record stores.
|
|
1253
|
+
# Rows: hook writes an antigravity marker keyed by its PARENT pid; an upsert failure
|
|
1254
|
+
# writes NO marker (record authority first); resolver 0→null, 1→identity on EITHER
|
|
1255
|
+
# backend, no-record/drifted marker→null, two distinct live identities on one owner pid
|
|
1256
|
+
# →THROW (never guess, never downgrade to anonymous), two markers naming the SAME
|
|
1257
|
+
# identity→not a conflict; antigravity is native-push so its replyable comes from the
|
|
1258
|
+
# adapter probe, never from a mailbox watch it can never arm (보정①).
|
|
1259
|
+
run_ts scripts/check-agy-sender-identity.ts
|
|
1240
1260
|
}
|
|
1241
1261
|
|
|
1242
1262
|
|
|
@@ -1251,7 +1271,7 @@ check_package_source_routing() {
|
|
|
1251
1271
|
# plus self-root fallback and the resume unresolvedAcpIntent signal. Isolated
|
|
1252
1272
|
# via a temp PI_CODING_AGENT_DIR — the real ~/.pi/agent is never touched. No
|
|
1253
1273
|
# backend, no spawn, no API cost.
|
|
1254
|
-
|
|
1274
|
+
run_ts scripts/check-package-source-routing.ts
|
|
1255
1275
|
}
|
|
1256
1276
|
|
|
1257
1277
|
|
|
@@ -1267,7 +1287,7 @@ smoke_session_id_name() {
|
|
|
1267
1287
|
fail "[smoke-session-id-name] pi binary not on PATH — cannot run live substrate proof"
|
|
1268
1288
|
return 1
|
|
1269
1289
|
fi
|
|
1270
|
-
|
|
1290
|
+
run_ts scripts/smoke-session-id-name.ts || {
|
|
1271
1291
|
fail "[smoke-session-id-name] live substrate smoke failed"
|
|
1272
1292
|
return 1
|
|
1273
1293
|
}
|
|
@@ -1608,7 +1628,7 @@ check_pi_preflight() {
|
|
|
1608
1628
|
# decision 8 precedence (saved false > saved true > prefix > no-inputs >
|
|
1609
1629
|
# fail-fast) and decision 7's separator-boundary prefix against pi's own
|
|
1610
1630
|
# ProjectTrustStore in a temp agentDir. Deterministic, no network/backend.
|
|
1611
|
-
|
|
1631
|
+
run_ts scripts/check-pi-preflight.ts
|
|
1612
1632
|
}
|
|
1613
1633
|
|
|
1614
1634
|
|
|
@@ -1663,7 +1683,7 @@ check_acp_provider_surface() {
|
|
|
1663
1683
|
# sentinel shape, and a FAIL-LOUD streamSimple (calling it throws — no native
|
|
1664
1684
|
# fallback, no empty-but-successful stream). Pure, no pi runtime, no API.
|
|
1665
1685
|
section "ACP provider surface (S0 loader/fence)"
|
|
1666
|
-
|
|
1686
|
+
run_ts scripts/check-acp-provider-surface.ts
|
|
1667
1687
|
}
|
|
1668
1688
|
|
|
1669
1689
|
check_acp_sdk_surface() {
|
|
@@ -1675,7 +1695,7 @@ check_acp_sdk_surface() {
|
|
|
1675
1695
|
# turn needs (silent-rename gate), and forbids any source-level anthropic SDK
|
|
1676
1696
|
# import / API-client use (the anthropic dep is a peer-pin ONLY).
|
|
1677
1697
|
section "ACP SDK surface (S2a dep pin + peer-resolution + no-client-use)"
|
|
1678
|
-
|
|
1698
|
+
run_ts scripts/check-acp-sdk-surface.ts
|
|
1679
1699
|
}
|
|
1680
1700
|
|
|
1681
1701
|
check_acp_overlay() {
|
|
@@ -1688,7 +1708,7 @@ check_acp_overlay() {
|
|
|
1688
1708
|
# stale symlinks cleaned; binary-owned files preserved; CLAUDE_CONFIG_DIR
|
|
1689
1709
|
# launch-env planted; idempotent. Pure, no live model.
|
|
1690
1710
|
section "ACP overlay (S2b claude-config-overlay)"
|
|
1691
|
-
|
|
1711
|
+
run_ts scripts/check-acp-overlay.ts
|
|
1692
1712
|
}
|
|
1693
1713
|
|
|
1694
1714
|
check_acp_tool_surface() {
|
|
@@ -1699,7 +1719,7 @@ check_acp_tool_surface() {
|
|
|
1699
1719
|
# extraArgs/plugins) + the S2b billing-carrier guard (no _meta.systemPrompt
|
|
1700
1720
|
# unless a caller supplies one). Pure preflight — NOT a backend wire read.
|
|
1701
1721
|
section "ACP tool surface (S2b exclude-tools preflight + session meta)"
|
|
1702
|
-
|
|
1722
|
+
run_ts scripts/check-acp-tool-surface.ts
|
|
1703
1723
|
}
|
|
1704
1724
|
|
|
1705
1725
|
check_acp_event_mapper() {
|
|
@@ -1711,7 +1731,7 @@ check_acp_event_mapper() {
|
|
|
1711
1731
|
# context→ACP-prompt transcript passthrough (excludes systemPrompt/thinking,
|
|
1712
1732
|
# single text block). Pure, no live backend.
|
|
1713
1733
|
section "ACP event mapper (S2c notification→stream + context)"
|
|
1714
|
-
|
|
1734
|
+
run_ts scripts/check-acp-event-mapper.ts
|
|
1715
1735
|
}
|
|
1716
1736
|
|
|
1717
1737
|
check_acp_prompt_builder() {
|
|
@@ -1722,7 +1742,7 @@ check_acp_prompt_builder() {
|
|
|
1722
1742
|
# excluded so a reuse session is not re-injected its own history). Pure, no
|
|
1723
1743
|
# session store yet — locks the builder before S2d wires the reuse paths.
|
|
1724
1744
|
section "ACP prompt builder (S2d bootstrapPath prompt scope)"
|
|
1725
|
-
|
|
1745
|
+
run_ts scripts/check-acp-prompt-builder.ts
|
|
1726
1746
|
}
|
|
1727
1747
|
|
|
1728
1748
|
check_acp_config() {
|
|
@@ -1735,7 +1755,7 @@ check_acp_config() {
|
|
|
1735
1755
|
# headers, and envelope enrich (PI_SESSION_ID/PI_AGENT_ID into entwurf-bridge
|
|
1736
1756
|
# only, stale filtered, post-hash). Pure + temp-dir settings I/O, no child/spawn.
|
|
1737
1757
|
section "ACP provider config (S2g operator mcpServers/skillPlugins/tools passthrough)"
|
|
1738
|
-
|
|
1758
|
+
run_ts scripts/check-acp-config.ts
|
|
1739
1759
|
}
|
|
1740
1760
|
|
|
1741
1761
|
check_acp_session_store() {
|
|
@@ -1746,7 +1766,7 @@ check_acp_session_store() {
|
|
|
1746
1766
|
# (turn-scoped/-p one-shot is ALWAYS new — no in-memory reuse, no persisted
|
|
1747
1767
|
# resume/load in the first cut). Pure + temp-dir record I/O, no child/spawn.
|
|
1748
1768
|
section "ACP session store (S2d-1b-1 signature/compat/bootstrap decision)"
|
|
1749
|
-
|
|
1769
|
+
run_ts scripts/check-acp-session-store.ts
|
|
1750
1770
|
}
|
|
1751
1771
|
|
|
1752
1772
|
check_acp_backend_preflight() {
|
|
@@ -1757,7 +1777,7 @@ check_acp_backend_preflight() {
|
|
|
1757
1777
|
# assertExcludeToolsHonored is wired into the live provider path, not just the
|
|
1758
1778
|
# pure gate. No backend launched (preflight throws first). Pure.
|
|
1759
1779
|
section "ACP backend preflight (S2c runtime exclude-tools wiring)"
|
|
1760
|
-
|
|
1780
|
+
run_ts scripts/check-acp-backend-preflight.ts
|
|
1761
1781
|
}
|
|
1762
1782
|
|
|
1763
1783
|
check_acp_session_reuse() {
|
|
@@ -1770,7 +1790,7 @@ check_acp_session_reuse() {
|
|
|
1770
1790
|
# never torn down between turns, and source-locks buildAcpPrompt wiring +
|
|
1771
1791
|
# single-site applyAcpSessionUpdate via the router. No real child launched.
|
|
1772
1792
|
section "ACP session reuse (S2d-1b-2b delta-only capture + mutable routing)"
|
|
1773
|
-
|
|
1793
|
+
run_ts scripts/check-acp-session-reuse.ts
|
|
1774
1794
|
}
|
|
1775
1795
|
|
|
1776
1796
|
check_acp_carrier_augment() {
|
|
@@ -1782,7 +1802,7 @@ check_acp_carrier_augment() {
|
|
|
1782
1802
|
# so it never enters contextMessageSignatures — with entwurf cwd/AGENTS.md
|
|
1783
1803
|
# de-dup. Pure + temp-dir fs, no spawn.
|
|
1784
1804
|
section "ACP carrier + augment (S2d-1c engraving + first-user augment)"
|
|
1785
|
-
|
|
1805
|
+
run_ts scripts/check-acp-carrier-augment.ts
|
|
1786
1806
|
}
|
|
1787
1807
|
|
|
1788
1808
|
check_pack() {
|
|
@@ -1808,7 +1828,11 @@ check_pack() {
|
|
|
1808
1828
|
# npm's own lifecycle banner stay off stdout; otherwise they pollute the --json
|
|
1809
1829
|
# payload this parses. prepack runs on dry-run too, which is how dist lands in
|
|
1810
1830
|
# this gate's file list.
|
|
1811
|
-
|
|
1831
|
+
# with-dist-lock wraps the WHOLE pack (prepack build-bridge emit + npm's
|
|
1832
|
+
# post-build dist read) so a concurrent pack/build can't `rm -rf dist` mid-read
|
|
1833
|
+
# (the 2026-07-03 phantom "dist missing" race). The nested prepack build-bridge
|
|
1834
|
+
# is reentrant via ENTWURF_BUILD_LOCK_HELD.
|
|
1835
|
+
json=$(cd "$REPO_DIR" && bash scripts/with-dist-lock.sh npm pack --dry-run --json --silent 2>/dev/null) || {
|
|
1812
1836
|
fail "[check-pack] npm pack --dry-run failed"
|
|
1813
1837
|
return 1
|
|
1814
1838
|
}
|
|
@@ -1867,6 +1891,14 @@ check_pack() {
|
|
|
1867
1891
|
# doctor.sh runs this prebuilt JS when installed under node_modules (strip-types
|
|
1868
1892
|
# refuses the .ts there), same boundary start.sh crosses. build-bridge emits it.
|
|
1869
1893
|
"mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
|
|
1894
|
+
# 0.12.7 — node_modules-safe agy PreInvocation hook. The stable npm bin
|
|
1895
|
+
# dispatches here because Node refuses raw .ts below node_modules.
|
|
1896
|
+
"mcp/entwurf-bridge/dist/scripts/agy-imprint.js"
|
|
1897
|
+
# 0.12.7 — the three OPERATOR commands run.sh dispatches. Installed, REPO_DIR is
|
|
1898
|
+
# under node_modules, so run_ts must find a compiled twin or the command is dead.
|
|
1899
|
+
"mcp/entwurf-bridge/dist/scripts/doctor-pi-provider.js"
|
|
1900
|
+
"mcp/entwurf-bridge/dist/scripts/new-session-id.js"
|
|
1901
|
+
"mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js"
|
|
1870
1902
|
# 0.12.5 — the node_modules-safe plugin hook + its lib. install-meta-bridge copies
|
|
1871
1903
|
# these compiled JS into the assembled plugin when installed (raw .ts can't
|
|
1872
1904
|
# strip-types under node_modules). meta-session.js is shared with the store-doctor
|
|
@@ -1904,6 +1936,13 @@ check_pack() {
|
|
|
1904
1936
|
'\.tmp-verify/'
|
|
1905
1937
|
'\.agent-(reports|shell)/'
|
|
1906
1938
|
'pi/meta-bridge/\.assembled/'
|
|
1939
|
+
# Python bytecode residue — `scripts/` ships whole via the files allowlist,
|
|
1940
|
+
# which BYPASSES .gitignore/.npmignore for its contents, so a `pnpm check`
|
|
1941
|
+
# run's generated scripts/__pycache__/*.pyc rode into the 0.12.6 tarball. The
|
|
1942
|
+
# files-array `!**/__pycache__` / `!**/*.pyc` negations exclude it; this is the
|
|
1943
|
+
# tripwire that fails loud if that negation is ever dropped (결합 규칙).
|
|
1944
|
+
'__pycache__'
|
|
1945
|
+
'\.pyc$'
|
|
1907
1946
|
)
|
|
1908
1947
|
|
|
1909
1948
|
local pass=1 f pat hit
|
|
@@ -1936,7 +1975,7 @@ check_pack() {
|
|
|
1936
1975
|
return 1
|
|
1937
1976
|
}
|
|
1938
1977
|
|
|
1939
|
-
|
|
1978
|
+
_check_pack_install_impl() {
|
|
1940
1979
|
# Heavy publish gate. Runs the remaining three checks in #13's
|
|
1941
1980
|
# publish checklist that check_pack (dry-run only) does not cover:
|
|
1942
1981
|
#
|
|
@@ -1965,8 +2004,15 @@ check_pack_install() {
|
|
|
1965
2004
|
# that lands as `junghanacs-entwurf-<version>.tgz`. Hardcoded against
|
|
1966
2005
|
# the scope above so a name change cannot silently slide past this gate.
|
|
1967
2006
|
tgz_name="junghanacs-entwurf-${version}.tgz"
|
|
1968
|
-
|
|
1969
|
-
|
|
2007
|
+
# Pack into a UNIQUE per-run dir, never the repo root. Writing/removing a fixed
|
|
2008
|
+
# ${REPO_DIR}/<tgz> pollutes the working tree (a crash leaves a stray tarball) AND
|
|
2009
|
+
# lets two concurrent packs corrupt/delete each other's artifact ("tarball data
|
|
2010
|
+
# seems corrupted" / ENOENT; a half-installed package then fails the later
|
|
2011
|
+
# install-meta-bridge check downstream). A per-run pack dir makes the tarball
|
|
2012
|
+
# instance-private end-to-end — every consumer below + the trap follow $pack_tmp.
|
|
2013
|
+
local pack_tmp
|
|
2014
|
+
pack_tmp=$(mktemp -d -t entwurf-pack.XXXXXX)
|
|
2015
|
+
tgz_path="${pack_tmp}/${tgz_name}"
|
|
1970
2016
|
|
|
1971
2017
|
# 0.12.1 C — stale-dist guard. `tsc` emit does NOT prune orphaned files from
|
|
1972
2018
|
# outDir, and `files: ["mcp/"]` would carry any leftover dist file into the
|
|
@@ -1978,7 +2024,11 @@ check_pack_install() {
|
|
|
1978
2024
|
printf 'module.exports = "stale";\n' > "$stale_probe"
|
|
1979
2025
|
|
|
1980
2026
|
echo "[check-pack-install] npm pack -> ${tgz_name}"
|
|
1981
|
-
|
|
2027
|
+
# with-dist-lock: same whole-pack serialization as check-pack — this heavy gate
|
|
2028
|
+
# and a background check-pack (via `pnpm check`) both pack, and unserialized they
|
|
2029
|
+
# race the shared dist dir. The stale-dist sentinel planted just above still
|
|
2030
|
+
# proves build-bridge's own `rm -rf dist` clean step under the lock.
|
|
2031
|
+
(cd "$REPO_DIR" && bash scripts/with-dist-lock.sh npm pack --dry-run=false --pack-destination "$pack_tmp" 2>&1 | tail -1) || {
|
|
1982
2032
|
fail "[check-pack-install] npm pack failed"
|
|
1983
2033
|
return 1
|
|
1984
2034
|
}
|
|
@@ -1999,7 +2049,7 @@ check_pack_install() {
|
|
|
1999
2049
|
# If it did, build-bridge's `rm -rf dist` clean step regressed and stale/orphan
|
|
2000
2050
|
# emit can ship. (See the plant just before npm pack above.)
|
|
2001
2051
|
if grep -qxF "mcp/entwurf-bridge/dist/__stale_probe__.js" <<<"$tar_files"; then
|
|
2002
|
-
rm -
|
|
2052
|
+
rm -rf "$pack_tmp"
|
|
2003
2053
|
fail "[check-pack-install] stale dist file shipped — build-bridge did not clean dist before emit (orphan-emit publish risk)"
|
|
2004
2054
|
return 1
|
|
2005
2055
|
fi
|
|
@@ -2025,6 +2075,14 @@ check_pack_install() {
|
|
|
2025
2075
|
# 0.12.4 — prebuilt node_modules-safe store-scan artifact for the doctor
|
|
2026
2076
|
# (see check-pack). The installed-scan smoke below runs exactly this file.
|
|
2027
2077
|
"mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
|
|
2078
|
+
# 0.12.7 — node_modules-safe agy PreInvocation hook. The installed bin smoke
|
|
2079
|
+
# below executes this exact compiled leaf from under node_modules.
|
|
2080
|
+
"mcp/entwurf-bridge/dist/scripts/agy-imprint.js"
|
|
2081
|
+
# 0.12.7 — the three operator commands (see check-pack). The installed-command
|
|
2082
|
+
# regression below drives each one through the real `entwurf` bin.
|
|
2083
|
+
"mcp/entwurf-bridge/dist/scripts/doctor-pi-provider.js"
|
|
2084
|
+
"mcp/entwurf-bridge/dist/scripts/new-session-id.js"
|
|
2085
|
+
"mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js"
|
|
2028
2086
|
# 0.12.5 — node_modules-safe plugin hook + lib (see check-pack). The installed
|
|
2029
2087
|
# hook regression below runs exactly this compiled JS from under node_modules.
|
|
2030
2088
|
"mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js"
|
|
@@ -2056,6 +2114,10 @@ check_pack_install() {
|
|
|
2056
2114
|
'^plugins/' '^node_modules/'
|
|
2057
2115
|
'\.tmp-verify/' '\.agent-(reports|shell)/'
|
|
2058
2116
|
'pi/meta-bridge/\.assembled/'
|
|
2117
|
+
# Python bytecode residue (see check-pack forbidden note): scripts/ ships
|
|
2118
|
+
# whole, so generated pyc bypasses ignore files — this cross-checks the actual
|
|
2119
|
+
# tarball, not just the dry-run resolver.
|
|
2120
|
+
'__pycache__' '\.pyc$'
|
|
2059
2121
|
)
|
|
2060
2122
|
for pat in "${tar_forbidden[@]}"; do
|
|
2061
2123
|
local hit
|
|
@@ -2068,7 +2130,7 @@ check_pack_install() {
|
|
|
2068
2130
|
done
|
|
2069
2131
|
|
|
2070
2132
|
if [ "$pass" != "1" ]; then
|
|
2071
|
-
rm -
|
|
2133
|
+
rm -rf "$pack_tmp"
|
|
2072
2134
|
fail "[check-pack-install] tar -tf invariants violated"
|
|
2073
2135
|
return 1
|
|
2074
2136
|
fi
|
|
@@ -2087,7 +2149,7 @@ check_pack_install() {
|
|
|
2087
2149
|
# nested under $tmp, whose pnpm-add node_modules/package.json would make npm
|
|
2088
2150
|
# climb the parent and choke ("Cannot read properties of null").
|
|
2089
2151
|
npm_tmp=$(mktemp -d -t entwurf-npm-managed.XXXXXX)
|
|
2090
|
-
trap 'rm -rf "$tmp" "$npm_tmp" "$
|
|
2152
|
+
trap 'rm -rf "$tmp" "$npm_tmp" "$pack_tmp"' RETURN
|
|
2091
2153
|
|
|
2092
2154
|
printf '%s\n' '{ "name": "entwurf-install-smoke", "version": "0.0.0", "private": true }' > "$tmp/package.json"
|
|
2093
2155
|
|
|
@@ -2141,7 +2203,7 @@ check_pack_install() {
|
|
|
2141
2203
|
# this whole lane is about).
|
|
2142
2204
|
local loader_out loader_home="$tmp/loader-home"
|
|
2143
2205
|
mkdir -p "$loader_home/.pi/agent"
|
|
2144
|
-
loader_out=$(cd "$tmp" && HOME="$loader_home" PI_CODING_AGENT_DIR="$loader_home/.pi/agent" pi -e "$tmp/node_modules/@junghanacs/entwurf" --list-models entwurf 2>&1) || {
|
|
2206
|
+
loader_out=$(cd "$tmp" && HOME="$loader_home" XDG_DATA_HOME="$loader_home/.local/share" XDG_STATE_HOME="$loader_home/.local/state" XDG_CACHE_HOME="$loader_home/.cache" PI_CODING_AGENT_DIR="$loader_home/.pi/agent" pi -e "$tmp/node_modules/@junghanacs/entwurf" --list-models entwurf 2>&1) || {
|
|
2145
2207
|
fail "[check-pack-install] pi loader smoke failed (exit non-zero):"
|
|
2146
2208
|
echo "$loader_out" | tail -10 | sed 's/^/ /' >&2
|
|
2147
2209
|
return 1
|
|
@@ -2191,12 +2253,12 @@ check_pack_install() {
|
|
|
2191
2253
|
fail "[check-pack-install] npm-managed layout missing executable run.sh (postinstall-chmod did not run?) at $npm_pkg"
|
|
2192
2254
|
return 1
|
|
2193
2255
|
fi
|
|
2194
|
-
if [ ! -x "$npmroot/node_modules/.bin/entwurf" ] || [ ! -x "$npmroot/node_modules/.bin/entwurf-bridge" ] || [ ! -x "$npmroot/node_modules/.bin/entwurf-statusline" ]; then
|
|
2195
|
-
fail "[check-pack-install] npm-managed neutral install missing package bins (entwurf / entwurf-bridge / entwurf-statusline)"
|
|
2256
|
+
if [ ! -x "$npmroot/node_modules/.bin/entwurf" ] || [ ! -x "$npmroot/node_modules/.bin/entwurf-bridge" ] || [ ! -x "$npmroot/node_modules/.bin/entwurf-statusline" ] || [ ! -x "$npmroot/node_modules/.bin/entwurf-agy-statusline" ] || [ ! -x "$npmroot/node_modules/.bin/entwurf-agy-imprint" ]; then
|
|
2257
|
+
fail "[check-pack-install] npm-managed neutral install missing package bins (entwurf / entwurf-bridge / entwurf-statusline / entwurf-agy-statusline / entwurf-agy-imprint)"
|
|
2196
2258
|
ls -l "$npmroot/node_modules/.bin" 2>/dev/null | sed 's/^/ /' >&2 || true
|
|
2197
2259
|
return 1
|
|
2198
2260
|
fi
|
|
2199
|
-
wire_log=$(HOME="$npmhome" "$npm_pkg/run.sh" install "$npmproj" 2>&1) || {
|
|
2261
|
+
wire_log=$(HOME="$npmhome" XDG_DATA_HOME="$npmhome/.local/share" XDG_STATE_HOME="$npmhome/.local/state" XDG_CACHE_HOME="$npmhome/.cache" "$npm_pkg/run.sh" install "$npmproj" 2>&1) || {
|
|
2200
2262
|
fail "[check-pack-install] npm-managed run.sh install failed (preflight rejected hoisted deps?):"
|
|
2201
2263
|
echo "$wire_log" | tail -15 | sed 's/^/ /' >&2
|
|
2202
2264
|
return 1
|
|
@@ -2238,7 +2300,7 @@ sys.exit(0 if any(isinstance(s,str) and s.endswith('/node_modules/@junghanacs/en
|
|
|
2238
2300
|
# a KNOWN flag and the entwurf provider must load, sourced only from user scope.
|
|
2239
2301
|
# Before the fix this printed "Unknown options: --entwurf-control".
|
|
2240
2302
|
local foreign_out
|
|
2241
|
-
foreign_out=$(cd "$tmp" && HOME="$npmhome" PI_CODING_AGENT_DIR="$npmhome/.pi/agent" pi --entwurf-control --list-models entwurf 2>&1) || {
|
|
2303
|
+
foreign_out=$(cd "$tmp" && HOME="$npmhome" XDG_DATA_HOME="$npmhome/.local/share" XDG_STATE_HOME="$npmhome/.local/state" XDG_CACHE_HOME="$npmhome/.cache" PI_CODING_AGENT_DIR="$npmhome/.pi/agent" pi --entwurf-control --list-models entwurf 2>&1) || {
|
|
2242
2304
|
fail "[check-pack-install] foreign-cwd --entwurf-control smoke failed (user-scope citizen not loading?):"
|
|
2243
2305
|
echo "$foreign_out" | tail -10 | sed 's/^/ /' >&2
|
|
2244
2306
|
return 1
|
|
@@ -2279,7 +2341,7 @@ SH
|
|
|
2279
2341
|
chmod +x "$fake_claude_dir/claude"
|
|
2280
2342
|
local mb_home="$npm_tmp/meta-home" mb_cfg="$npm_tmp/meta-claude" mb_log
|
|
2281
2343
|
mkdir -p "$mb_home" "$mb_cfg"
|
|
2282
|
-
mb_log=$(HOME="$mb_home" XDG_DATA_HOME="$mb_home/.local/share" CLAUDE_CONFIG_DIR="$mb_cfg" FAKE_CLAUDE_LOG="$fake_claude_log" PATH="$fake_claude_dir:$npmroot/node_modules/.bin:$PATH" "$npm_pkg/run.sh" install-meta-bridge 2>&1) || {
|
|
2344
|
+
mb_log=$(HOME="$mb_home" XDG_DATA_HOME="$mb_home/.local/share" XDG_STATE_HOME="$mb_home/.local/state" XDG_CACHE_HOME="$mb_home/.cache" CLAUDE_CONFIG_DIR="$mb_cfg" FAKE_CLAUDE_LOG="$fake_claude_log" PATH="$fake_claude_dir:$npmroot/node_modules/.bin:$PATH" "$npm_pkg/run.sh" install-meta-bridge 2>&1) || {
|
|
2283
2345
|
fail "[check-pack-install] installed install-meta-bridge failed under fake claude:"
|
|
2284
2346
|
echo "$mb_log" | tail -20 | sed 's/^/ /' >&2
|
|
2285
2347
|
return 1
|
|
@@ -2414,7 +2476,7 @@ function finish(trimmed) {
|
|
|
2414
2476
|
try { msg = JSON.parse(trimmed); }
|
|
2415
2477
|
catch { console.error('unparseable tools/list:', trimmed.slice(0, 300)); if (stderr.trim()) console.error(stderr.trim()); process.exit(1); }
|
|
2416
2478
|
const names = (msg?.result?.tools ?? []).map((t) => t?.name).sort();
|
|
2417
|
-
for (const need of ['entwurf_v2', 'entwurf_peers', 'entwurf_self', 'entwurf_inbox_read']) {
|
|
2479
|
+
for (const need of ['entwurf_v2', 'entwurf_peers', 'entwurf_self', 'entwurf_inbox_read', 'entwurf_register_native']) {
|
|
2418
2480
|
if (!names.includes(need)) { console.error('missing MCP tool from installed boot:', need, '— got', names.join(',')); process.exit(1); }
|
|
2419
2481
|
}
|
|
2420
2482
|
console.log(names.join(','));
|
|
@@ -2434,6 +2496,109 @@ JS
|
|
|
2434
2496
|
fi
|
|
2435
2497
|
echo "[check-pack-install] installed bridge boot pass (dist boots under node_modules, pi-free: $boot_out)"
|
|
2436
2498
|
|
|
2499
|
+
# 0.12.7 — installed AGY IMPRINT regression. The npm bin resolves through a
|
|
2500
|
+
# node_modules symlink; raw scripts/agy-imprint.ts is therefore forbidden by
|
|
2501
|
+
# Node's strip-types fence. Execute the real installed bin with an isolated
|
|
2502
|
+
# agent dir and prove the neutral hook response + one record write. This is the
|
|
2503
|
+
# exact package bug that a dev-only hook smoke cannot see.
|
|
2504
|
+
local installed_agy_imprint="$npmroot/node_modules/.bin/entwurf-agy-imprint"
|
|
2505
|
+
local agy_imprint_agent="$npm_tmp/agy-imprint-agent" agy_imprint_out agy_record_count
|
|
2506
|
+
mkdir -p "$agy_imprint_agent"
|
|
2507
|
+
if ! agy_imprint_out=$(printf '%s\n' '{"conversationId":"pack-install-agy-conversation","workspacePaths":["/tmp/entwurf-pack-install"],"modelName":"probe-model"}' | HOME="$npmhome" XDG_DATA_HOME="$npmhome/.local/share" XDG_STATE_HOME="$npmhome/.local/state" XDG_CACHE_HOME="$npmhome/.cache" PI_CODING_AGENT_DIR="$agy_imprint_agent" "$installed_agy_imprint" 2>&1); then
|
|
2508
|
+
fail "[check-pack-install] installed entwurf-agy-imprint FAILED under node_modules (raw-.ts strip-types regression or emitted hook missing):"
|
|
2509
|
+
echo "$agy_imprint_out" | tail -15 | sed 's/^/ /' >&2
|
|
2510
|
+
return 1
|
|
2511
|
+
fi
|
|
2512
|
+
if [ "$agy_imprint_out" != '{"injectSteps":[]}' ]; then
|
|
2513
|
+
fail "[check-pack-install] installed entwurf-agy-imprint returned a non-neutral hook response: $agy_imprint_out"
|
|
2514
|
+
return 1
|
|
2515
|
+
fi
|
|
2516
|
+
agy_record_count=$(find "$agy_imprint_agent/meta-sessions" -maxdepth 1 -name '*.meta.json' -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
2517
|
+
if [ "$agy_record_count" != "1" ]; then
|
|
2518
|
+
fail "[check-pack-install] installed entwurf-agy-imprint did not write exactly one isolated meta-record (got $agy_record_count)"
|
|
2519
|
+
return 1
|
|
2520
|
+
fi
|
|
2521
|
+
echo "[check-pack-install] installed agy imprint pass (compiled JS runs under node_modules; neutral response + record write)"
|
|
2522
|
+
|
|
2523
|
+
# 0.12.7 — installed OPERATOR COMMAND regression. `entwurf <cmd>` dispatches through
|
|
2524
|
+
# run.sh, whose REPO_DIR is under node_modules once installed, so a raw-.ts entrypoint
|
|
2525
|
+
# dies on the strip-types fence. These three are operator surfaces, not dev gates:
|
|
2526
|
+
# doctor-pi-provider is the pi-ownership verdict, new-session-id is the alias that mints
|
|
2527
|
+
# a garden citizen (docs/setup-clean-host.md tells operators to run the installed bin),
|
|
2528
|
+
# and meta-bridge-prune is the store maintenance verb. All three shipped DEAD through
|
|
2529
|
+
# 0.12.6 because the only installed smokes drove bins, never subcommands.
|
|
2530
|
+
#
|
|
2531
|
+
# Assert MEANING, not just the absence of the fence string: a command that regressed to
|
|
2532
|
+
# a stub or an empty exit would still "not crash". So: the id must be well-formed, the
|
|
2533
|
+
# doctor must reach its own verdict body, and prune must actually walk a 0-record store.
|
|
2534
|
+
local installed_entwurf="$npmroot/node_modules/.bin/entwurf"
|
|
2535
|
+
local op_agent="$npm_tmp/op-agent" op_out
|
|
2536
|
+
mkdir -p "$op_agent/meta-sessions"
|
|
2537
|
+
|
|
2538
|
+
# Same sandbox root set on every operator-command drive: doctor-pi-provider READS install-state
|
|
2539
|
+
# below XDG_DATA_HOME, so an inherited real root would make this gate's verdict depend on the
|
|
2540
|
+
# operator's host instead of the sandbox (non-hermetic even when nothing is written).
|
|
2541
|
+
local op_xdg_data="$npmhome/.local/share" op_xdg_state="$npmhome/.local/state" op_xdg_cache="$npmhome/.cache"
|
|
2542
|
+
if ! op_out=$(HOME="$npmhome" XDG_DATA_HOME="$op_xdg_data" XDG_STATE_HOME="$op_xdg_state" XDG_CACHE_HOME="$op_xdg_cache" PI_CODING_AGENT_DIR="$op_agent" "$installed_entwurf" new-session-id 2>&1); then
|
|
2543
|
+
fail "[check-pack-install] installed 'entwurf new-session-id' FAILED under node_modules (strip-types fence or missing compiled twin):"
|
|
2544
|
+
echo "$op_out" | tail -8 | sed 's/^/ /' >&2
|
|
2545
|
+
return 1
|
|
2546
|
+
fi
|
|
2547
|
+
# Same shape as SESSION_ID_RE (the garden id SSOT): <denote-stamp>-<6 hex>. A stub or a
|
|
2548
|
+
# truncated id would still "not crash", so the gate reads the id, not just the exit code.
|
|
2549
|
+
if ! printf '%s' "$op_out" | grep -qE '^[0-9]{8}T[0-9]{6}-[0-9a-f]{6}$'; then
|
|
2550
|
+
fail "[check-pack-install] installed 'entwurf new-session-id' did not print a well-formed garden session id: $op_out"
|
|
2551
|
+
return 1
|
|
2552
|
+
fi
|
|
2553
|
+
|
|
2554
|
+
if ! op_out=$(HOME="$npmhome" XDG_DATA_HOME="$op_xdg_data" XDG_STATE_HOME="$op_xdg_state" XDG_CACHE_HOME="$op_xdg_cache" PI_CODING_AGENT_DIR="$op_agent" "$installed_entwurf" doctor-pi-provider 2>&1); then
|
|
2555
|
+
# A doctor may exit non-zero on an unadopted host — that is a VERDICT, not a crash.
|
|
2556
|
+
# The fence, by contrast, kills it before any verdict body is printed.
|
|
2557
|
+
if printf '%s' "$op_out" | grep -q ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING; then
|
|
2558
|
+
fail "[check-pack-install] installed 'entwurf doctor-pi-provider' hit the node_modules strip-types fence:"
|
|
2559
|
+
echo "$op_out" | tail -8 | sed 's/^/ /' >&2
|
|
2560
|
+
return 1
|
|
2561
|
+
fi
|
|
2562
|
+
fi
|
|
2563
|
+
if ! printf '%s' "$op_out" | grep -q '\[pi-provider doctor\]' || ! printf '%s' "$op_out" | grep -q 'EFFECTIVE'; then
|
|
2564
|
+
fail "[check-pack-install] installed 'entwurf doctor-pi-provider' never reached its verdict body (no scopes/EFFECTIVE report):"
|
|
2565
|
+
echo "$op_out" | tail -8 | sed 's/^/ /' >&2
|
|
2566
|
+
return 1
|
|
2567
|
+
fi
|
|
2568
|
+
|
|
2569
|
+
if ! op_out=$(HOME="$npmhome" XDG_DATA_HOME="$op_xdg_data" XDG_STATE_HOME="$op_xdg_state" XDG_CACHE_HOME="$op_xdg_cache" PI_CODING_AGENT_DIR="$op_agent" "$installed_entwurf" meta-bridge-prune "$op_agent/meta-sessions" 2>&1); then
|
|
2570
|
+
fail "[check-pack-install] installed 'entwurf meta-bridge-prune' FAILED on a 0-record store:"
|
|
2571
|
+
echo "$op_out" | tail -8 | sed 's/^/ /' >&2
|
|
2572
|
+
return 1
|
|
2573
|
+
fi
|
|
2574
|
+
if ! printf '%s' "$op_out" | grep -q 'prune candidates' || ! printf '%s' "$op_out" | grep -q "store: $op_agent/meta-sessions"; then
|
|
2575
|
+
fail "[check-pack-install] installed 'entwurf meta-bridge-prune' did not scan the store it was given:"
|
|
2576
|
+
echo "$op_out" | tail -8 | sed 's/^/ /' >&2
|
|
2577
|
+
return 1
|
|
2578
|
+
fi
|
|
2579
|
+
echo "[check-pack-install] installed operator commands pass (new-session-id id-shaped, doctor-pi-provider reaches its verdict, meta-bridge-prune walks a 0-record store)"
|
|
2580
|
+
|
|
2581
|
+
# A dev-only gate has NO compiled twin by design. Under an installed package run_ts must
|
|
2582
|
+
# REFUSE it with a legible message — never fall back to raw .ts (that just re-raises the
|
|
2583
|
+
# fence error) and never exit 0 (a silent no-op would let CI "pass" a gate it never ran).
|
|
2584
|
+
local devgate_out devgate_rc=0
|
|
2585
|
+
devgate_out=$(HOME="$npmhome" XDG_DATA_HOME="$op_xdg_data" XDG_STATE_HOME="$op_xdg_state" XDG_CACHE_HOME="$op_xdg_cache" PI_CODING_AGENT_DIR="$op_agent" "$installed_entwurf" check-meta-session 2>&1) || devgate_rc=$?
|
|
2586
|
+
if [ "$devgate_rc" -eq 0 ]; then
|
|
2587
|
+
fail "[check-pack-install] a dev-only gate (check-meta-session) exited 0 from an installed package — it cannot have run; run_ts must refuse it"
|
|
2588
|
+
return 1
|
|
2589
|
+
fi
|
|
2590
|
+
if printf '%s' "$devgate_out" | grep -q ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING; then
|
|
2591
|
+
fail "[check-pack-install] a dev-only gate leaked the raw strip-types fence error instead of run_ts's refusal:"
|
|
2592
|
+
echo "$devgate_out" | tail -6 | sed 's/^/ /' >&2
|
|
2593
|
+
return 1
|
|
2594
|
+
fi
|
|
2595
|
+
if ! printf '%s' "$devgate_out" | grep -q 'dev-clone-only surface'; then
|
|
2596
|
+
fail "[check-pack-install] a dev-only gate under an installed package did not produce run_ts's refusal message:"
|
|
2597
|
+
echo "$devgate_out" | tail -6 | sed 's/^/ /' >&2
|
|
2598
|
+
return 1
|
|
2599
|
+
fi
|
|
2600
|
+
echo "[check-pack-install] dev-only gate refusal pass (installed package refuses check-* legibly, no raw-.ts fallback, no silent exit 0)"
|
|
2601
|
+
|
|
2437
2602
|
# 0.12.4 — installed STORE-DOCTOR regression. meta-bridge-doctor.sh's full store
|
|
2438
2603
|
# scan runs the prebuilt dist JS when it lives under node_modules (strip-types
|
|
2439
2604
|
# refuses the .ts there — the same class as the bridge boot above). Before the dist
|
|
@@ -2484,6 +2649,41 @@ JS
|
|
|
2484
2649
|
return 0
|
|
2485
2650
|
}
|
|
2486
2651
|
|
|
2652
|
+
check_pack_install() {
|
|
2653
|
+
# SELF-FENCE wrapper (rule 11). Keep this OUTSIDE the implementation so every exit path —
|
|
2654
|
+
# including an early failure before the implementation's cleanup trap is installed — returns
|
|
2655
|
+
# through the comparison. The DATA tree is byte-fenced. STATE cannot be byte-fenced because a
|
|
2656
|
+
# live native session may append legitimate lines concurrently, so fence the gate's unique fake
|
|
2657
|
+
# conversation marker instead; any increase proves that agy-imprint escaped its sandbox.
|
|
2658
|
+
trap - RETURN
|
|
2659
|
+
local real_data_root="${XDG_DATA_HOME:-$HOME/.local/share}/entwurf"
|
|
2660
|
+
local real_imprint_log="${XDG_STATE_HOME:-$HOME/.local/state}/entwurf/agy-imprint.log"
|
|
2661
|
+
local data_before data_after fake_before fake_after rc=0
|
|
2662
|
+
data_before="$( (find "$real_data_root" -type f -print0 2>/dev/null | sort -z | xargs -0r sha256sum) 2>/dev/null || true)"
|
|
2663
|
+
fake_before="$(grep -Fc 'conversationId=pack-install-agy-conversation' "$real_imprint_log" 2>/dev/null || true)"
|
|
2664
|
+
|
|
2665
|
+
_check_pack_install_impl "$@" || rc=$?
|
|
2666
|
+
# _check_pack_install_impl installs a RETURN cleanup trap after allocating its temp roots.
|
|
2667
|
+
# It has fired now; clear it before this wrapper returns so it cannot leak into its caller.
|
|
2668
|
+
trap - RETURN
|
|
2669
|
+
|
|
2670
|
+
data_after="$( (find "$real_data_root" -type f -print0 2>/dev/null | sort -z | xargs -0r sha256sum) 2>/dev/null || true)"
|
|
2671
|
+
fake_after="$(grep -Fc 'conversationId=pack-install-agy-conversation' "$real_imprint_log" 2>/dev/null || true)"
|
|
2672
|
+
if [ "$data_before" != "$data_after" ]; then
|
|
2673
|
+
fail "[check-pack-install] SELF-FENCE: this gate changed the operator's REAL install-state tree ($real_data_root) — a sandbox drive is leaking through an inherited XDG root:"
|
|
2674
|
+
diff <(printf '%s\n' "$data_before") <(printf '%s\n' "$data_after") | sed 's/^/ /' >&2 || true
|
|
2675
|
+
rc=1
|
|
2676
|
+
fi
|
|
2677
|
+
if [ "$fake_before" != "$fake_after" ]; then
|
|
2678
|
+
fail "[check-pack-install] SELF-FENCE: this gate appended its fake agy birth marker to the operator's REAL state log ($real_imprint_log): before=$fake_before after=$fake_after"
|
|
2679
|
+
rc=1
|
|
2680
|
+
fi
|
|
2681
|
+
if [ "$rc" -eq 0 ]; then
|
|
2682
|
+
echo "[check-pack-install] self-fence pass (real DATA tree byte-identical; fake STATE marker count unchanged)"
|
|
2683
|
+
fi
|
|
2684
|
+
return "$rc"
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2487
2687
|
|
|
2488
2688
|
# --- v2 install/runtime verification gates ---
|
|
2489
2689
|
#
|
|
@@ -2525,7 +2725,7 @@ function finishOk(trimmed) {
|
|
|
2525
2725
|
process.exit(1);
|
|
2526
2726
|
}
|
|
2527
2727
|
const names = tools.map((t) => t?.name).sort();
|
|
2528
|
-
const expected = ['entwurf_peers', 'entwurf_self', 'entwurf_inbox_read', 'entwurf_v2'];
|
|
2728
|
+
const expected = ['entwurf_peers', 'entwurf_self', 'entwurf_inbox_read', 'entwurf_register_native', 'entwurf_v2'];
|
|
2529
2729
|
for (const name of expected) {
|
|
2530
2730
|
if (!names.includes(name)) {
|
|
2531
2731
|
console.error(`missing MCP tool: ${name}`);
|
|
@@ -2627,7 +2827,7 @@ setup_all() {
|
|
|
2627
2827
|
|
|
2628
2828
|
echo "[setup] repo: $REPO_DIR"
|
|
2629
2829
|
echo "[setup] project: $project_dir"
|
|
2630
|
-
echo "[setup] scope: entwurf v2
|
|
2830
|
+
echo "[setup] scope: entwurf v2 package + detected native-harness bridges + pi adapter"
|
|
2631
2831
|
echo "[setup] verification: v2 install smoke (entwurf-bridge; LIVE substrate = release-gate)"
|
|
2632
2832
|
|
|
2633
2833
|
(cd "$REPO_DIR" && pnpm install --frozen-lockfile)
|
|
@@ -2647,6 +2847,28 @@ setup_all() {
|
|
|
2647
2847
|
echo "[setup] no native harness (claude) on PATH — skipping meta-bridge wiring (pi-only host)"
|
|
2648
2848
|
fi
|
|
2649
2849
|
|
|
2850
|
+
# Expose entwurf's STABLE bins on PATH for this DEV checkout (막힘 ②) BEFORE wiring agy: the
|
|
2851
|
+
# agy mcp_config, settings.statusLine, and hooks.json record the bare names `entwurf-bridge` /
|
|
2852
|
+
# `entwurf-agy-statusline` / `entwurf-agy-imprint`, so they must resolve for the agy doctors
|
|
2853
|
+
# to pass. NON-FATAL — a foreign bin already on PATH is left as-is.
|
|
2854
|
+
expose_dev_bin
|
|
2855
|
+
|
|
2856
|
+
# Fold agy (Antigravity) MCP bridge wiring into setup (막힘 ①, GLG 2026-07-04: install
|
|
2857
|
+
# ownership moves to entwurf). Same detection-gated, idempotent, NON-FATAL posture as the
|
|
2858
|
+
# meta-bridge block above — agy is an OPTIONAL harness, so a refused/corrupt agy config warns
|
|
2859
|
+
# but never bricks a pi/Claude setup. The hard gate stays doctor-agy-bridge.
|
|
2860
|
+
wire_agy_bridge
|
|
2861
|
+
|
|
2862
|
+
# Fold agy statusLine wiring into setup (#46 Task 1: own the ambient status area so it shows
|
|
2863
|
+
# driver + garden id, the claude meta-bridge symmetry). Same detection-gated NON-FATAL posture
|
|
2864
|
+
# — an explicit install-agy-statusline is fail-loud, but the setup wrapper WARNs + continues.
|
|
2865
|
+
wire_agy_statusline
|
|
2866
|
+
|
|
2867
|
+
# Fold agy PreInvocation birth imprint wiring into setup (#46 close criterion: manual register 0).
|
|
2868
|
+
# The hook runs the thin `entwurf-agy-imprint` bin and returns {"injectSteps":[]} so agy's loop
|
|
2869
|
+
# survives while the meta-record is created/attached by conversationId.
|
|
2870
|
+
wire_agy_hooks
|
|
2871
|
+
|
|
2650
2872
|
# Deterministic preflight lives in `pnpm check`; live substrate acceptance lives
|
|
2651
2873
|
# in `LIVE=1 ./run.sh release-gate <scratch>`. Setup is the install path, so it
|
|
2652
2874
|
# verifies the installed MCP bridge boundary only and does NOT run the legacy
|
|
@@ -2655,13 +2877,175 @@ setup_all() {
|
|
|
2655
2877
|
validate_entwurf_bridge
|
|
2656
2878
|
|
|
2657
2879
|
echo ""
|
|
2658
|
-
echo "DONE: entwurf setup (pi
|
|
2880
|
+
echo "DONE: entwurf setup (pi adapter + detected native bridges + v2 install smoke) green."
|
|
2659
2881
|
if command -v claude >/dev/null 2>&1; then
|
|
2660
|
-
echo "Verify
|
|
2882
|
+
echo "Verify Claude wiring with: ./run.sh doctor-meta-bridge"
|
|
2883
|
+
fi
|
|
2884
|
+
if command -v agy >/dev/null 2>&1; then
|
|
2885
|
+
echo "Verify agy wiring with: ./run.sh doctor-agy-bridge"
|
|
2886
|
+
echo " ./run.sh doctor-agy-statusline"
|
|
2887
|
+
echo " ./run.sh doctor-agy-hooks"
|
|
2661
2888
|
fi
|
|
2662
2889
|
echo "Run 'LIVE=1 ./run.sh release-gate <scratch>' for live substrate acceptance."
|
|
2663
2890
|
}
|
|
2664
2891
|
|
|
2892
|
+
# wire_agy_bridge — detection-gated, NON-FATAL agy (Antigravity) MCP bridge wiring, folded into
|
|
2893
|
+
# setup so a relocate/clone needs ONE idempotent command (막힘 ①). Mirrors the meta-bridge
|
|
2894
|
+
# block: agy on PATH → idempotent install-agy-bridge; no agy → honest skip, NO state ("있으면
|
|
2895
|
+
# 설정, 없으면 담아준다"). NON-FATAL by contract: agy is an OPTIONAL harness, so a refused/corrupt
|
|
2896
|
+
# agy config must NOT brick a pi/Claude setup — the hard gate is doctor-agy-bridge (issue #45:
|
|
2897
|
+
# the '?' surfaces in doctor, not by killing setup). WARNs are reason-specific so a transitional
|
|
2898
|
+
# symlink (someone else's SSOT) and a corrupt config (invalid JSON) are never conflated.
|
|
2899
|
+
wire_agy_bridge() {
|
|
2900
|
+
# Detection = the agy binary on PATH. AGY_BIN pins the target (default `agy`) so the
|
|
2901
|
+
# hermetic smoke can point at a fake agy or a definitely-absent path without depending on
|
|
2902
|
+
# whatever agy the CI/dev host happens to have — production leaves it unset (= `command -v
|
|
2903
|
+
# agy`, no regression). Same override spirit as agy-bridge.sh's AGY_MCP_CONFIG/AGY_BRIDGE_COMMAND.
|
|
2904
|
+
if ! command -v "${AGY_BIN:-agy}" >/dev/null 2>&1; then
|
|
2905
|
+
echo "[setup] no agy on PATH — skipping agy bridge wiring (no state; pi/Claude-only host)"
|
|
2906
|
+
return 0
|
|
2907
|
+
fi
|
|
2908
|
+
section "agy bridge install (native harness detected: Antigravity)"
|
|
2909
|
+
local out rc
|
|
2910
|
+
set +e
|
|
2911
|
+
out="$(bash "$REPO_DIR/scripts/agy-bridge.sh" install 2>&1)"
|
|
2912
|
+
rc=$?
|
|
2913
|
+
set -e
|
|
2914
|
+
printf '%s\n' "$out"
|
|
2915
|
+
if [ "$rc" -eq 0 ]; then
|
|
2916
|
+
echo "[setup] agy bridge wired (idempotent). Verify with: ./run.sh doctor-agy-bridge"
|
|
2917
|
+
return 0
|
|
2918
|
+
fi
|
|
2919
|
+
# NON-FATAL: keep setup alive, surface the reason honestly (never a silent pass).
|
|
2920
|
+
# ORDER MATTERS: the permission failures carry the same words as the mcp_config ones ("refused
|
|
2921
|
+
# (symlink)", "invalid JSON") and MUST be matched first — otherwise a settings.json problem gets
|
|
2922
|
+
# reported as an mcp_config problem and sends the operator to repair the wrong file.
|
|
2923
|
+
case "$out" in
|
|
2924
|
+
*"permission refused (symlink)"*|*"permission invalid JSON"*|*"permission could not be granted"*)
|
|
2925
|
+
# The MCP server IS registered — only the allow rule failed. agy defaults every mcp action to
|
|
2926
|
+
# Ask, so the bridge works but stops for a y/n on EVERY entwurf_v2 call. Half-wired, and said
|
|
2927
|
+
# so: the explicit installer fails loud on this; setup only degrades it, never hides it.
|
|
2928
|
+
echo "[setup] WARN: agy settings.json could not take our permission rule — bridge REGISTERED but NOT GRANTED." >&2
|
|
2929
|
+
echo "[setup] agy will prompt on every entwurf_v2 call until 'mcp(entwurf-bridge/entwurf_v2)'" >&2
|
|
2930
|
+
echo "[setup] is in its permissions.allow (see the line above for why). setup continues." >&2
|
|
2931
|
+
;;
|
|
2932
|
+
*"refused (symlink)"*)
|
|
2933
|
+
echo "[setup] WARN: agy mcp_config is a symlink — someone else's SSOT (transitional)." >&2
|
|
2934
|
+
echo "[setup] Bridge NOT wired; expected until install ownership moves to entwurf." >&2
|
|
2935
|
+
echo "[setup] Re-run setup once the symlink is dropped. setup continues." >&2
|
|
2936
|
+
;;
|
|
2937
|
+
*"invalid JSON"*)
|
|
2938
|
+
echo "[setup] WARN: your agy mcp_config is CORRUPT (invalid JSON) — bridge NOT wired." >&2
|
|
2939
|
+
echo "[setup] doctor-agy-bridge will KEEP FAILING until you repair that file." >&2
|
|
2940
|
+
echo "[setup] (Not a silent skip — fix the config, then re-run setup.) setup continues." >&2
|
|
2941
|
+
;;
|
|
2942
|
+
*)
|
|
2943
|
+
echo "[setup] WARN: agy bridge install did not complete (rc=$rc; see the line above)." >&2
|
|
2944
|
+
echo "[setup] Bridge NOT wired; verify with ./run.sh doctor-agy-bridge. setup continues." >&2
|
|
2945
|
+
;;
|
|
2946
|
+
esac
|
|
2947
|
+
return 0
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
# wire_agy_statusline — detection-gated, NON-FATAL agy statusLine wiring, folded into setup (#46
|
|
2951
|
+
# Task 1). Mirrors wire_agy_bridge: agy on PATH → idempotent install-agy-statusline; no agy →
|
|
2952
|
+
# honest skip, NO state. NON-FATAL by contract (agy is OPTIONAL — a refused/corrupt settings must
|
|
2953
|
+
# not brick a pi/Claude setup); the hard gate is doctor-agy-statusline. The renderer is the
|
|
2954
|
+
# stable bin entwurf-agy-statusline, exposed by expose_dev_bin above.
|
|
2955
|
+
wire_agy_statusline() {
|
|
2956
|
+
if ! command -v "${AGY_BIN:-agy}" >/dev/null 2>&1; then
|
|
2957
|
+
echo "[setup] no agy on PATH — skipping agy statusLine wiring (no state; pi/Claude-only host)"
|
|
2958
|
+
return 0
|
|
2959
|
+
fi
|
|
2960
|
+
section "agy statusLine install (native harness detected: Antigravity)"
|
|
2961
|
+
local out rc
|
|
2962
|
+
set +e
|
|
2963
|
+
out="$(bash "$REPO_DIR/scripts/agy-statusline-bridge.sh" install 2>&1)"
|
|
2964
|
+
rc=$?
|
|
2965
|
+
set -e
|
|
2966
|
+
printf '%s\n' "$out"
|
|
2967
|
+
if [ "$rc" -eq 0 ]; then
|
|
2968
|
+
echo "[setup] agy statusLine wired (idempotent). Verify with: ./run.sh doctor-agy-statusline"
|
|
2969
|
+
return 0
|
|
2970
|
+
fi
|
|
2971
|
+
case "$out" in
|
|
2972
|
+
*"refused (symlink)"*)
|
|
2973
|
+
echo "[setup] WARN: agy settings.json is a symlink — someone else's SSOT (transitional)." >&2
|
|
2974
|
+
echo "[setup] statusLine NOT wired; expected until install ownership moves to entwurf." >&2
|
|
2975
|
+
echo "[setup] Re-run setup once the symlink is dropped. setup continues." >&2
|
|
2976
|
+
;;
|
|
2977
|
+
*"invalid JSON"*)
|
|
2978
|
+
echo "[setup] WARN: your agy settings.json is CORRUPT (invalid JSON) — statusLine NOT wired." >&2
|
|
2979
|
+
echo "[setup] doctor-agy-statusline will KEEP FAILING until you repair that file." >&2
|
|
2980
|
+
echo "[setup] (Not a silent skip — fix the config, then re-run setup.) setup continues." >&2
|
|
2981
|
+
;;
|
|
2982
|
+
*)
|
|
2983
|
+
echo "[setup] WARN: agy statusLine install did not complete (rc=$rc; see the line above)." >&2
|
|
2984
|
+
echo "[setup] statusLine NOT wired; verify with ./run.sh doctor-agy-statusline. setup continues." >&2
|
|
2985
|
+
;;
|
|
2986
|
+
esac
|
|
2987
|
+
return 0
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2990
|
+
# wire_agy_hooks — detection-gated, NON-FATAL agy PreInvocation imprint wiring. Same setup posture
|
|
2991
|
+
# as the MCP/statusLine adapters, but this one is the birth writer that turns statusLine '?' into a
|
|
2992
|
+
# garden id after the first invocation.
|
|
2993
|
+
wire_agy_hooks() {
|
|
2994
|
+
if ! command -v "${AGY_BIN:-agy}" >/dev/null 2>&1; then
|
|
2995
|
+
echo "[setup] no agy on PATH — skipping agy hooks wiring (no state; pi/Claude-only host)"
|
|
2996
|
+
return 0
|
|
2997
|
+
fi
|
|
2998
|
+
section "agy hooks install (native harness detected: Antigravity)"
|
|
2999
|
+
local out rc
|
|
3000
|
+
set +e
|
|
3001
|
+
out="$(bash "$REPO_DIR/scripts/agy-hooks-bridge.sh" install 2>&1)"
|
|
3002
|
+
rc=$?
|
|
3003
|
+
set -e
|
|
3004
|
+
printf '%s\n' "$out"
|
|
3005
|
+
if [ "$rc" -eq 0 ]; then
|
|
3006
|
+
echo "[setup] agy hooks wired (idempotent). Verify with: ./run.sh doctor-agy-hooks"
|
|
3007
|
+
return 0
|
|
3008
|
+
fi
|
|
3009
|
+
case "$out" in
|
|
3010
|
+
*"refused (symlink)"*)
|
|
3011
|
+
echo "[setup] WARN: agy hooks.json is a symlink — someone else's SSOT (transitional)." >&2
|
|
3012
|
+
echo "[setup] birth imprint NOT wired; re-run setup once the symlink is dropped. setup continues." >&2
|
|
3013
|
+
;;
|
|
3014
|
+
*"invalid JSON"*)
|
|
3015
|
+
echo "[setup] WARN: your agy hooks.json is CORRUPT (invalid JSON) — birth imprint NOT wired." >&2
|
|
3016
|
+
echo "[setup] doctor-agy-hooks will KEEP FAILING until you repair that file. setup continues." >&2
|
|
3017
|
+
;;
|
|
3018
|
+
*)
|
|
3019
|
+
echo "[setup] WARN: agy hooks install did not complete (rc=$rc; see the line above)." >&2
|
|
3020
|
+
echo "[setup] Birth imprint NOT wired; verify with ./run.sh doctor-agy-hooks. setup continues." >&2
|
|
3021
|
+
;;
|
|
3022
|
+
esac
|
|
3023
|
+
return 0
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
# expose_dev_bin — make the `entwurf-bridge` STABLE bin resolve for a DEV checkout (막힘 ②).
|
|
3027
|
+
# setup IS the dev install command (consumers get the bin from npm bin-linking), so setup owns a
|
|
3028
|
+
# managed ~/.local/bin/entwurf-bridge symlink into this checkout via scripts/dev-bin.sh, recorded
|
|
3029
|
+
# for an honest inverse (remove-dev-bin). NON-FATAL like wire_agy_bridge: a foreign bin already on
|
|
3030
|
+
# PATH (a real npm install) is REFUSED not clobbered, and a BIN_DIR off PATH only WARNs — neither
|
|
3031
|
+
# bricks setup. The hard gate stays doctor-agy-bridge (a missing/dangling bin FAILs there).
|
|
3032
|
+
expose_dev_bin() {
|
|
3033
|
+
section "dev bin: expose entwurf-bridge on PATH (dev checkout)"
|
|
3034
|
+
local rc
|
|
3035
|
+
set +e
|
|
3036
|
+
bash "$REPO_DIR/scripts/dev-bin.sh" expose
|
|
3037
|
+
rc=$?
|
|
3038
|
+
set -e
|
|
3039
|
+
[ "$rc" -eq 0 ] && return 0
|
|
3040
|
+
if [ "$rc" -eq 3 ]; then
|
|
3041
|
+
echo "[setup] WARN: entwurf-bridge is already on PATH as someone else's bin (not ours) — left as-is." >&2
|
|
3042
|
+
echo "[setup] If that is a stale/foreign bin, remove it and re-run setup. setup continues." >&2
|
|
3043
|
+
else
|
|
3044
|
+
echo "[setup] WARN: dev bin exposure did not complete (rc=$rc; see above). setup continues." >&2
|
|
3045
|
+
fi
|
|
3046
|
+
return 0
|
|
3047
|
+
}
|
|
3048
|
+
|
|
2665
3049
|
# release-gate — the single command that, when GREEN, is sufficient to cut
|
|
2666
3050
|
# release cuts. Runs the full static floor (`pnpm check`) followed by the
|
|
2667
3051
|
# v2-native live gates, then emits one PASS/FAIL/SKIP summary. Everything is
|
|
@@ -2958,6 +3342,13 @@ case "$cmd" in
|
|
|
2958
3342
|
check-shell-quote)
|
|
2959
3343
|
check_shell_quote
|
|
2960
3344
|
;;
|
|
3345
|
+
check-install-surface)
|
|
3346
|
+
# 0.12.7 — structural half of the node_modules strip-types fence: run_ts is the only
|
|
3347
|
+
# crossing, every operator subcommand has a compiled twin, bin wrappers branch, dev
|
|
3348
|
+
# gates stay out of the tarball, and offline smokes never touch the real $HOME.
|
|
3349
|
+
# check-pack-install owns the dynamic half (it drives the installed commands).
|
|
3350
|
+
run_ts scripts/check-install-surface.ts
|
|
3351
|
+
;;
|
|
2961
3352
|
check-entwurf-session-identity)
|
|
2962
3353
|
check_entwurf_session_identity
|
|
2963
3354
|
;;
|
|
@@ -3021,6 +3412,9 @@ case "$cmd" in
|
|
|
3021
3412
|
check-entwurf-v2-mailbox)
|
|
3022
3413
|
check_entwurf_v2_mailbox
|
|
3023
3414
|
;;
|
|
3415
|
+
check-entwurf-v2-native-push)
|
|
3416
|
+
check_entwurf_v2_native_push
|
|
3417
|
+
;;
|
|
3024
3418
|
check-entwurf-v2-runner)
|
|
3025
3419
|
check_entwurf_v2_runner
|
|
3026
3420
|
;;
|
|
@@ -3114,11 +3508,20 @@ case "$cmd" in
|
|
|
3114
3508
|
check-entwurf-mailbox-guard)
|
|
3115
3509
|
check_entwurf_mailbox_guard
|
|
3116
3510
|
;;
|
|
3511
|
+
check-native-push-adapter)
|
|
3512
|
+
check_native_push_adapter
|
|
3513
|
+
;;
|
|
3514
|
+
check-native-push-register)
|
|
3515
|
+
check_native_push_register
|
|
3516
|
+
;;
|
|
3517
|
+
check-agy-sender-identity)
|
|
3518
|
+
check_agy_sender_identity
|
|
3519
|
+
;;
|
|
3117
3520
|
new-session-id)
|
|
3118
3521
|
# Garden launcher helper: print one fresh garden sessionId (SSOT:
|
|
3119
3522
|
# generateSessionId). Used by the operator alias to make every
|
|
3120
3523
|
# --entwurf-control session a garden citizen. Stdout = the id only.
|
|
3121
|
-
|
|
3524
|
+
run_ts scripts/new-session-id.ts
|
|
3122
3525
|
;;
|
|
3123
3526
|
smoke-resident-garden-guard)
|
|
3124
3527
|
# LIVE negative (0 tokens) + opt-in positive gate for the resident
|
|
@@ -3173,6 +3576,47 @@ case "$cmd" in
|
|
|
3173
3576
|
# duplicate/drift records. Offline + deterministic (deps bash+node+python3).
|
|
3174
3577
|
(cd "$REPO_DIR" && bash scripts/smoke-meta-install-state.sh)
|
|
3175
3578
|
;;
|
|
3579
|
+
smoke-agy-install-state)
|
|
3580
|
+
# 봉인 8 regression gate for the agy MCP install adapter: install→doctor→uninstall in an
|
|
3581
|
+
# ISOLATED HOME+XDG with a fake stable bin + fake pgrep/ss — adopt (preserve unrelated) +
|
|
3582
|
+
# state, doctor static-clean/live-SKIP (+live-PASS with a fake agy), honest-inverse
|
|
3583
|
+
# uninstall, symlink refuse, dangling FAIL, create-new inverse, and ⓪ checkout impurity 0.
|
|
3584
|
+
# Offline + deterministic (deps: bash+python3).
|
|
3585
|
+
(cd "$REPO_DIR" && bash scripts/smoke-agy-install-state.sh)
|
|
3586
|
+
;;
|
|
3587
|
+
smoke-agy-statusline-state)
|
|
3588
|
+
# #46 Task 1 regression gate for the agy statusLine install adapter: install→doctor→uninstall
|
|
3589
|
+
# in an ISOLATED HOME+XDG with a fake stable bin (entwurf-agy-statusline) + fake pgrep —
|
|
3590
|
+
# own the statusLine subtree WHOLE (preserve unrelated keys) + state (stable command, prior
|
|
3591
|
+
# subtree as preimage), doctor static-clean/live-SKIP (+live-consistent with a fake agy) /
|
|
3592
|
+
# drift-FAIL / dangling-command-FAIL / not-ours note, honest-inverse uninstall, symlink +
|
|
3593
|
+
# dangling-symlink refuse, create-new inverse, the NON-FATAL wire wrapper, and checkout
|
|
3594
|
+
# impurity 0. Offline + deterministic (deps: bash+python3).
|
|
3595
|
+
(cd "$REPO_DIR" && bash scripts/smoke-agy-statusline-state.sh)
|
|
3596
|
+
;;
|
|
3597
|
+
smoke-agy-hooks-state)
|
|
3598
|
+
# #46 birth imprint regression gate: hooks.json named hook ownership + direct
|
|
3599
|
+
# PreInvocation stdin → upsertMetaSession antigravity record, isolated HOME/XDG/PI agent.
|
|
3600
|
+
(cd "$REPO_DIR" && bash scripts/smoke-agy-hooks-state.sh)
|
|
3601
|
+
;;
|
|
3602
|
+
smoke-pi-provider-state)
|
|
3603
|
+
# #46 Task 2 regression gate for the pi provider install adapter: register-pi-provider.py
|
|
3604
|
+
# (ownership-classified install/remove, user+project scopes) + read-only doctor-pi-provider.ts
|
|
3605
|
+
# (effective shadow view). ISOLATED HOME+XDG + fake stable bin — user ownership matrix
|
|
3606
|
+
# (absent/managed-legacy/managed-current/user-override), state honest-inverse (legacy NOT
|
|
3607
|
+
# restored), sibling + legacy prune, project no-state strip, doctor effective/drift/dangling/
|
|
3608
|
+
# malformed/project-stale/'?', symlink refuse, and checkout impurity 0. Offline (bash+python3+node).
|
|
3609
|
+
(cd "$REPO_DIR" && bash scripts/smoke-pi-provider-state.sh)
|
|
3610
|
+
;;
|
|
3611
|
+
smoke-agy-native-push-live)
|
|
3612
|
+
# 봉인 8 LIVE acceptance gate for the native-push (agy) delivery rail. Drives the REAL
|
|
3613
|
+
# antigravity adapter + register core + runEntwurfV2 (production deps) against a live agy
|
|
3614
|
+
# conversation (AGY_CONVERSATION_ID): probe route, register create/attach idempotency,
|
|
3615
|
+
# fire→native-push delivered, owned-outcome reject, bogus-conv probe-indeterminate reject.
|
|
3616
|
+
# Meta-store is isolated to a temp dir (only the agy round-trip is real); honest SKIP when
|
|
3617
|
+
# LIVE!=1. doctor-static preflight FAILs before the agy bridge is wired (③).
|
|
3618
|
+
run_ts scripts/smoke-agy-native-push-live.ts
|
|
3619
|
+
;;
|
|
3176
3620
|
smoke-user-scope-citizen)
|
|
3177
3621
|
# 0.12.6 install-boundary gate: register-pi-package.py is the shared
|
|
3178
3622
|
# packages[] SSOT for project/user install and remove; user scope makes
|
|
@@ -3211,6 +3655,101 @@ case "$cmd" in
|
|
|
3211
3655
|
# zero claude-code meta-records is a SILENT MISS -> non-zero exit.
|
|
3212
3656
|
(cd "$REPO_DIR" && bash scripts/meta-bridge-doctor.sh "$@")
|
|
3213
3657
|
;;
|
|
3658
|
+
install-agy-bridge)
|
|
3659
|
+
# 봉인 7: the agy (Antigravity) MCP install ADAPTER (SEPARATE from the Claude
|
|
3660
|
+
# marketplace install — only runner/reporting is shared). Registers ONE entwurf-bridge
|
|
3661
|
+
# server entry in the agy mcp_config: adopt a regular file / create a new one / REFUSE a
|
|
3662
|
+
# symlink (someone else's SSOT). Records an install-state under $XDG_DATA_HOME/entwurf/
|
|
3663
|
+
# agy-bridge/ for an honest inverse. The command written is a STABLE bin (entwurf-bridge),
|
|
3664
|
+
# never a repo/git-hash path (the oracle dangling lesson).
|
|
3665
|
+
(cd "$REPO_DIR" && bash scripts/agy-bridge.sh install "$@")
|
|
3666
|
+
;;
|
|
3667
|
+
uninstall-agy-bridge)
|
|
3668
|
+
# 봉인 7: honest inverse of install-agy-bridge from the install-state (restore the
|
|
3669
|
+
# captured preimage / remove our key; remove the file if we created it empty). Refuses if
|
|
3670
|
+
# the managed config became a symlink since install; no state → nothing to undo.
|
|
3671
|
+
(cd "$REPO_DIR" && bash scripts/agy-bridge.sh uninstall "$@")
|
|
3672
|
+
;;
|
|
3673
|
+
doctor-agy-bridge)
|
|
3674
|
+
# 봉인 7: 2-tier fail-loud doctor. STATIC proves both candidate configs (global
|
|
3675
|
+
# ~/.gemini/config/mcp_config.json — the file live agy actually reads — + legacy
|
|
3676
|
+
# ~/.gemini/antigravity-cli which install now cleans) resolve, parse, and carry a
|
|
3677
|
+
# RESOLVABLE command (a dangling command FAILS). LIVE proves runtime-effectiveness only
|
|
3678
|
+
# when an agy process exists; with no agy it is an honest SKIP (never a PASS in disguise).
|
|
3679
|
+
(cd "$REPO_DIR" && bash scripts/agy-bridge.sh doctor "$@")
|
|
3680
|
+
;;
|
|
3681
|
+
wire-agy-bridge)
|
|
3682
|
+
# 막힘 ①: the detection-gated, NON-FATAL setup wrapper around install-agy-bridge (agy on
|
|
3683
|
+
# PATH → idempotent install; no agy → honest skip, no state). HIDDEN/internal — setup calls
|
|
3684
|
+
# this; it is exposed as a subcommand only so smoke-agy-install-state can drive it
|
|
3685
|
+
# deterministically. The hard gate stays doctor-agy-bridge (issue #45: the '?' is a doctor
|
|
3686
|
+
# signal, not a setup-killer).
|
|
3687
|
+
wire_agy_bridge
|
|
3688
|
+
;;
|
|
3689
|
+
install-agy-statusline)
|
|
3690
|
+
# #46 Task 1: own the WHOLE statusLine subtree of agy settings.json → the stable-bin renderer
|
|
3691
|
+
# entwurf-agy-statusline (driver + garden id), the claude meta-bridge statusLine symmetry.
|
|
3692
|
+
# Adopt a regular file / create / REFUSE a symlink. install-state under $XDG_DATA_HOME/
|
|
3693
|
+
# entwurf/agy-statusline/ for an honest inverse. The command is a BARE stable bin — dev AND
|
|
3694
|
+
# installed (the checkout path lives only in the dev-bin symlink state, never in settings).
|
|
3695
|
+
(cd "$REPO_DIR" && bash scripts/agy-statusline-bridge.sh install "$@")
|
|
3696
|
+
;;
|
|
3697
|
+
uninstall-agy-statusline)
|
|
3698
|
+
# #46 Task 1: honest inverse of install-agy-statusline — restore the captured statusLine
|
|
3699
|
+
# subtree preimage (remove the key if absent, else set it back; remove the file if we created
|
|
3700
|
+
# it empty). Refuses if settings.json became a symlink since install; no state → nothing.
|
|
3701
|
+
(cd "$REPO_DIR" && bash scripts/agy-statusline-bridge.sh uninstall "$@")
|
|
3702
|
+
;;
|
|
3703
|
+
doctor-agy-statusline)
|
|
3704
|
+
# #46 Task 1: fail-loud doctor. STATIC proves the SINGLE settings root agy reads statusLine
|
|
3705
|
+
# from (~/.gemini/antigravity-cli/settings.json — Task-1 capture, not the 2-candidate mcp
|
|
3706
|
+
# root) parses and carries OUR RESOLVABLE command (dangling FAILs, state drift FAILs). LIVE
|
|
3707
|
+
# proves runtime-effectiveness only with an agy process; else an honest SKIP.
|
|
3708
|
+
(cd "$REPO_DIR" && bash scripts/agy-statusline-bridge.sh doctor "$@")
|
|
3709
|
+
;;
|
|
3710
|
+
install-agy-hooks)
|
|
3711
|
+
# #46 birth writer: install the Antigravity PreInvocation named hook that runs
|
|
3712
|
+
# entwurf-agy-imprint and returns {"injectSteps":[]}.
|
|
3713
|
+
(cd "$REPO_DIR" && bash scripts/agy-hooks-bridge.sh install "$@")
|
|
3714
|
+
;;
|
|
3715
|
+
uninstall-agy-hooks)
|
|
3716
|
+
# Honest inverse of install-agy-hooks: restore/remove only our named hook.
|
|
3717
|
+
(cd "$REPO_DIR" && bash scripts/agy-hooks-bridge.sh uninstall "$@")
|
|
3718
|
+
;;
|
|
3719
|
+
doctor-agy-hooks)
|
|
3720
|
+
# Fail-loud doctor for agy hooks.json imprint wiring.
|
|
3721
|
+
(cd "$REPO_DIR" && bash scripts/agy-hooks-bridge.sh doctor "$@")
|
|
3722
|
+
;;
|
|
3723
|
+
doctor-pi-provider)
|
|
3724
|
+
# #46 Task 2: read-only fail-loud doctor for the pi provider ownership (entwurfProvider.
|
|
3725
|
+
# mcpServers.entwurf-bridge). Uses config.ts readProviderSettingsFile SSOT for the EFFECTIVE
|
|
3726
|
+
# (project-shadows-user) command — never a re-implemented merge. Reports user/project/effective,
|
|
3727
|
+
# gates on stable-bin resolvability, and distinguishes state-owned drift (FAIL) from an
|
|
3728
|
+
# unowned user override (honest note). No agy/pi process needed — pure settings inspection.
|
|
3729
|
+
run_ts scripts/doctor-pi-provider.ts "$@"
|
|
3730
|
+
;;
|
|
3731
|
+
wire-agy-statusline)
|
|
3732
|
+
# #46 Task 1: the detection-gated, NON-FATAL setup wrapper around install-agy-statusline.
|
|
3733
|
+
# HIDDEN/internal — setup calls this; exposed so smoke-agy-statusline-state can drive it
|
|
3734
|
+
# deterministically. The hard gate stays doctor-agy-statusline.
|
|
3735
|
+
wire_agy_statusline
|
|
3736
|
+
;;
|
|
3737
|
+
wire-agy-hooks)
|
|
3738
|
+
# #46 birth writer setup wrapper around install-agy-hooks.
|
|
3739
|
+
wire_agy_hooks
|
|
3740
|
+
;;
|
|
3741
|
+
expose-dev-bin)
|
|
3742
|
+
# 막힘 ②: expose the entwurf-bridge STABLE bin on PATH for a DEV checkout (a managed symlink
|
|
3743
|
+
# into this checkout, recorded for an honest inverse). HIDDEN/internal — setup calls the
|
|
3744
|
+
# NON-FATAL expose_dev_bin wrapper; exposed here so smoke-agy-install-state can drive the
|
|
3745
|
+
# foreign-refuse WARN path. The exposure logic lives in scripts/dev-bin.sh.
|
|
3746
|
+
expose_dev_bin
|
|
3747
|
+
;;
|
|
3748
|
+
remove-dev-bin)
|
|
3749
|
+
# 막힘 ②: honest inverse of expose-dev-bin — remove ONLY our managed link + state (REFUSE if
|
|
3750
|
+
# it became foreign). The raw script (no wrapper) so an operator sees a loud failure.
|
|
3751
|
+
(cd "$REPO_DIR" && bash scripts/dev-bin.sh remove "$@")
|
|
3752
|
+
;;
|
|
3214
3753
|
meta-bridge-prune)
|
|
3215
3754
|
# 1.0.0 meta-bridge Phase 4: LISTING-ONLY janitor for the meta-session store.
|
|
3216
3755
|
# doctor reds on corrupt/duplicate/drift but intentionally does NOT fail on
|
|
@@ -3221,7 +3760,7 @@ case "$cmd" in
|
|
|
3221
3760
|
# surviving authority). Default store = defaultMetaSessionsDir(); pass [dir]
|
|
3222
3761
|
# + [--ttl-days N] to override.
|
|
3223
3762
|
shift || true
|
|
3224
|
-
|
|
3763
|
+
run_ts scripts/meta-bridge-prune.ts "$@"
|
|
3225
3764
|
;;
|
|
3226
3765
|
meta-bridge-managed-keys)
|
|
3227
3766
|
# 0.10.0 meta-bridge: emit the SSOT of settings.json/~/.claude.json keys that
|
|
@@ -3318,6 +3857,9 @@ case "$cmd" in
|
|
|
3318
3857
|
remove)
|
|
3319
3858
|
remove_local_package "$TARGET_PROJECT_DIR"
|
|
3320
3859
|
;;
|
|
3860
|
+
remove-user-scope)
|
|
3861
|
+
remove_user_scope_citizen
|
|
3862
|
+
;;
|
|
3321
3863
|
-h|--help|help|"")
|
|
3322
3864
|
usage
|
|
3323
3865
|
;;
|