Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
465315d
invoker: wf-1789407151357-66/implement-hook-unverified-tag-ledger — P…
Sep 27, 2026
f31826d
invoker: wf-1789407151357-66/verify-hook-unverified-tag-ledger — Run …
Sep 27, 2026
53422e4
invoker: wf-1789407151357-66/scrub-handoff-artifacts — Terminal read-…
Sep 27, 2026
3d80a25
Merge experiment/wf-1789407151357-66/scrub-handoff-artifacts/g1.t59.a…
EdbertChan Sep 27, 2026
bb94e67
invoker: wf-1789407155931-67/implement-hook-verdict-flip-watch — Put …
Sep 27, 2026
55a721d
invoker: wf-1789407155931-67/verify-hook-verdict-flip-watch — Run the…
Sep 27, 2026
175457a
invoker: wf-1789407155931-67/scrub-handoff-artifacts — Terminal read-…
Sep 27, 2026
0712dfa
Merge experiment/wf-1789407155931-67/scrub-handoff-artifacts/g1.t60.a…
EdbertChan Sep 27, 2026
d43e291
invoker: wf-1789407160126-68/implement-hook-wait-needs-wakeup — Put t…
Sep 27, 2026
9f37ae6
invoker: wf-1789407160126-68/verify-hook-wait-needs-wakeup — Run the …
Sep 27, 2026
42c0fa0
invoker: wf-1789407160126-68/scrub-handoff-artifacts — Terminal read-…
Sep 27, 2026
991f7f6
Merge experiment/wf-1789407160126-68/scrub-handoff-artifacts/g1.t60.a…
EdbertChan Sep 27, 2026
b17989c
invoker: wf-1789407163087-69/implement-hook-wrong-check-reflect — Put…
Sep 27, 2026
c127a7e
invoker: wf-1789407163087-69/verify-hook-wrong-check-reflect — Run th…
Sep 27, 2026
2dc3cdf
invoker: wf-1789407163087-69/scrub-handoff-artifacts — Terminal read-…
Sep 27, 2026
3678dbe
Merge experiment/wf-1789407163087-69/scrub-handoff-artifacts/g1.t60.a…
EdbertChan Sep 27, 2026
19e10f9
invoker: wf-1789407166425-70/implement-install-from-registry — Instal…
Sep 27, 2026
0fafc18
invoker: wf-1789407166425-70/verify-install-from-registry — Run the d…
Sep 27, 2026
ce7d3b8
invoker: wf-1789407166425-70/scrub-handoff-artifacts — Terminal read-…
Sep 27, 2026
9a30c94
Merge experiment/wf-1789407166425-70/scrub-handoff-artifacts/g1.t60.a…
EdbertChan Sep 27, 2026
8457fb5
tests: follow registry hook installer
Sep 27, 2026
dd755a3
invoker: wf-1790490529005-203/repair — Repair PR #1204 (failed check …
Sep 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions engine/hooks/_flags/tests/test_installed_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
Run: python3 -m unittest discover -s engine/hooks/_flags/tests -v
"""
import os
import re
import shutil
import subprocess
import sys
Expand All @@ -26,8 +25,12 @@

FLAGS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
HOOKS_DIR = os.path.dirname(FLAGS_DIR)
SDK_DIR = os.path.join(HOOKS_DIR, "_sdk")
REPO_DIR = os.path.dirname(os.path.dirname(HOOKS_DIR))
INSTALL_SH = os.path.join(REPO_DIR, "install.sh")
sys.path.insert(0, SDK_DIR)

from install_from_registry import harness_hook_names # noqa: E402

CONSUMER = (
"import os, sys\n"
Expand Down Expand Up @@ -135,13 +138,7 @@ def test_every_hook_importing_flags_is_linked_where_it_is_installed(self):
for hook in sorted(importers):
for harness, relative in HARNESS_DIRS:
folder = relative.replace(os.sep, "/")
installed = re.search(
r'link_item "{}" "\$HOOKS_SNAPSHOT_DIR/{}" "\$HOME/{}/{}"'.format(
re.escape(hook), re.escape(hook), re.escape(folder), re.escape(hook)
),
self.body,
)
if not installed:
if hook not in harness_hook_names(harness):
continue
checked += 1
with self.subTest(hook=hook, harness=harness):
Expand All @@ -152,8 +149,8 @@ def test_every_hook_importing_flags_is_linked_where_it_is_installed(self):
)
self.assertTrue(
checked,
"matched no link_item line for any flags-importing hook -- the regex "
"no longer matches install.sh, so this test checked nothing",
"matched no registry-installed harness for any flags-importing hook, "
"so this test checked nothing",
)


Expand Down
27 changes: 26 additions & 1 deletion engine/hooks/_sdk/install_from_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ def _fragment_paths(hook: str, harness: str) -> list[Path]:
return sorted(paths)


def harness_hook_names(harness: str, registry_path: Path | None = None) -> list[str]:
registry, _thresholds = load_registry(registry_path)
return [
hook
for hook in registry
if (HOOKS_DIR / hook).is_dir()
if harness == "claude" or hook != "cat-mode-default"
]


def _load_fragment(path: Path) -> dict:
data = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(data, dict) or not isinstance(data.get("hooks"), dict):
Expand Down Expand Up @@ -142,7 +152,11 @@ def install(home: Path | None = None, registry_path: Path | None = None) -> int:
home = home or Path.home()
registry, _thresholds = load_registry(registry_path)
registry_hooks = set(registry)
active_hooks = list(registry)
active_hooks = [
name
for name, record in registry.items()
if record.mode != "off"
]
python, warning = _pick_install_python()
if warning:
sys.stderr.write(warning)
Expand Down Expand Up @@ -175,6 +189,17 @@ def install(home: Path | None = None, registry_path: Path | None = None) -> int:

def main() -> int:
try:
if len(sys.argv) == 3 and sys.argv[1] == "--list-harness-hooks":
harness = sys.argv[2]
if harness not in CONFIGS:
print(f"error unknown harness: {harness}", file=sys.stderr)
return 2
for hook in harness_hook_names(harness):
print(hook)
return 0
if len(sys.argv) != 1:
print("usage install_from_registry.py [--list-harness-hooks claude|cursor|codex]", file=sys.stderr)
return 2
return install()
except Exception as exc:
print(f"error install_from_registry: {exc}", file=sys.stderr)
Expand Down
5 changes: 3 additions & 2 deletions engine/hooks/agent-launch-guard/tests/test_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
sys.path.insert(0, SDK_DIR)

import detect # noqa: E402
from install_from_registry import harness_hook_names # noqa: E402
from finding import Finding # noqa: E402
from render import render # noqa: E402

Expand Down Expand Up @@ -134,10 +135,10 @@ def test_install_links_the_dir_the_manifest_points_at(self):
with open(os.path.join(REPO_ROOT, "install.sh"), encoding="utf-8") as handle:
install_sh = handle.read()
self.assertIn(
'link_item "agent-launch-guard" "$HOOKS_SNAPSHOT_DIR/agent-launch-guard" '
'"$HOME/.claude/hooks/agent-launch-guard"',
'install_from_registry.py" --list-harness-hooks claude',
install_sh,
)
self.assertIn("agent-launch-guard", harness_hook_names("claude"))

def test_manifest_targets_installed_claude_hook(self):
with open(os.path.join(HOOKS_DIR, "claude.hook.json"), encoding="utf-8") as handle:
Expand Down
93 changes: 9 additions & 84 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -355,59 +355,9 @@ link_item "_markers" "$HOOKS_SNAPSHOT_DIR/_markers" "$HOME/.claude/hooks/_marker
install_local_runner "$REPO_DIR/engine/hooks/_runner" "$HOME/.claude/hooks/_runner"
link_item "_flags" "$HOOKS_SNAPSHOT_DIR/_flags" "$HOME/.claude/hooks/_flags"
link_item "_sdk" "$HOOKS_SNAPSHOT_DIR/_sdk" "$HOME/.claude/hooks/_sdk"
link_item "diu-stop" "$HOOKS_SNAPSHOT_DIR/diu-stop" "$HOME/.claude/hooks/diu-stop"
link_item "bug-complaint-leak" "$HOOKS_SNAPSHOT_DIR/bug-complaint-leak" "$HOME/.claude/hooks/bug-complaint-leak"
link_item "demo-freeze" "$HOOKS_SNAPSHOT_DIR/demo-freeze" "$HOME/.claude/hooks/demo-freeze"
link_item "frustration-watchdog" "$HOOKS_SNAPSHOT_DIR/frustration-watchdog" "$HOME/.claude/hooks/frustration-watchdog"
link_item "skill-usage-log" "$HOOKS_SNAPSHOT_DIR/skill-usage-log" "$HOME/.claude/hooks/skill-usage-log"
link_item "reflect-on-thrash" "$HOOKS_SNAPSHOT_DIR/reflect-on-thrash" "$HOME/.claude/hooks/reflect-on-thrash"
link_item "scope-lock" "$HOOKS_SNAPSHOT_DIR/scope-lock" "$HOME/.claude/hooks/scope-lock"
link_item "restart-risk-check" "$HOOKS_SNAPSHOT_DIR/restart-risk-check" "$HOME/.claude/hooks/restart-risk-check"
link_item "auto-pr" "$HOOKS_SNAPSHOT_DIR/auto-pr" "$HOME/.claude/hooks/auto-pr"
link_item "pr-schema-gate" "$HOOKS_SNAPSHOT_DIR/pr-schema-gate" "$HOME/.claude/hooks/pr-schema-gate"
link_item "external-claim-gate" "$HOOKS_SNAPSHOT_DIR/external-claim-gate" "$HOME/.claude/hooks/external-claim-gate"
link_item "wrong-check-reflect" "$HOOKS_SNAPSHOT_DIR/wrong-check-reflect" "$HOME/.claude/hooks/wrong-check-reflect"
link_item "handback-needs-attempt" "$HOOKS_SNAPSHOT_DIR/handback-needs-attempt" "$HOME/.claude/hooks/handback-needs-attempt"
link_item "llm-judge" "$HOOKS_SNAPSHOT_DIR/llm-judge" "$HOME/.claude/hooks/llm-judge"
link_item "hook-health" "$HOOKS_SNAPSHOT_DIR/hook-health" "$HOME/.claude/hooks/hook-health"
link_item "build-the-lever" "$HOOKS_SNAPSHOT_DIR/build-the-lever" "$HOME/.claude/hooks/build-the-lever"
link_item "split-scope" "$HOOKS_SNAPSHOT_DIR/split-scope" "$HOME/.claude/hooks/split-scope"
link_item "no-comments" "$HOOKS_SNAPSHOT_DIR/no-comments" "$HOME/.claude/hooks/no-comments"
link_item "explicit-failures" "$HOOKS_SNAPSHOT_DIR/explicit-failures" "$HOME/.claude/hooks/explicit-failures"
link_item "text-match-decision-warn" "$HOOKS_SNAPSHOT_DIR/text-match-decision-warn" "$HOME/.claude/hooks/text-match-decision-warn"
link_item "bound-tool-result" "$HOOKS_SNAPSHOT_DIR/bound-tool-result" "$HOME/.claude/hooks/bound-tool-result"
link_item "repeat-error-stop" "$HOOKS_SNAPSHOT_DIR/repeat-error-stop" "$HOME/.claude/hooks/repeat-error-stop"
link_item "repeat-deny-stop" "$HOOKS_SNAPSHOT_DIR/repeat-deny-stop" "$HOME/.claude/hooks/repeat-deny-stop"
link_item "prove-it-ship-gate" "$HOOKS_SNAPSHOT_DIR/prove-it-ship-gate" "$HOME/.claude/hooks/prove-it-ship-gate"
link_item "narrow-the-scope" "$HOOKS_SNAPSHOT_DIR/narrow-the-scope" "$HOME/.claude/hooks/narrow-the-scope"
link_item "answer-overrides-menu" "$HOOKS_SNAPSHOT_DIR/answer-overrides-menu" "$HOME/.claude/hooks/answer-overrides-menu"
link_item "serial-option-guard" "$HOOKS_SNAPSHOT_DIR/serial-option-guard" "$HOME/.claude/hooks/serial-option-guard"
link_item "cat-mode-default" "$HOOKS_SNAPSHOT_DIR/cat-mode-default" "$HOME/.claude/hooks/cat-mode-default"
link_item "fanout-routing-guard" "$HOOKS_SNAPSHOT_DIR/fanout-routing-guard" "$HOME/.claude/hooks/fanout-routing-guard"
link_item "playbook-router" "$HOOKS_SNAPSHOT_DIR/playbook-router" "$HOME/.claude/hooks/playbook-router"
link_item "restated-constraint" "$HOOKS_SNAPSHOT_DIR/restated-constraint" "$HOME/.claude/hooks/restated-constraint"
link_item "named-verb-guard" "$HOOKS_SNAPSHOT_DIR/named-verb-guard" "$HOME/.claude/hooks/named-verb-guard"
link_item "user-did-it" "$HOOKS_SNAPSHOT_DIR/user-did-it" "$HOME/.claude/hooks/user-did-it"
echo "--- claude hooks: wait / hedge / callout stack ---"
link_item "wait-needs-wakeup" "$HOOKS_SNAPSHOT_DIR/wait-needs-wakeup" "$HOME/.claude/hooks/wait-needs-wakeup"
link_item "hedge-runs-prove-it" "$HOOKS_SNAPSHOT_DIR/hedge-runs-prove-it" "$HOME/.claude/hooks/hedge-runs-prove-it"
link_item "gate-blame-needs-evidence" "$HOOKS_SNAPSHOT_DIR/gate-blame-needs-evidence" "$HOME/.claude/hooks/gate-blame-needs-evidence"
link_item "unverified-tag-ledger" "$HOOKS_SNAPSHOT_DIR/unverified-tag-ledger" "$HOME/.claude/hooks/unverified-tag-ledger"
link_item "unverified-tag-check" "$HOOKS_SNAPSHOT_DIR/unverified-tag-check" "$HOME/.claude/hooks/unverified-tag-check"
link_item "incidence-needs-repetition" "$HOOKS_SNAPSHOT_DIR/incidence-needs-repetition" "$HOME/.claude/hooks/incidence-needs-repetition"
link_item "verdict-flip-watch" "$HOOKS_SNAPSHOT_DIR/verdict-flip-watch" "$HOME/.claude/hooks/verdict-flip-watch"
link_item "new-file-callout" "$HOOKS_SNAPSHOT_DIR/new-file-callout" "$HOME/.claude/hooks/new-file-callout"
link_item "agent-relay-attribution" "$HOOKS_SNAPSHOT_DIR/agent-relay-attribution" "$HOME/.claude/hooks/agent-relay-attribution"
link_item "scratchpad-collision" "$HOOKS_SNAPSHOT_DIR/scratchpad-collision" "$HOME/.claude/hooks/scratchpad-collision"
link_item "ui-input-guard" "$HOOKS_SNAPSHOT_DIR/ui-input-guard" "$HOME/.claude/hooks/ui-input-guard"
link_item "handoff-needs-smoke-test" "$HOOKS_SNAPSHOT_DIR/handoff-needs-smoke-test" "$HOME/.claude/hooks/handoff-needs-smoke-test"
link_item "hook-freshness" "$HOOKS_SNAPSHOT_DIR/hook-freshness" "$HOME/.claude/hooks/hook-freshness"
link_item "gh-write-verification" "$HOOKS_SNAPSHOT_DIR/gh-write-verification" "$HOME/.claude/hooks/gh-write-verification"
link_item "history-before-reversal" "$HOOKS_SNAPSHOT_DIR/history-before-reversal" "$HOME/.claude/hooks/history-before-reversal"
link_item "publish-act-guard" "$HOOKS_SNAPSHOT_DIR/publish-act-guard" "$HOME/.claude/hooks/publish-act-guard"
link_item "categorical-scope-guard" "$HOOKS_SNAPSHOT_DIR/categorical-scope-guard" "$HOME/.claude/hooks/categorical-scope-guard"
link_item "claimed-search-not-run" "$HOOKS_SNAPSHOT_DIR/claimed-search-not-run" "$HOME/.claude/hooks/claimed-search-not-run"
link_item "agent-launch-guard" "$HOOKS_SNAPSHOT_DIR/agent-launch-guard" "$HOME/.claude/hooks/agent-launch-guard"
while IFS= read -r hook_name; do
link_item "$hook_name" "$HOOKS_SNAPSHOT_DIR/$hook_name" "$HOME/.claude/hooks/$hook_name"
done < <(python3 "$REPO_DIR/engine/hooks/_sdk/install_from_registry.py" --list-harness-hooks claude)

echo "--- git pre-push hooks (init.templateDir and this clone) ---"
bash "$REPO_DIR/scripts/install/install-git-template.sh"
Expand All @@ -419,44 +369,19 @@ install_local_runner "$REPO_DIR/engine/hooks/_runner" "$HOME/.cursor/hooks/_runn
link_item "_flags" "$HOOKS_SNAPSHOT_DIR/_flags" "$HOME/.cursor/hooks/_flags"
link_item "_sdk" "$HOOKS_SNAPSHOT_DIR/_sdk" "$HOME/.cursor/hooks/_sdk"
link_item "_markers" "$HOOKS_SNAPSHOT_DIR/_markers" "$HOME/.cursor/hooks/_markers"
link_item "bug-complaint-leak" "$HOOKS_SNAPSHOT_DIR/bug-complaint-leak" "$HOME/.cursor/hooks/bug-complaint-leak"
link_item "reflect-on-thrash" "$HOOKS_SNAPSHOT_DIR/reflect-on-thrash" "$HOME/.cursor/hooks/reflect-on-thrash"
link_item "scope-lock" "$HOOKS_SNAPSHOT_DIR/scope-lock" "$HOME/.cursor/hooks/scope-lock"
link_item "auto-pr" "$HOOKS_SNAPSHOT_DIR/auto-pr" "$HOME/.cursor/hooks/auto-pr"
link_item "pr-schema-gate" "$HOOKS_SNAPSHOT_DIR/pr-schema-gate" "$HOME/.cursor/hooks/pr-schema-gate"
link_item "wrong-check-reflect" "$HOOKS_SNAPSHOT_DIR/wrong-check-reflect" "$HOME/.cursor/hooks/wrong-check-reflect"
link_item "llm-judge" "$HOOKS_SNAPSHOT_DIR/llm-judge" "$HOME/.cursor/hooks/llm-judge"
link_item "hook-health" "$HOOKS_SNAPSHOT_DIR/hook-health" "$HOME/.cursor/hooks/hook-health"
link_item "skill-usage-log" "$HOOKS_SNAPSHOT_DIR/skill-usage-log" "$HOME/.cursor/hooks/skill-usage-log"
link_item "build-the-lever" "$HOOKS_SNAPSHOT_DIR/build-the-lever" "$HOME/.cursor/hooks/build-the-lever"
link_item "split-scope" "$HOOKS_SNAPSHOT_DIR/split-scope" "$HOME/.cursor/hooks/split-scope"
link_item "repeat-error-stop" "$HOOKS_SNAPSHOT_DIR/repeat-error-stop" "$HOME/.cursor/hooks/repeat-error-stop"
link_item "ui-input-guard" "$HOOKS_SNAPSHOT_DIR/ui-input-guard" "$HOME/.cursor/hooks/ui-input-guard"
link_item "text-match-decision-warn" "$HOOKS_SNAPSHOT_DIR/text-match-decision-warn" "$HOME/.cursor/hooks/text-match-decision-warn"
link_item "bound-tool-result" "$HOOKS_SNAPSHOT_DIR/bound-tool-result" "$HOME/.cursor/hooks/bound-tool-result"
link_item "unverified-tag-check" "$HOOKS_SNAPSHOT_DIR/unverified-tag-check" "$HOME/.cursor/hooks/unverified-tag-check"
while IFS= read -r hook_name; do
link_item "$hook_name" "$HOOKS_SNAPSHOT_DIR/$hook_name" "$HOME/.cursor/hooks/$hook_name"
done < <(python3 "$REPO_DIR/engine/hooks/_sdk/install_from_registry.py" --list-harness-hooks cursor)

echo "--- codex hooks (\$HOME/.codex/hooks) ---"
mkdir -p "$HOME/.codex/hooks"
install_local_runner "$REPO_DIR/engine/hooks/_runner" "$HOME/.codex/hooks/_runner"
link_item "_flags" "$HOOKS_SNAPSHOT_DIR/_flags" "$HOME/.codex/hooks/_flags"
link_item "_sdk" "$HOOKS_SNAPSHOT_DIR/_sdk" "$HOME/.codex/hooks/_sdk"
link_item "_markers" "$HOOKS_SNAPSHOT_DIR/_markers" "$HOME/.codex/hooks/_markers"
link_item "diu-stop" "$HOOKS_SNAPSHOT_DIR/diu-stop" "$HOME/.codex/hooks/diu-stop"
link_item "scope-lock" "$HOOKS_SNAPSHOT_DIR/scope-lock" "$HOME/.codex/hooks/scope-lock"
link_item "auto-pr" "$HOOKS_SNAPSHOT_DIR/auto-pr" "$HOME/.codex/hooks/auto-pr"
link_item "pr-schema-gate" "$HOOKS_SNAPSHOT_DIR/pr-schema-gate" "$HOME/.codex/hooks/pr-schema-gate"
link_item "wrong-check-reflect" "$HOOKS_SNAPSHOT_DIR/wrong-check-reflect" "$HOME/.codex/hooks/wrong-check-reflect"
link_item "llm-judge" "$HOOKS_SNAPSHOT_DIR/llm-judge" "$HOME/.codex/hooks/llm-judge"
link_item "hook-health" "$HOOKS_SNAPSHOT_DIR/hook-health" "$HOME/.codex/hooks/hook-health"
link_item "skill-usage-log" "$HOOKS_SNAPSHOT_DIR/skill-usage-log" "$HOME/.codex/hooks/skill-usage-log"
link_item "build-the-lever" "$HOOKS_SNAPSHOT_DIR/build-the-lever" "$HOME/.codex/hooks/build-the-lever"
link_item "split-scope" "$HOOKS_SNAPSHOT_DIR/split-scope" "$HOME/.codex/hooks/split-scope"
link_item "repeat-error-stop" "$HOOKS_SNAPSHOT_DIR/repeat-error-stop" "$HOME/.codex/hooks/repeat-error-stop"
link_item "ui-input-guard" "$HOOKS_SNAPSHOT_DIR/ui-input-guard" "$HOME/.codex/hooks/ui-input-guard"
link_item "text-match-decision-warn" "$HOOKS_SNAPSHOT_DIR/text-match-decision-warn" "$HOME/.codex/hooks/text-match-decision-warn"
link_item "bound-tool-result" "$HOOKS_SNAPSHOT_DIR/bound-tool-result" "$HOME/.codex/hooks/bound-tool-result"
link_item "unverified-tag-check" "$HOOKS_SNAPSHOT_DIR/unverified-tag-check" "$HOME/.codex/hooks/unverified-tag-check"
while IFS= read -r hook_name; do
link_item "$hook_name" "$HOOKS_SNAPSHOT_DIR/$hook_name" "$HOME/.codex/hooks/$hook_name"
done < <(python3 "$REPO_DIR/engine/hooks/_sdk/install_from_registry.py" --list-harness-hooks codex)

echo "--- cursor hooks.json (\$HOME/.cursor/hooks.json) ---"
mkdir -p "$HOME/.cursor"
Expand Down
6 changes: 5 additions & 1 deletion scripts/ci/check_install_effective.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,11 @@ def registry_hook_names() -> set[str]:

def active_registry_hook_names() -> set[str]:
registry, _thresholds = load_registry(REPO / "engine/hooks/hooks.toml")
return set(registry)
return {
name
for name, record in registry.items()
if record.mode != "off"
}


def check_hooks_registered() -> list[str]:
Expand Down
6 changes: 5 additions & 1 deletion scripts/install/mirror_stop_hooks_to_subagent_stop.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ def command_prefix(self) -> str:

def active_registry_hooks() -> set[str]:
registry, _thresholds = load_registry()
return set(registry)
return {
name
for name, record in registry.items()
if record.mode != "off"
}


def load_manifests(
Expand Down
12 changes: 5 additions & 7 deletions tests/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def registry_records():
def active_registry_hooks():
return {
name
for name in registry_records()
for name, record in registry_records().items()
if record["mode"] != "off"
if glob.glob(os.path.join(REPO_ROOT, "engine", "hooks", name, "*.hook*.json"))
}

Expand Down Expand Up @@ -737,10 +738,7 @@ def test_skill_usage_log_is_linked_but_not_wired_while_registry_mode_is_off(self
for hooks, event, marker in expected:
with self.subTest(event=event, marker=marker):
matching = [entry for entry in hooks[event] if marker in json.dumps(entry)]
self.assertEqual(len(matching), 1, matching)
self.assertIn("_runner/run.py", json.dumps(matching[0]))
claude_pre = [entry for entry in claude_hooks["PreToolUse"] if "skill-usage-log/" in json.dumps(entry)]
self.assertEqual(claude_pre[0]["matcher"], "Skill|Read|Bash")
self.assertEqual(matching, [])

def test_llm_judge_inbox_wired_for_claude_cursor_and_codex(self):
for agent_dir in (".claude", ".cursor", ".codex"):
Expand Down Expand Up @@ -773,10 +771,10 @@ def test_unverified_tag_check_is_linked_but_not_wired_while_registry_mode_is_off
self.assertTrue(os.path.islink(target), target)
self.assertEqual(os.readlink(target), hook_src(self.fake_home, "unverified-tag-check"))
claude_stop = self._claude_hook_commands("Stop")
self.assertEqual(sum("unverified-tag-check/claude_stop_check.py" in command for command in claude_stop), 1, claude_stop)
self.assertEqual(sum("unverified-tag-check/claude_stop_check.py" in command for command in claude_stop), 0, claude_stop)
with open(os.path.join(self.fake_home, ".cursor", "hooks.json")) as handle:
cursor_stop = json.load(handle)["hooks"]["stop"]
self.assertEqual(sum("unverified-tag-check/cursor_session.py" in str(entry.get("command", "")) for entry in cursor_stop), 1, cursor_stop)
self.assertEqual(sum("unverified-tag-check/cursor_session.py" in str(entry.get("command", "")) for entry in cursor_stop), 0, cursor_stop)
with open(config_path) as handle:
text = handle.read()
self.assertIn('model = "gpt-5"', text)
Expand Down
Loading