@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
|
@@ -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"
|