Activation fixes for the single-session presence gate. Two bugs blocked it,
both caught by live testing after all units were green:
1) Wrong branch key. presence_gate used Path.cwd().name, but under the Claude
Code bridge the hook process cwd is the project root, so every session keyed
to "AIPass": the gate never enforced one-live-session-per-branch and would
have rejected sessions project-globally (any 2nd interactive session in any
branch). Now _resolve_branch(hook_data) reads the event payload's cwd (the
real session dir) and walks up to the branch root (.trinity/ or apps/),
mirroring branch_loader. Applied in handle() and handle_stop().
2) Block never reached Claude Code. engine.dispatch() returned only stdout, so
the bridge could not surface a non-zero exit. dispatch() now returns
(stdout, exit_code) and the bridge exits with it on a block. Pre-existing gap
affecting every block hook on every event; now fixed engine-wide. An
intentional block (exit 2 + {"decision":"block"}) propagates; a crashing hook
(exit 2, non-JSON stdout) is logged and falls through, so the gate fails open.
Proven: 110 hooks unit tests pass (6 new for branch resolution); seedgo @hooks
100%, no type errors. Live bridge end-to-end (real live holder + real bridge):
duplicate into a held branch -> exit 2 + block reason naming the branch; a
different free branch -> exit 0 (per-branch isolation intact). Gate remains
dormant: not yet wired into provider settings.
Design: DPLAN-0225 / FPLAN-0289 P1 activation. Build by @hooks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CqoxFdbDMirzkQ5kjRVVos
143 lines
3.8 KiB
JSON
143 lines
3.8 KiB
JSON
{
|
|
"_comment": "Per-project hook configuration for the AIPass hook engine (DPLAN-0184)",
|
|
"hooks_enabled": true,
|
|
|
|
"UserPromptSubmit": {
|
|
"presence_gate": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.security.presence_gate.handle",
|
|
"matcher": ""
|
|
},
|
|
"identity_injector": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.prompt.identity.handle",
|
|
"matcher": ""
|
|
},
|
|
"email_notification": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.notification.email.handle",
|
|
"matcher": ""
|
|
},
|
|
"branch_prompt": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.prompt.branch_loader.handle",
|
|
"matcher": ""
|
|
},
|
|
"tier0_kernel": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.prompt.tier0_kernel.handle",
|
|
"matcher": ""
|
|
},
|
|
"navmap": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.prompt.navmap.handle",
|
|
"matcher": ""
|
|
},
|
|
"auto_process": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.lifecycle.auto_process.handle",
|
|
"matcher": "",
|
|
"timeout": 120
|
|
}
|
|
},
|
|
|
|
"PreToolUse": {
|
|
"tool_use_sound": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.notification.tool_sound.handle",
|
|
"matcher": "Bash|Edit|MultiEdit|Write|Read|Grep|Glob|WebSearch|WebFetch|Task"
|
|
},
|
|
"pre_edit_gate": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.security.edit_gate.handle",
|
|
"matcher": "Edit|MultiEdit|Write|NotebookEdit"
|
|
},
|
|
"git_gate": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.security.git_gate.handle",
|
|
"matcher": "Bash|Edit|MultiEdit|Write|NotebookEdit"
|
|
},
|
|
"rm_gate": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.security.rm_gate.handle",
|
|
"matcher": "Bash"
|
|
},
|
|
"engine_test_sound": {
|
|
"enabled": false,
|
|
"command": "python3 $AIPASS_HOME/.claude/hooks/engine_test_sound.py",
|
|
"matcher": "WebSearch"
|
|
}
|
|
},
|
|
|
|
"PostToolUse": {
|
|
"auto_fix_diagnostics": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.lifecycle.auto_fix.handle",
|
|
"matcher": "Edit|MultiEdit|Write|NotebookEdit",
|
|
"timeout": 45
|
|
},
|
|
"auto_watchdog": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.lifecycle.auto_watchdog.handle",
|
|
"matcher": "Bash"
|
|
}
|
|
},
|
|
|
|
"SubagentStop": {
|
|
"subagent_stop_gate": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.security.subagent_gate.handle",
|
|
"matcher": "",
|
|
"timeout": 60
|
|
}
|
|
},
|
|
|
|
"Stop": {
|
|
"stop_sound": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.notification.stop_sound.handle",
|
|
"matcher": ""
|
|
},
|
|
"telegram_response": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.notification.telegram_response.handle",
|
|
"matcher": "",
|
|
"timeout": 30
|
|
},
|
|
"presence_release": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.security.presence_gate.handle_stop",
|
|
"matcher": ""
|
|
}
|
|
},
|
|
|
|
"Notification": {
|
|
"notification_sound": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.notification.announce.handle",
|
|
"matcher": ""
|
|
}
|
|
},
|
|
|
|
"PreCompact": {
|
|
"pre_compact": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.lifecycle.compact.handle",
|
|
"matcher": "",
|
|
"timeout": 60
|
|
},
|
|
"pre_compact_rollover": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.lifecycle.rollover.handle",
|
|
"matcher": "",
|
|
"timeout": 120
|
|
},
|
|
"auto_process": {
|
|
"enabled": true,
|
|
"handler": "aipass.hooks.apps.handlers.lifecycle.auto_process.handle",
|
|
"matcher": "",
|
|
"timeout": 120
|
|
}
|
|
}
|
|
}
|