mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 15:02:32 +00:00
Custom tools with session lifecycle, examples for hooks and tools
- Custom tools: TypeScript modules that extend pi with new tools - Custom TUI rendering via renderCall/renderResult - User interaction via pi.ui (select, confirm, input, notify) - Session lifecycle via onSession callback for state reconstruction - Examples: todo.ts, question.ts, hello.ts - Hook examples: permission-gate, git-checkpoint, protected-paths - Session lifecycle centralized in AgentSession - Works across all modes (interactive, print, RPC) - Unified session event for hooks (replaces session_start/session_switch) - Box component added to pi-tui - Examples bundled in npm and binary releases Fixes #190
This commit is contained in:
parent
295f51b53f
commit
e7097d911a
33 changed files with 1926 additions and 117 deletions
76
packages/coding-agent/examples/hooks/README.md
Normal file
76
packages/coding-agent/examples/hooks/README.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Hooks Examples
|
||||
|
||||
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/).
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Test directly
|
||||
pi --hook examples/hooks/permission-gate.ts
|
||||
|
||||
# Or copy to hooks directory for persistent use
|
||||
cp permission-gate.ts ~/.pi/agent/hooks/
|
||||
```
|
||||
|
||||
## 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" | "switch" | "clear"
|
||||
// ctx.ui, ctx.exec, ctx.cwd, ctx.sessionFile, ctx.hasUI
|
||||
});
|
||||
|
||||
pi.on("tool_call", async (event, ctx) => {
|
||||
// Can block tool execution
|
||||
if (dangerous) {
|
||||
return { block: true, reason: "Blocked" };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
pi.on("tool_result", async (event, ctx) => {
|
||||
// Can modify result
|
||||
return { result: "modified result" };
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Available events:**
|
||||
- `session` - startup, session switch, clear
|
||||
- `branch` - before branching (can skip conversation restore)
|
||||
- `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