mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 13:04:08 +00:00
Add setEditorText/getEditorText to hook UI context, improve custom() API
- Add setEditorText() and getEditorText() to HookUIContext for prompt generator pattern - custom() now accepts async factories for fire-and-forget work - Add CancellableLoader component to tui package - Add BorderedLoader component for hooks with cancel UI - Export HookAPI, HookContext, HookFactory from main package - Update all examples to import from packages instead of relative paths - Update hooks.md and custom-tools.md documentation fixes #350
This commit is contained in:
parent
02d0d6e192
commit
6f7c10e323
39 changed files with 477 additions and 163 deletions
|
|
@ -2,97 +2,53 @@
|
|||
|
||||
Example hooks for pi-coding-agent.
|
||||
|
||||
## Examples
|
||||
|
||||
### permission-gate.ts
|
||||
Prompts for confirmation before running dangerous bash commands (rm -rf, sudo, chmod 777, etc.).
|
||||
|
||||
### git-checkpoint.ts
|
||||
Creates git stash checkpoints at each turn, allowing code restoration when branching.
|
||||
|
||||
### protected-paths.ts
|
||||
Blocks writes to protected paths (.env, .git/, node_modules/).
|
||||
|
||||
### file-trigger.ts
|
||||
Watches a trigger file and injects its contents into the conversation. Useful for external systems (CI, file watchers, webhooks) to send messages to the agent.
|
||||
|
||||
### confirm-destructive.ts
|
||||
Prompts for confirmation before destructive session actions (clear, switch, branch). Demonstrates how to cancel `before_*` session events.
|
||||
|
||||
### dirty-repo-guard.ts
|
||||
Prevents session changes when there are uncommitted git changes. Blocks clear/switch/branch until you commit.
|
||||
|
||||
### auto-commit-on-exit.ts
|
||||
Automatically commits changes when the agent exits (shutdown event). Uses the last assistant message to generate a commit message.
|
||||
|
||||
### custom-compaction.ts
|
||||
Custom context compaction that summarizes the entire conversation instead of keeping recent turns. Uses the `before_compact` hook event to intercept compaction and generate a comprehensive summary using `complete()` from the AI package. Useful when you want maximum context window space at the cost of losing exact conversation history.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Test directly
|
||||
# Load a hook with --hook flag
|
||||
pi --hook examples/hooks/permission-gate.ts
|
||||
|
||||
# Or copy to hooks directory for persistent use
|
||||
# Or copy to hooks directory for auto-discovery
|
||||
cp permission-gate.ts ~/.pi/agent/hooks/
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
| Hook | Description |
|
||||
|------|-------------|
|
||||
| `permission-gate.ts` | Prompts for confirmation before dangerous bash commands (rm -rf, sudo, etc.) |
|
||||
| `git-checkpoint.ts` | Creates git stash checkpoints at each turn for code restoration on branch |
|
||||
| `protected-paths.ts` | Blocks writes to protected paths (.env, .git/, node_modules/) |
|
||||
| `file-trigger.ts` | Watches a trigger file and injects contents into conversation |
|
||||
| `confirm-destructive.ts` | Confirms before destructive session actions (clear, switch, branch) |
|
||||
| `dirty-repo-guard.ts` | Prevents session changes with uncommitted git changes |
|
||||
| `auto-commit-on-exit.ts` | Auto-commits on exit using last assistant message for commit message |
|
||||
| `custom-compaction.ts` | Custom compaction that summarizes entire conversation |
|
||||
| `qna.ts` | Extracts questions from last response into editor via `ctx.ui.setEditorText()` |
|
||||
| `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
|
||||
|
||||
## Writing Hooks
|
||||
|
||||
See [docs/hooks.md](../../docs/hooks.md) for full documentation.
|
||||
|
||||
### Key Points
|
||||
|
||||
**Hook structure:**
|
||||
```typescript
|
||||
import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
||||
|
||||
export default function (pi: HookAPI) {
|
||||
pi.on("session", async (event, ctx) => {
|
||||
// event.reason: "start" | "before_switch" | "switch" | "before_clear" | "clear" |
|
||||
// "before_branch" | "branch" | "shutdown"
|
||||
// event.targetTurnIndex: number (only for before_branch/branch)
|
||||
// ctx.ui, ctx.exec, ctx.cwd, ctx.sessionFile, ctx.hasUI
|
||||
|
||||
// Cancel before_* actions:
|
||||
if (event.reason === "before_clear") {
|
||||
return { cancel: true };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// Subscribe to events
|
||||
pi.on("tool_call", async (event, ctx) => {
|
||||
// Can block tool execution
|
||||
if (dangerous) {
|
||||
return { block: true, reason: "Blocked" };
|
||||
if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
|
||||
const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
|
||||
if (!ok) return { block: true, reason: "Blocked by user" };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
pi.on("tool_result", async (event, ctx) => {
|
||||
// Can modify result
|
||||
return { result: "modified result" };
|
||||
// Register custom commands
|
||||
pi.registerCommand("hello", {
|
||||
description: "Say hello",
|
||||
handler: async (args, ctx) => {
|
||||
ctx.ui.notify("Hello!", "info");
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Available events:**
|
||||
- `session` - lifecycle events with before/after variants (can cancel before_* actions)
|
||||
- `agent_start` / `agent_end` - per user prompt
|
||||
- `turn_start` / `turn_end` - per LLM turn
|
||||
- `tool_call` - before tool execution (can block)
|
||||
- `tool_result` - after tool execution (can modify)
|
||||
|
||||
**UI methods:**
|
||||
```typescript
|
||||
const choice = await ctx.ui.select("Title", ["Option A", "Option B"]);
|
||||
const confirmed = await ctx.ui.confirm("Title", "Are you sure?");
|
||||
const input = await ctx.ui.input("Title", "placeholder");
|
||||
ctx.ui.notify("Message", "info"); // or "warning", "error"
|
||||
```
|
||||
|
||||
**Sending messages:**
|
||||
```typescript
|
||||
pi.send("Message to inject into conversation");
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue