@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.
Files changed (92) hide show
  1. package/AGENTS.md +31 -17
  2. package/BASELINE.md +42 -8
  3. package/CHANGELOG.md +22 -0
  4. package/DELIVERY.md +71 -14
  5. package/README.md +77 -45
  6. package/VERIFY.md +18 -13
  7. package/docs/setup-clean-host.md +80 -22
  8. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +90 -66
  9. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +54 -0
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +153 -0
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +436 -0
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/context.js +157 -0
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +105 -0
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +90 -0
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +194 -0
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +153 -0
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +42 -9
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +49 -13
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +104 -11
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +30 -1
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-native-push.js +57 -0
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +10 -0
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +9 -0
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +21 -0
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +5 -0
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +17 -0
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +125 -0
  28. package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/adapter.js +158 -0
  29. package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +61 -0
  30. package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +166 -0
  31. package/mcp/entwurf-bridge/dist/scripts/doctor-pi-provider.js +130 -0
  32. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js +178 -0
  33. package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +24 -0
  34. package/mcp/entwurf-bridge/src/index.ts +101 -67
  35. package/mcp/entwurf-bridge/test.sh +1 -1
  36. package/mcp/entwurf-bridge/tsconfig.build.json +23 -3
  37. package/package.json +10 -5
  38. package/pi-extensions/lib/entwurf-deliverability.ts +62 -9
  39. package/pi-extensions/lib/entwurf-self-address.ts +58 -15
  40. package/pi-extensions/lib/entwurf-v2-contract.ts +120 -12
  41. package/pi-extensions/lib/entwurf-v2-decider.ts +60 -0
  42. package/pi-extensions/lib/entwurf-v2-native-push.ts +86 -0
  43. package/pi-extensions/lib/entwurf-v2-production.ts +20 -0
  44. package/pi-extensions/lib/entwurf-v2-release.ts +9 -0
  45. package/pi-extensions/lib/entwurf-v2-runner.ts +29 -1
  46. package/pi-extensions/lib/entwurf-v2-send.ts +7 -0
  47. package/pi-extensions/lib/entwurf-v2-surface.ts +17 -0
  48. package/pi-extensions/lib/meta-sender-identity.ts +154 -0
  49. package/pi-extensions/lib/native-push/adapter.ts +255 -0
  50. package/pi-extensions/lib/native-push/register.ts +99 -0
  51. package/run.sh +756 -214
  52. package/scripts/agy-bridge-config.py +446 -0
  53. package/scripts/agy-bridge.sh +359 -0
  54. package/scripts/agy-hooks-bridge.sh +193 -0
  55. package/scripts/agy-hooks-config.py +257 -0
  56. package/scripts/agy-imprint.sh +28 -0
  57. package/scripts/agy-imprint.ts +193 -0
  58. package/scripts/agy-statusline-bridge.sh +176 -0
  59. package/scripts/agy-statusline-config.py +213 -0
  60. package/scripts/agy-statusline.sh +256 -0
  61. package/scripts/build-bridge.sh +20 -0
  62. package/scripts/check-agy-sender-identity.ts +364 -0
  63. package/scripts/check-entwurf-bridge-boot.ts +8 -2
  64. package/scripts/check-entwurf-deliverability.ts +34 -0
  65. package/scripts/check-entwurf-self-address.ts +78 -11
  66. package/scripts/check-entwurf-v2-contract.ts +136 -1
  67. package/scripts/check-entwurf-v2-decider.ts +95 -1
  68. package/scripts/check-entwurf-v2-matrix.ts +14 -3
  69. package/scripts/check-entwurf-v2-native-push.ts +193 -0
  70. package/scripts/check-entwurf-v2-production.ts +68 -1
  71. package/scripts/check-entwurf-v2-runner.ts +58 -0
  72. package/scripts/check-entwurf-v2-surface.ts +35 -0
  73. package/scripts/check-install-surface.ts +357 -0
  74. package/scripts/check-native-push-adapter.ts +319 -0
  75. package/scripts/check-native-push-register.ts +130 -0
  76. package/scripts/dev-bin.sh +195 -0
  77. package/scripts/doctor-pi-provider.ts +140 -0
  78. package/scripts/meta-bridge-doctor.sh +36 -2
  79. package/scripts/register-pi-package.py +37 -3
  80. package/scripts/register-pi-provider.py +287 -0
  81. package/scripts/smoke-agy-hooks-state.sh +172 -0
  82. package/scripts/smoke-agy-install-state.sh +660 -0
  83. package/scripts/smoke-agy-native-push-live.ts +243 -0
  84. package/scripts/smoke-agy-statusline-state.sh +300 -0
  85. package/scripts/smoke-meta-async-drift.sh +9 -2
  86. package/scripts/smoke-meta-install-state.sh +20 -0
  87. package/scripts/smoke-pi-provider-state.sh +182 -0
  88. package/scripts/smoke-user-scope-citizen.sh +62 -0
  89. package/scripts/with-dist-lock.sh +81 -0
  90. package/scripts/__pycache__/meta-bridge-state.cpython-312.pyc +0 -0
  91. package/scripts/__pycache__/meta-bridge-state.cpython-313.pyc +0 -0
  92. package/scripts/__pycache__/register-pi-package.cpython-313.pyc +0 -0
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env bash
2
+ # smoke-agy-hooks-state — regression gate for Antigravity PreInvocation birth imprint wiring.
3
+ set -euo pipefail
4
+
5
+ REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6
+ BRIDGE="$REPO_DIR/scripts/agy-hooks-bridge.sh"
7
+ IMPRINT="$REPO_DIR/scripts/agy-imprint.ts"
8
+
9
+ pass=0
10
+ ok() { printf ' ok %s\n' "$1"; pass=$((pass + 1)); }
11
+ die() { printf 'FAIL: %s\n' "$1" >&2; exit 1; }
12
+ want() { eval "$2" && ok "$1" || die "$1"; }
13
+
14
+ REPO_BEFORE="$(cd "$REPO_DIR" && git status --porcelain)"
15
+ SB="$(mktemp -d)"
16
+ trap 'rm -rf "$SB"' EXIT
17
+ export HOME="$SB/home"
18
+ export XDG_DATA_HOME="$SB/xdg"
19
+ export XDG_STATE_HOME="$SB/state"
20
+ HOOKS="$HOME/.gemini/config/plugins/entwurf-agy-imprint/hooks.json"
21
+ LEGACY="$HOME/.gemini/antigravity-cli/hooks.json"
22
+ LEGACY_PLUGIN="$HOME/.gemini/config/plugins/entwurf-probe/hooks.json"
23
+ LEGACY_PLUGIN_JSON="$(dirname "$LEGACY_PLUGIN")/plugin.json"
24
+ PLUGIN_JSON="$(dirname "$HOOKS")/plugin.json"
25
+ STATE="$XDG_DATA_HOME/entwurf/agy-hooks/install-state.json"
26
+ mkdir -p "$(dirname "$HOOKS")" "$(dirname "$LEGACY")" "$(dirname "$LEGACY_PLUGIN")" "$SB/bin"
27
+ printf '#!/usr/bin/env bash\necho {\\"injectSteps\\":[]}\n' > "$SB/bin/entwurf-agy-imprint"
28
+ chmod +x "$SB/bin/entwurf-agy-imprint"
29
+ export PATH="$SB/bin:$PATH"
30
+
31
+ printf '{"keep-me":{"PreInvocation":[{"type":"command","command":"echo keep"}]}}\n' > "$HOOKS"
32
+ printf '{"agy-birth-probe":{"PreInvocation":[{"type":"command","command":"cat > /tmp/old"}]},"entwurf-agy-imprint":{"PreInvocation":[{"type":"command","command":"old-imprint"}]},"keep-legacy":{"PreInvocation":[{"type":"command","command":"echo legacy"}]}}\n' > "$LEGACY"
33
+ printf '{"name":"entwurf-probe","version":"1.0.0"}\n' > "$LEGACY_PLUGIN_JSON"
34
+ printf '{"agy-birth-probe":{"PreInvocation":[{"type":"command","command":"cat > /tmp/plugin-old"}]}}\n' > "$LEGACY_PLUGIN"
35
+ bash "$BRIDGE" install >/dev/null
36
+ want "install: imprint hook configured" \
37
+ "python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); sys.exit(0 if d[\"entwurf-agy-imprint\"][\"PreInvocation\"][0][\"command\"]==\"entwurf-agy-imprint\" else 1)' '$HOOKS'"
38
+ want "install: unrelated hook preserved" \
39
+ "python3 -c 'import json,sys; sys.exit(0 if \"keep-me\" in json.load(open(sys.argv[1])) else 1)' '$HOOKS'"
40
+ want "install: state written" "[ -f '$STATE' ]"
41
+ want "install: plugin.json materialized" "[ -f '$PLUGIN_JSON' ]"
42
+ want "install: plugin.json uses non-probe name" "grep -q 'entwurf-agy-imprint' '$PLUGIN_JSON'"
43
+ want "install: stable command recorded" \
44
+ "python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))[\"command\"])' '$STATE' | grep -qx entwurf-agy-imprint"
45
+ want "install: legacy top-level agy-birth-probe removed" \
46
+ "python3 -c 'import json,sys; sys.exit(0 if \"agy-birth-probe\" not in json.load(open(sys.argv[1])) else 1)' '$LEGACY'"
47
+ want "install: legacy top-level duplicate imprint removed" \
48
+ "python3 -c 'import json,sys; sys.exit(0 if \"entwurf-agy-imprint\" not in json.load(open(sys.argv[1])) else 1)' '$LEGACY'"
49
+ want "install: unrelated legacy hook preserved" \
50
+ "python3 -c 'import json,sys; sys.exit(0 if \"keep-legacy\" in json.load(open(sys.argv[1])) else 1)' '$LEGACY'"
51
+ want "install: old entwurf-probe plugin hook file removed" "[ ! -e '$LEGACY_PLUGIN' ]"
52
+ want "install: old entwurf-probe plugin.json removed" "[ ! -e '$LEGACY_PLUGIN_JSON' ]"
53
+
54
+ DOC_OUT="$(bash "$BRIDGE" doctor)"; DOC_RC=$?
55
+ want "doctor: exits 0" "[ '$DOC_RC' -eq 0 ]"
56
+ want "doctor: command resolvable" "printf '%s' \"\$DOC_OUT\" | grep -q \"configured → 'entwurf-agy-imprint' (resolvable)\""
57
+ want "doctor: state confirms configured" "printf '%s' \"\$DOC_OUT\" | grep -q 'still configure entwurf-agy-imprint'"
58
+ want "doctor: legacy top-level guard reports clean" "printf '%s' \"\$DOC_OUT\" | grep -q 'legacy top-level: present but carries no entwurf/probe hook keys'"
59
+ want "doctor: old plugin guard reports absent" "printf '%s' \"\$DOC_OUT\" | grep -q 'legacy plugin(entwurf-probe): absent'"
60
+
61
+ python3 -c 'import json,sys; p=sys.argv[1]; d=json.load(open(p)); d["agy-birth-probe"]={"PreInvocation":[{"type":"command","command":"old"}]}; json.dump(d,open(p,"w"))' "$LEGACY"
62
+ if bash "$BRIDGE" doctor >/dev/null 2>&1; then die "legacy-drift: doctor should FAIL when top-level carries old probe key"; fi
63
+ ok "legacy-drift: doctor FAILS on top-level agy-birth-probe"
64
+ bash "$BRIDGE" install >/dev/null
65
+ want "legacy-drift: re-install cleans top-level again" \
66
+ "python3 -c 'import json,sys; sys.exit(0 if \"agy-birth-probe\" not in json.load(open(sys.argv[1])) else 1)' '$LEGACY'"
67
+ mkdir -p "$(dirname "$LEGACY_PLUGIN")"
68
+ printf '{"agy-birth-probe":{"PreInvocation":[{"type":"command","command":"old-plugin"}]}}\n' > "$LEGACY_PLUGIN"
69
+ if bash "$BRIDGE" doctor >/dev/null 2>&1; then die "legacy-plugin-drift: doctor should FAIL when old plugin carries probe key"; fi
70
+ ok "legacy-plugin-drift: doctor FAILS on old entwurf-probe plugin key"
71
+ bash "$BRIDGE" install >/dev/null
72
+ want "legacy-plugin-drift: re-install removes old plugin hook file" "[ ! -e '$LEGACY_PLUGIN' ]"
73
+
74
+ python3 -c 'import json,sys; p=sys.argv[1]; d=json.load(open(p)); d.pop("entwurf-agy-imprint", None); json.dump(d,open(p,"w"))' "$HOOKS"
75
+ if bash "$BRIDGE" doctor >/dev/null 2>&1; then die "drift: doctor should FAIL when state hook is removed"; fi
76
+ ok "drift: doctor FAILS on state-present + hook-removed"
77
+ bash "$BRIDGE" install >/dev/null
78
+
79
+ rm -f "$HOOKS"
80
+ DOC_OUT="$(bash "$BRIDGE" doctor 2>&1)"; DOC_RC=$?
81
+ want "orphan: doctor exits 0 when hooks file is absent" "[ '$DOC_RC' -eq 0 ]"
82
+ want "orphan: doctor logs ORPHANED" "printf '%s' \"\$DOC_OUT\" | grep -q ORPHANED"
83
+ want "orphan: state removed" "[ ! -f '$STATE' ]"
84
+
85
+ printf '{"keep-me":{"PreInvocation":[{"type":"command","command":"echo keep"}]}}\n' > "$HOOKS"
86
+ bash "$BRIDGE" install >/dev/null
87
+ bash "$BRIDGE" uninstall >/dev/null
88
+ want "uninstall: imprint hook removed" \
89
+ "python3 -c 'import json,sys; sys.exit(0 if \"entwurf-agy-imprint\" not in json.load(open(sys.argv[1])) else 1)' '$HOOKS'"
90
+ want "uninstall: unrelated hook survived" \
91
+ "python3 -c 'import json,sys; sys.exit(0 if \"keep-me\" in json.load(open(sys.argv[1])) else 1)' '$HOOKS'"
92
+ want "uninstall: state removed" "[ ! -f '$STATE' ]"
93
+
94
+ rm -f "$HOOKS"
95
+ printf '{}\n' > "$SB/real_hooks.json"
96
+ ln -s "$SB/real_hooks.json" "$HOOKS"
97
+ if bash "$BRIDGE" install >/dev/null 2>&1; then die "symlink: install should REFUSE"; fi
98
+ ok "symlink: install refused"
99
+ want "symlink: no state written" "[ ! -f '$STATE' ]"
100
+ rm -f "$HOOKS"
101
+
102
+ # Direct imprint contract: stdout neutral, create then attach by conversationId, no duplicate.
103
+ AGENT="$SB/agent"
104
+ payload='{"conversationId":"conv-smoke","workspacePaths":["/work/smoke"],"transcriptPath":"/tmp/t.jsonl","modelName":"gemini-smoke"}'
105
+ printf '%s' "$payload" | PI_CODING_AGENT_DIR="$AGENT" node --experimental-strip-types "$IMPRINT" > "$SB/out1"
106
+ want "imprint: stdout is neutral PreInvocation response" "grep -qx '{\"injectSteps\":\[\]}' '$SB/out1'"
107
+ want "imprint: creates one antigravity record" \
108
+ "[ \$(find '$AGENT/meta-sessions' -name '*.meta.json' | wc -l) -eq 1 ] && grep -q '\"backend\": \"antigravity\"' '$AGENT/meta-sessions'/*.meta.json"
109
+ printf '%s' "$payload" | PI_CODING_AGENT_DIR="$AGENT" node --experimental-strip-types "$IMPRINT" >/dev/null
110
+ want "imprint: second run attaches, no duplicate" "[ \$(find '$AGENT/meta-sessions' -name '*.meta.json' | wc -l) -eq 1 ]"
111
+ printf '%s' '{"workspacePaths":["/work/smoke"]}' | PI_CODING_AGENT_DIR="$SB/agent2" node --experimental-strip-types "$IMPRINT" >/dev/null
112
+ want "imprint: missing conversationId writes no record" "[ ! -d '$SB/agent2/meta-sessions' ] || [ \$(find '$SB/agent2/meta-sessions' -name '*.meta.json' | wc -l) -eq 0 ]"
113
+
114
+ # ── RE-INSTALL PROVENANCE: an installer is re-run on every upgrade ────────────
115
+ # The preimage answers "what was here before US". Re-capturing it on each install would record OUR
116
+ # OWN previous hook as the operator's, and the honest inverse would then restore us — uninstall
117
+ # leaving behind the very thing it exists to remove. Same bug class, all three agy adapters.
118
+ rm -f "$HOOKS" "$STATE"
119
+ mkdir -p "$(dirname "$HOOKS")"
120
+ printf '{"other-plugin":{"PreInvocation":[{"type":"command","command":"keepme"}]}}\n' > "$HOOKS"
121
+ bash "$BRIDGE" install >/dev/null 2>&1
122
+ bash "$BRIDGE" install >/dev/null 2>&1
123
+ bash "$BRIDGE" install >/dev/null 2>&1
124
+ want "re-install: provenance stays the FIRST install's (preimage still null, not our own hook)" \
125
+ "python3 -c \"import json,sys;sys.exit(0 if json.load(open('$STATE'))['preimage'] is None else 1)\""
126
+ bash "$BRIDGE" uninstall >/dev/null 2>&1
127
+ want "re-install: uninstall after install×3 still removes our hook (no self-restore)" \
128
+ "! python3 -c \"import json,sys;sys.exit(0 if 'entwurf-agy-imprint' in json.load(open('$HOOKS')) else 1)\""
129
+ want "re-install: an unrelated plugin's hook survives the whole cycle" \
130
+ "python3 -c \"import json,sys;sys.exit(0 if 'other-plugin' in json.load(open('$HOOKS')) else 1)\""
131
+
132
+ REPO_AFTER="$(cd "$REPO_DIR" && git status --porcelain)"
133
+ want "purity: checkout unchanged (all writes stayed in sandbox HOME+XDG)" "[ \"$REPO_BEFORE\" = \"$REPO_AFTER\" ]"
134
+
135
+ # ── FOREIGN TARGET: state describes a hooks file this host does not load ──────────────
136
+ # The recorded hooks file is perfectly configured — it is just not the one agy loads here. A doctor
137
+ # that only inspects the recorded path calls that green while the LIVE PreInvocation hook is
138
+ # unowned: uninstall would leave it in place, and its provenance is unrecorded. A real host reached
139
+ # this shape via a verification run that isolated HOME but SHARED XDG_DATA_HOME. Isolation must move
140
+ # HOME and XDG_DATA_HOME together.
141
+ bash "$BRIDGE" install >/dev/null # re-own this host (earlier cases may have torn the state down)
142
+ FOREIGN_HOOKS="$SB/foreign-hooks.json"
143
+ cp "$HOOKS" "$FOREIGN_HOOKS"
144
+ python3 -c "
145
+ import json,sys
146
+ p=sys.argv[1]; d=json.load(open(p)); d['managedHooksPath']=sys.argv[2]
147
+ json.dump(d, open(p,'w'))" "$STATE" "$FOREIGN_HOOKS"
148
+ set +e; FT_OUT="$(bash "$BRIDGE" doctor 2>&1)"; FT_RC=$?; set -e
149
+ want "foreign-target: doctor FAILS when install-state manages hooks this host does not load" "[ '$FT_RC' -ne 0 ]"
150
+ want "foreign-target: the report names both the recorded and the live hooks path" \
151
+ "printf '%s' \"\$FT_OUT\" | grep -q 'FOREIGN TARGET' && printf '%s' \"\$FT_OUT\" | grep -qF '$FOREIGN_HOOKS' && printf '%s' \"\$FT_OUT\" | grep -qF '$HOOKS'"
152
+ want "foreign-target: it names the real damage — the live hook is unowned" \
153
+ "printf '%s' \"\$FT_OUT\" | grep -qi 'unowned'"
154
+ want "foreign-target: neither the foreign hooks file nor the state is auto-deleted" "[ -f '$FOREIGN_HOOKS' ] && [ -f '$STATE' ]"
155
+ rm -f "$FOREIGN_HOOKS"
156
+
157
+ # A present state with invalid JSON or no managed target is corrupt evidence, not "no evidence".
158
+ # The doctor must fail loud instead of parsing to an empty string and skipping the ownership check.
159
+ printf 'not-json{{{' > "$STATE"
160
+ set +e; FT_OUT="$(bash "$BRIDGE" doctor 2>&1)"; FT_RC=$?; set -e
161
+ want "corrupt-state: doctor FAILS on unreadable install-state" "[ '$FT_RC' -ne 0 ]"
162
+ want "corrupt-state: report names CORRUPT instead of silently skipping ownership" \
163
+ "printf '%s' \"\$FT_OUT\" | grep -q 'state: CORRUPT'"
164
+
165
+ # A RELATIVE managed path is corrupt too — install records absolute paths only, and resolving a
166
+ # relative one against the doctor's cwd could bless whatever directory it happens to run from.
167
+ printf '{"managedHooksPath":".gemini/config/plugins/entwurf-agy-imprint/hooks.json"}' > "$STATE"
168
+ set +e; FT_OUT="$(bash "$BRIDGE" doctor 2>&1)"; FT_RC=$?; set -e
169
+ want "corrupt-state: a relative managedHooksPath is CORRUPT, never resolved against the doctor's cwd" \
170
+ "[ '$FT_RC' -ne 0 ] && printf '%s' \"\$FT_OUT\" | grep -q 'state: CORRUPT'"
171
+
172
+ printf '\nsmoke-agy-hooks-state: %d checks passed\n' "$pass"