feat(coding-agent): add hook API for CLI flags, shortcuts, and tool control

Hook API additions:
- pi.getTools() / pi.setTools(toolNames) - dynamically enable/disable tools
- pi.registerFlag(name, options) / pi.getFlag(name) - register custom CLI flags
- pi.registerShortcut(shortcut, options) - register keyboard shortcuts

Plan mode hook (examples/hooks/plan-mode.ts):
- /plan command or Shift+P shortcut to toggle
- --plan CLI flag to start in plan mode
- Read-only tools: read, bash, grep, find, ls
- Bash restricted to non-destructive commands (blocks rm, mv, git commit, etc.)
- Interactive prompt after each response: execute, stay, or refine
- Shows plan indicator in footer when active
- State persists across sessions
This commit is contained in:
Helmut Januschka 2026-01-03 09:52:13 +01:00 committed by Mario Zechner
parent 059292ead1
commit c956a726ed
13 changed files with 636 additions and 46 deletions

View file

@ -78,10 +78,14 @@ describe.skipIf(!API_KEY)("Compaction hooks", () => {
handlers,
messageRenderers: new Map(),
commands: new Map(),
flags: new Map(),
flagValues: new Map(),
shortcuts: new Map(),
setSendMessageHandler: () => {},
setAppendEntryHandler: () => {},
setGetToolsHandler: () => {},
setSetToolsHandler: () => {},
setFlagValue: () => {},
};
}
@ -269,10 +273,14 @@ describe.skipIf(!API_KEY)("Compaction hooks", () => {
]),
messageRenderers: new Map(),
commands: new Map(),
flags: new Map(),
flagValues: new Map(),
shortcuts: new Map(),
setSendMessageHandler: () => {},
setAppendEntryHandler: () => {},
setGetToolsHandler: () => {},
setSetToolsHandler: () => {},
setFlagValue: () => {},
};
createSession([throwingHook]);
@ -318,10 +326,14 @@ describe.skipIf(!API_KEY)("Compaction hooks", () => {
]),
messageRenderers: new Map(),
commands: new Map(),
flags: new Map(),
flagValues: new Map(),
shortcuts: new Map(),
setSendMessageHandler: () => {},
setAppendEntryHandler: () => {},
setGetToolsHandler: () => {},
setSetToolsHandler: () => {},
setFlagValue: () => {},
};
const hook2: LoadedHook = {
@ -349,10 +361,14 @@ describe.skipIf(!API_KEY)("Compaction hooks", () => {
]),
messageRenderers: new Map(),
commands: new Map(),
flags: new Map(),
flagValues: new Map(),
shortcuts: new Map(),
setSendMessageHandler: () => {},
setAppendEntryHandler: () => {},
setGetToolsHandler: () => {},
setSetToolsHandler: () => {},
setFlagValue: () => {},
};
createSession([hook1, hook2]);