@mariozechner/pi-coding-agent 0.30.2 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +244 -1
- package/README.md +105 -84
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +5 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts +3 -3
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +7 -10
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +73 -34
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +464 -210
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -2
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +2 -2
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts +2 -2
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +2 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +84 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
- package/dist/core/compaction/branch-summarization.js +233 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -0
- package/dist/core/{compaction.d.ts → compaction/compaction.d.ts} +38 -19
- package/dist/core/compaction/compaction.d.ts.map +1 -0
- package/dist/core/compaction/compaction.js +558 -0
- package/dist/core/compaction/compaction.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -0
- package/dist/core/compaction/index.d.ts.map +1 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/index.js.map +1 -0
- package/dist/core/compaction/utils.d.ts +35 -0
- package/dist/core/compaction/utils.d.ts.map +1 -0
- package/dist/core/compaction/utils.js +138 -0
- package/dist/core/compaction/utils.js.map +1 -0
- package/dist/core/custom-tools/index.d.ts +2 -1
- package/dist/core/custom-tools/index.d.ts.map +1 -1
- package/dist/core/custom-tools/index.js +1 -0
- package/dist/core/custom-tools/index.js.map +1 -1
- package/dist/core/custom-tools/loader.d.ts.map +1 -1
- package/dist/core/custom-tools/loader.js +13 -80
- package/dist/core/custom-tools/loader.js.map +1 -1
- package/dist/core/custom-tools/types.d.ts +84 -59
- package/dist/core/custom-tools/types.d.ts.map +1 -1
- package/dist/core/custom-tools/types.js.map +1 -1
- package/dist/core/custom-tools/wrapper.d.ts +15 -0
- package/dist/core/custom-tools/wrapper.d.ts.map +1 -0
- package/dist/core/custom-tools/wrapper.js +23 -0
- package/dist/core/custom-tools/wrapper.js.map +1 -0
- package/dist/core/exec.d.ts +29 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +71 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/export-html/index.d.ts +17 -0
- package/dist/core/export-html/index.d.ts.map +1 -0
- package/dist/core/export-html/index.js +171 -0
- package/dist/core/export-html/index.js.map +1 -0
- package/dist/core/export-html/template.css +781 -0
- package/dist/core/export-html/template.html +54 -0
- package/dist/core/export-html/template.js +1185 -0
- package/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/dist/core/export-html/vendor/marked.min.js +6 -0
- package/dist/core/hooks/index.d.ts +4 -4
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js +3 -3
- package/dist/core/hooks/index.js.map +1 -1
- package/dist/core/hooks/loader.d.ts +40 -5
- package/dist/core/hooks/loader.d.ts.map +1 -1
- package/dist/core/hooks/loader.js +43 -10
- package/dist/core/hooks/loader.js.map +1 -1
- package/dist/core/hooks/runner.d.ts +94 -18
- package/dist/core/hooks/runner.d.ts.map +1 -1
- package/dist/core/hooks/runner.js +199 -120
- package/dist/core/hooks/runner.js.map +1 -1
- package/dist/core/hooks/tool-wrapper.d.ts +1 -1
- package/dist/core/hooks/tool-wrapper.d.ts.map +1 -1
- package/dist/core/hooks/tool-wrapper.js +36 -19
- package/dist/core/hooks/tool-wrapper.js.map +1 -1
- package/dist/core/hooks/types.d.ts +407 -96
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/core/index.d.ts +4 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +44 -12
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +82 -34
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -5
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +7 -7
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +7 -7
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +45 -14
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/sdk.d.ts +7 -10
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +88 -32
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +202 -36
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +565 -133
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +9 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +13 -12
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +6 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +33 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -0
- package/dist/core/tools/edit-diff.js +171 -0
- package/dist/core/tools/edit-diff.js.map +1 -0
- package/dist/core/tools/edit.d.ts +7 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +20 -95
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +22 -21
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +3 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +6 -2
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +12 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.js +30 -0
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts +14 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.js +35 -0
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +14 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +36 -0
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +5 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +5 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +12 -6
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +57 -25
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/hook-editor.d.ts +15 -0
- package/dist/modes/interactive/components/hook-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/hook-editor.js +95 -0
- package/dist/modes/interactive/components/hook-editor.js.map +1 -0
- package/dist/modes/interactive/components/hook-message.d.ts +18 -0
- package/dist/modes/interactive/components/hook-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/hook-message.js +80 -0
- package/dist/modes/interactive/components/hook-message.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +3 -3
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +15 -2
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +70 -21
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +52 -0
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector.js +745 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +3 -3
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +2 -5
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +29 -12
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +589 -208
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +13 -1
- package/dist/modes/interactive/theme/light.json +13 -1
- package/dist/modes/interactive/theme/theme-schema.json +34 -0
- package/dist/modes/interactive/theme/theme.d.ts +20 -2
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +135 -2
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts +3 -3
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +26 -20
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +13 -10
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +11 -10
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +88 -35
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +30 -11
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/shell.d.ts +4 -2
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +36 -7
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +2 -2
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/compaction.md +388 -0
- package/docs/custom-tools.md +146 -43
- package/docs/extension-loading.md +1004 -0
- package/docs/hooks.md +562 -596
- package/docs/rpc.md +33 -19
- package/docs/sdk.md +93 -21
- package/docs/session-tree-plan.md +441 -0
- package/docs/session.md +172 -21
- package/docs/skills.md +2 -0
- package/docs/theme.md +31 -2
- package/docs/tree.md +197 -0
- package/docs/tui.md +343 -0
- package/examples/README.md +1 -9
- package/examples/custom-tools/hello/index.ts +4 -3
- package/examples/custom-tools/question/index.ts +4 -4
- package/examples/custom-tools/subagent/index.ts +7 -6
- package/examples/custom-tools/todo/index.ts +11 -5
- package/examples/hooks/README.md +29 -71
- package/examples/hooks/auto-commit-on-exit.ts +8 -9
- package/examples/hooks/confirm-destructive.ts +29 -30
- package/examples/hooks/custom-compaction.ts +20 -21
- package/examples/hooks/dirty-repo-guard.ts +41 -40
- package/examples/hooks/file-trigger.ts +10 -5
- package/examples/hooks/git-checkpoint.ts +16 -12
- package/examples/hooks/handoff.ts +150 -0
- package/examples/hooks/permission-gate.ts +1 -1
- package/examples/hooks/protected-paths.ts +1 -1
- package/examples/hooks/qna.ts +119 -0
- package/examples/hooks/snake.ts +343 -0
- package/examples/hooks/status-line.ts +40 -0
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/02-custom-model.ts +1 -1
- package/examples/sdk/03-custom-prompt.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/05-tools.ts +4 -4
- package/examples/sdk/06-hooks.ts +1 -1
- package/examples/sdk/07-context-files.ts +1 -1
- package/examples/sdk/08-slash-commands.ts +6 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
- package/examples/sdk/10-settings.ts +1 -1
- package/examples/sdk/11-sessions.ts +1 -1
- package/examples/sdk/12-full-control.ts +4 -7
- package/package.json +6 -6
- package/dist/core/compaction.d.ts.map +0 -1
- package/dist/core/compaction.js +0 -412
- package/dist/core/compaction.js.map +0 -1
- package/dist/core/export-html.d.ts +0 -23
- package/dist/core/export-html.d.ts.map +0 -1
- package/dist/core/export-html.js +0 -1185
- package/dist/core/export-html.js.map +0 -1
- package/dist/modes/interactive/components/compaction.d.ts +0 -15
- package/dist/modes/interactive/components/compaction.d.ts.map +0 -1
- package/dist/modes/interactive/components/compaction.js +0 -41
- package/dist/modes/interactive/components/compaction.js.map +0 -1
- package/docs/hooks-v2.md +0 -385
- package/docs/session-tree.md +0 -452
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,249 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [0.31.0] - 2026-01-02
|
|
4
|
+
|
|
5
|
+
This release introduces session trees for in-place branching, major API changes to hooks and custom tools, and structured compaction with file tracking.
|
|
6
|
+
|
|
7
|
+
### Session Tree
|
|
8
|
+
|
|
9
|
+
Sessions now use a tree structure with `id`/`parentId` fields. This enables in-place branching: navigate to any previous point with `/tree`, continue from there, and switch between branches while preserving all history in a single file.
|
|
10
|
+
|
|
11
|
+
**Existing sessions are automatically migrated** (v1 → v2) on first load. No manual action required.
|
|
12
|
+
|
|
13
|
+
New entry types: `BranchSummaryEntry` (context from abandoned branches), `CustomEntry` (hook state), `CustomMessageEntry` (hook-injected messages), `LabelEntry` (bookmarks).
|
|
14
|
+
|
|
15
|
+
See [docs/session.md](docs/session.md) for the file format and `SessionManager` API.
|
|
16
|
+
|
|
17
|
+
### Hooks Migration
|
|
18
|
+
|
|
19
|
+
The hooks API has been restructured with more granular events and better session access.
|
|
20
|
+
|
|
21
|
+
**Type renames:**
|
|
22
|
+
- `HookEventContext` → `HookContext`
|
|
23
|
+
- `HookCommandContext` is now a new interface extending `HookContext` with session control methods
|
|
24
|
+
|
|
25
|
+
**Event changes:**
|
|
26
|
+
- The monolithic `session` event is now split into granular events: `session_start`, `session_before_switch`, `session_switch`, `session_before_branch`, `session_branch`, `session_before_compact`, `session_compact`, `session_shutdown`
|
|
27
|
+
- `session_before_switch` and `session_switch` events now include `reason: "new" | "resume"` to distinguish between `/new` and `/resume`
|
|
28
|
+
- New `session_before_tree` and `session_tree` events for `/tree` navigation (hook can provide custom branch summary)
|
|
29
|
+
- New `before_agent_start` event: inject messages before the agent loop starts
|
|
30
|
+
- New `context` event: modify messages non-destructively before each LLM call
|
|
31
|
+
- Session entries are no longer passed in events. Use `ctx.sessionManager.getEntries()` or `ctx.sessionManager.getBranch()` instead
|
|
32
|
+
|
|
33
|
+
**API changes:**
|
|
34
|
+
- `pi.send(text, attachments?)` → `pi.sendMessage(message, triggerTurn?)` (creates `CustomMessageEntry`)
|
|
35
|
+
- New `pi.appendEntry(customType, data?)` for hook state persistence (not in LLM context)
|
|
36
|
+
- New `pi.registerCommand(name, options)` for custom slash commands (handler receives `HookCommandContext`)
|
|
37
|
+
- New `pi.registerMessageRenderer(customType, renderer)` for custom TUI rendering
|
|
38
|
+
- New `ctx.isIdle()`, `ctx.abort()`, `ctx.hasQueuedMessages()` for agent state (available in all events)
|
|
39
|
+
- New `ctx.ui.editor(title, prefill?)` for multi-line text editing with Ctrl+G external editor support
|
|
40
|
+
- New `ctx.ui.custom(component)` for full TUI component rendering with keyboard focus
|
|
41
|
+
- New `ctx.ui.setStatus(key, text)` for persistent status text in footer (multiple hooks can set their own)
|
|
42
|
+
- New `ctx.ui.theme` getter for styling text with theme colors
|
|
43
|
+
- `ctx.exec()` moved to `pi.exec()`
|
|
44
|
+
- `ctx.sessionFile` → `ctx.sessionManager.getSessionFile()`
|
|
45
|
+
- New `ctx.modelRegistry` and `ctx.model` for API key resolution
|
|
46
|
+
|
|
47
|
+
**HookCommandContext (slash commands only):**
|
|
48
|
+
- `ctx.waitForIdle()` - wait for agent to finish streaming
|
|
49
|
+
- `ctx.newSession(options?)` - create new sessions with optional setup callback
|
|
50
|
+
- `ctx.branch(entryId)` - branch from a specific entry
|
|
51
|
+
- `ctx.navigateTree(targetId, options?)` - navigate the session tree
|
|
52
|
+
|
|
53
|
+
These methods are only on `HookCommandContext` (not `HookContext`) because they can deadlock if called from event handlers that run inside the agent loop.
|
|
54
|
+
|
|
55
|
+
**Removed:**
|
|
56
|
+
- `hookTimeout` setting (hooks no longer have timeouts; use Ctrl+C to abort)
|
|
57
|
+
- `resolveApiKey` parameter (use `ctx.modelRegistry.getApiKey(model)`)
|
|
58
|
+
|
|
59
|
+
See [docs/hooks.md](docs/hooks.md) and [examples/hooks/](examples/hooks/) for the current API.
|
|
60
|
+
|
|
61
|
+
### Custom Tools Migration
|
|
62
|
+
|
|
63
|
+
The custom tools API has been restructured to mirror the hooks pattern with a context object.
|
|
64
|
+
|
|
65
|
+
**Type renames:**
|
|
66
|
+
- `CustomAgentTool` → `CustomTool`
|
|
67
|
+
- `ToolAPI` → `CustomToolAPI`
|
|
68
|
+
- `ToolContext` → `CustomToolContext`
|
|
69
|
+
- `ToolSessionEvent` → `CustomToolSessionEvent`
|
|
70
|
+
|
|
71
|
+
**Execute signature changed:**
|
|
72
|
+
```typescript
|
|
73
|
+
// Before (v0.30.2)
|
|
74
|
+
execute(toolCallId, params, signal, onUpdate)
|
|
75
|
+
|
|
76
|
+
// After
|
|
77
|
+
execute(toolCallId, params, onUpdate, ctx, signal?)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The new `ctx: CustomToolContext` provides `sessionManager`, `modelRegistry`, `model`, and agent state methods:
|
|
81
|
+
- `ctx.isIdle()` - check if agent is streaming
|
|
82
|
+
- `ctx.hasQueuedMessages()` - check if user has queued messages (skip interactive prompts)
|
|
83
|
+
- `ctx.abort()` - abort current operation (fire-and-forget)
|
|
84
|
+
|
|
85
|
+
**Session event changes:**
|
|
86
|
+
- `CustomToolSessionEvent` now only has `reason` and `previousSessionFile`
|
|
87
|
+
- Session entries are no longer in the event. Use `ctx.sessionManager.getBranch()` or `ctx.sessionManager.getEntries()` to reconstruct state
|
|
88
|
+
- Reasons: `"start" | "switch" | "branch" | "tree" | "shutdown"` (no separate `"new"` reason; `/new` triggers `"switch"`)
|
|
89
|
+
- `dispose()` method removed. Use `onSession` with `reason: "shutdown"` for cleanup
|
|
90
|
+
|
|
91
|
+
See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](examples/custom-tools/) for the current API.
|
|
92
|
+
|
|
93
|
+
### SDK Migration
|
|
94
|
+
|
|
95
|
+
**Type changes:**
|
|
96
|
+
- `CustomAgentTool` → `CustomTool`
|
|
97
|
+
- `AppMessage` → `AgentMessage`
|
|
98
|
+
- `sessionFile` returns `string | undefined` (was `string | null`)
|
|
99
|
+
- `model` returns `Model | undefined` (was `Model | null`)
|
|
100
|
+
- `Attachment` type removed. Use `ImageContent` from `@mariozechner/pi-ai` instead. Add images directly to message content arrays.
|
|
101
|
+
|
|
102
|
+
**AgentSession API:**
|
|
103
|
+
- `branch(entryIndex: number)` → `branch(entryId: string)`
|
|
104
|
+
- `getUserMessagesForBranching()` returns `{ entryId, text }` instead of `{ entryIndex, text }`
|
|
105
|
+
- `reset()` → `newSession(options?)` where options has optional `parentSession` for lineage tracking
|
|
106
|
+
- `newSession()` and `switchSession()` now return `Promise<boolean>` (false if cancelled by hook)
|
|
107
|
+
- New `navigateTree(targetId, options?)` for in-place tree navigation
|
|
108
|
+
|
|
109
|
+
**Hook integration:**
|
|
110
|
+
- New `sendHookMessage(message, triggerTurn?)` for hook message injection
|
|
111
|
+
|
|
112
|
+
**SessionManager API:**
|
|
113
|
+
- Method renames: `saveXXX()` → `appendXXX()` (e.g., `appendMessage`, `appendCompaction`)
|
|
114
|
+
- `branchInPlace()` → `branch()`
|
|
115
|
+
- `reset()` → `newSession(options?)` with optional `parentSession` for lineage tracking
|
|
116
|
+
- `createBranchedSessionFromEntries(entries, index)` → `createBranchedSession(leafId)`
|
|
117
|
+
- `SessionHeader.branchedFrom` → `SessionHeader.parentSession`
|
|
118
|
+
- `saveCompaction(entry)` → `appendCompaction(summary, firstKeptEntryId, tokensBefore, details?)`
|
|
119
|
+
- `getEntries()` now excludes the session header (use `getHeader()` separately)
|
|
120
|
+
- `getSessionFile()` returns `string | undefined` (undefined for in-memory sessions)
|
|
121
|
+
- New tree methods: `getTree()`, `getBranch()`, `getLeafId()`, `getLeafEntry()`, `getEntry()`, `getChildren()`, `getLabel()`
|
|
122
|
+
- New append methods: `appendCustomEntry()`, `appendCustomMessageEntry()`, `appendLabelChange()`
|
|
123
|
+
- New branch methods: `branch(entryId)`, `branchWithSummary()`
|
|
124
|
+
|
|
125
|
+
**ModelRegistry (new):**
|
|
126
|
+
|
|
127
|
+
`ModelRegistry` is a new class that manages model discovery and API key resolution. It combines built-in models with custom models from `models.json` and resolves API keys via `AuthStorage`.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
|
|
131
|
+
|
|
132
|
+
const authStorage = discoverAuthStorage(); // ~/.pi/agent/auth.json
|
|
133
|
+
const modelRegistry = discoverModels(authStorage); // + ~/.pi/agent/models.json
|
|
134
|
+
|
|
135
|
+
// Get all models (built-in + custom)
|
|
136
|
+
const allModels = modelRegistry.getAll();
|
|
137
|
+
|
|
138
|
+
// Get only models with valid API keys
|
|
139
|
+
const available = await modelRegistry.getAvailable();
|
|
140
|
+
|
|
141
|
+
// Find specific model
|
|
142
|
+
const model = modelRegistry.find("anthropic", "claude-sonnet-4-20250514");
|
|
143
|
+
|
|
144
|
+
// Get API key for a model
|
|
145
|
+
const apiKey = await modelRegistry.getApiKey(model);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
This replaces the old `resolveApiKey` callback pattern. Hooks and custom tools access it via `ctx.modelRegistry`.
|
|
149
|
+
|
|
150
|
+
**Renamed exports:**
|
|
151
|
+
- `messageTransformer` → `convertToLlm`
|
|
152
|
+
- `SessionContext` alias `LoadedSession` removed
|
|
153
|
+
|
|
154
|
+
See [docs/sdk.md](docs/sdk.md) and [examples/sdk/](examples/sdk/) for the current API.
|
|
155
|
+
|
|
156
|
+
### RPC Migration
|
|
157
|
+
|
|
158
|
+
**Session commands:**
|
|
159
|
+
- `reset` command → `new_session` command with optional `parentSession` field
|
|
160
|
+
|
|
161
|
+
**Branching commands:**
|
|
162
|
+
- `branch` command: `entryIndex` → `entryId`
|
|
163
|
+
- `get_branch_messages` response: `entryIndex` → `entryId`
|
|
164
|
+
|
|
165
|
+
**Type changes:**
|
|
166
|
+
- Messages are now `AgentMessage` (was `AppMessage`)
|
|
167
|
+
- `prompt` command: `attachments` field replaced with `images` field using `ImageContent` format
|
|
168
|
+
|
|
169
|
+
**Compaction events:**
|
|
170
|
+
- `auto_compaction_start` now includes `reason` field (`"threshold"` or `"overflow"`)
|
|
171
|
+
- `auto_compaction_end` now includes `willRetry` field
|
|
172
|
+
- `compact` response includes full `CompactionResult` (`summary`, `firstKeptEntryId`, `tokensBefore`, `details`)
|
|
173
|
+
|
|
174
|
+
See [docs/rpc.md](docs/rpc.md) for the current protocol.
|
|
175
|
+
|
|
176
|
+
### Structured Compaction
|
|
177
|
+
|
|
178
|
+
Compaction and branch summarization now use a structured output format:
|
|
179
|
+
- Clear sections: Goal, Progress, Key Information, File Operations
|
|
180
|
+
- File tracking: `readFiles` and `modifiedFiles` arrays in `details`, accumulated across compactions
|
|
181
|
+
- Conversations are serialized to text before summarization to prevent the model from "continuing" them
|
|
182
|
+
|
|
183
|
+
The `before_compact` and `before_tree` hook events allow custom compaction implementations. See [docs/compaction.md](docs/compaction.md).
|
|
184
|
+
|
|
185
|
+
### Interactive Mode
|
|
186
|
+
|
|
187
|
+
**`/tree` command:**
|
|
188
|
+
- Navigate the full session tree in-place
|
|
189
|
+
- Search by typing, page with ←/→
|
|
190
|
+
- Filter modes (Ctrl+O): default → no-tools → user-only → labeled-only → all
|
|
191
|
+
- Press `l` to label entries as bookmarks
|
|
192
|
+
- Selecting a branch switches context and optionally injects a summary of the abandoned branch
|
|
193
|
+
|
|
194
|
+
**Entry labels:**
|
|
195
|
+
- Bookmark any entry via `/tree` → select → `l`
|
|
196
|
+
- Labels appear in tree view and persist as `LabelEntry`
|
|
197
|
+
|
|
198
|
+
**Theme changes (breaking for custom themes):**
|
|
199
|
+
|
|
200
|
+
Custom themes must add these new color tokens or they will fail to load:
|
|
201
|
+
- `selectedBg`: background for selected/highlighted items in tree selector and other components
|
|
202
|
+
- `customMessageBg`: background for hook-injected messages (`CustomMessageEntry`)
|
|
203
|
+
- `customMessageText`: text color for hook messages
|
|
204
|
+
- `customMessageLabel`: label color for hook messages (the `[customType]` prefix)
|
|
205
|
+
|
|
206
|
+
Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) for the full color list and copy values from the built-in dark/light themes.
|
|
207
|
+
|
|
208
|
+
**Settings:**
|
|
209
|
+
- `enabledModels`: allowlist models in `settings.json` (same format as `--models` CLI)
|
|
210
|
+
|
|
211
|
+
### Added
|
|
212
|
+
|
|
213
|
+
- `ctx.ui.setStatus(key, text)` for hooks to display persistent status text in the footer ([#385](https://github.com/badlogic/pi-mono/pull/385) by [@prateekmedia](https://github.com/prateekmedia))
|
|
214
|
+
- `ctx.ui.theme` getter for styling status text and other output with theme colors
|
|
215
|
+
- `/share` command to upload session as a secret GitHub gist and get a shareable URL via shittycodingagent.ai ([#380](https://github.com/badlogic/pi-mono/issues/380))
|
|
216
|
+
- HTML export now includes a tree visualization sidebar for navigating session branches ([#375](https://github.com/badlogic/pi-mono/issues/375))
|
|
217
|
+
- HTML export supports keyboard shortcuts: Ctrl+T to toggle thinking blocks, Ctrl+O to toggle tool outputs
|
|
218
|
+
- HTML export supports theme-configurable background colors via optional `export` section in theme JSON ([#387](https://github.com/badlogic/pi-mono/pull/387) by [@mitsuhiko](https://github.com/mitsuhiko))
|
|
219
|
+
- HTML export syntax highlighting now uses theme colors and matches TUI rendering
|
|
220
|
+
- **Snake game example hook**: Demonstrates `ui.custom()`, `registerCommand()`, and session persistence. See [examples/hooks/snake.ts](examples/hooks/snake.ts).
|
|
221
|
+
- **`thinkingText` theme token**: Configurable color for thinking block text. ([#366](https://github.com/badlogic/pi-mono/pull/366) by [@paulbettner](https://github.com/paulbettner))
|
|
222
|
+
|
|
223
|
+
### Changed
|
|
224
|
+
|
|
225
|
+
- **Entry IDs**: Session entries now use short 8-character hex IDs instead of full UUIDs
|
|
226
|
+
- **API key priority**: `ANTHROPIC_OAUTH_TOKEN` now takes precedence over `ANTHROPIC_API_KEY`
|
|
227
|
+
- HTML export template split into separate files (template.html, template.css, template.js) for easier maintenance
|
|
228
|
+
|
|
229
|
+
### Fixed
|
|
230
|
+
|
|
231
|
+
- HTML export now properly sanitizes user messages containing HTML tags like `<style>` that could break DOM rendering
|
|
232
|
+
- Crash when displaying bash output containing Unicode format characters like U+0600-U+0604 ([#372](https://github.com/badlogic/pi-mono/pull/372) by [@HACKE-RC](https://github.com/HACKE-RC))
|
|
233
|
+
- **Footer shows full session stats**: Token usage and cost now include all messages, not just those after compaction. ([#322](https://github.com/badlogic/pi-mono/issues/322))
|
|
234
|
+
- **Status messages spam chat log**: Rapidly changing settings (e.g., thinking level via Shift+Tab) would add multiple status lines. Sequential status updates now coalesce into a single line. ([#365](https://github.com/badlogic/pi-mono/pull/365) by [@paulbettner](https://github.com/paulbettner))
|
|
235
|
+
- **Toggling thinking blocks during streaming shows nothing**: Pressing Ctrl+T while streaming would hide the current message until streaming completed.
|
|
236
|
+
- **Resuming session resets thinking level to off**: Initial model and thinking level were not saved to session file, causing `--resume`/`--continue` to default to `off`. ([#342](https://github.com/badlogic/pi-mono/issues/342) by [@aliou](https://github.com/aliou))
|
|
237
|
+
- **Hook `tool_result` event ignores errors from custom tools**: The `tool_result` hook event was never emitted when tools threw errors, and always had `isError: false` for successful executions. Now emits the event with correct `isError` value in both success and error cases. ([#374](https://github.com/badlogic/pi-mono/issues/374) by [@nicobailon](https://github.com/nicobailon))
|
|
238
|
+
- **Edit tool fails on Windows due to CRLF line endings**: Files with CRLF line endings now match correctly when LLMs send LF-only text. Line endings are normalized before matching and restored to original style on write. ([#355](https://github.com/badlogic/pi-mono/issues/355) by [@Pratham-Dubey](https://github.com/Pratham-Dubey))
|
|
239
|
+
- **Edit tool fails on files with UTF-8 BOM**: Files with UTF-8 BOM marker could cause "text not found" errors since the LLM doesn't include the invisible BOM character. BOM is now stripped before matching and restored on write. ([#394](https://github.com/badlogic/pi-mono/pull/394) by [@prathamdby](https://github.com/prathamdby))
|
|
240
|
+
- **Use bash instead of sh on Unix**: Fixed shell commands using `/bin/sh` instead of `/bin/bash` on Unix systems. ([#328](https://github.com/badlogic/pi-mono/pull/328) by [@dnouri](https://github.com/dnouri))
|
|
241
|
+
- **OAuth login URL clickable**: Made OAuth login URLs clickable in terminal. ([#349](https://github.com/badlogic/pi-mono/pull/349) by [@Cursivez](https://github.com/Cursivez))
|
|
242
|
+
- **Improved error messages**: Better error messages when `apiKey` or `model` are missing. ([#346](https://github.com/badlogic/pi-mono/pull/346) by [@ronyrus](https://github.com/ronyrus))
|
|
243
|
+
- **Session file validation**: `findMostRecentSession()` now validates session headers before returning, preventing non-session JSONL files from being loaded
|
|
244
|
+
- **Compaction error handling**: `generateSummary()` and `generateTurnPrefixSummary()` now throw on LLM errors instead of returning empty strings
|
|
245
|
+
- **Compaction with branched sessions**: Fixed compaction incorrectly including entries from abandoned branches, causing token overflow errors. Compaction now uses `sessionManager.getPath()` to work only on the current branch path, eliminating 80+ lines of duplicate entry collection logic between `prepareCompaction()` and `compact()`
|
|
246
|
+
- **enabledModels glob patterns**: `--models` and `enabledModels` now support glob patterns like `github-copilot/*` or `*sonnet*`. Previously, patterns were only matched literally or via substring search. ([#337](https://github.com/badlogic/pi-mono/issues/337))
|
|
4
247
|
|
|
5
248
|
## [0.30.2] - 2025-12-26
|
|
6
249
|
|
package/README.md
CHANGED
|
@@ -25,12 +25,13 @@ Works on Linux, macOS, and Windows (requires bash; see [Windows Setup](#windows-
|
|
|
25
25
|
- [Project Context Files](#project-context-files)
|
|
26
26
|
- [Custom System Prompt](#custom-system-prompt)
|
|
27
27
|
- [Custom Models and Providers](#custom-models-and-providers)
|
|
28
|
+
- [Settings File](#settings-file)
|
|
29
|
+
- [Extensions](#extensions)
|
|
28
30
|
- [Themes](#themes)
|
|
29
31
|
- [Custom Slash Commands](#custom-slash-commands)
|
|
30
32
|
- [Skills](#skills)
|
|
31
33
|
- [Hooks](#hooks)
|
|
32
34
|
- [Custom Tools](#custom-tools)
|
|
33
|
-
- [Settings File](#settings-file)
|
|
34
35
|
- [CLI Reference](#cli-reference)
|
|
35
36
|
- [Tools](#tools)
|
|
36
37
|
- [Programmatic Usage](#programmatic-usage)
|
|
@@ -190,9 +191,11 @@ The agent reads, writes, and edits files, and executes commands via bash.
|
|
|
190
191
|
| `/settings` | Open settings menu (thinking, theme, queue mode, toggles) |
|
|
191
192
|
| `/model` | Switch models mid-session (fuzzy search, arrow keys, Enter to select) |
|
|
192
193
|
| `/export [file]` | Export session to self-contained HTML |
|
|
194
|
+
| `/share` | Upload session as secret GitHub gist, get shareable URL (requires `gh` CLI) |
|
|
193
195
|
| `/session` | Show session info: path, message counts, token usage, cost |
|
|
194
196
|
| `/hotkeys` | Show all keyboard shortcuts |
|
|
195
197
|
| `/changelog` | Display full version history |
|
|
198
|
+
| `/tree` | Navigate session tree in-place (search, filter, label entries) |
|
|
196
199
|
| `/branch` | Create new conversation branch from a previous message |
|
|
197
200
|
| `/resume` | Switch to a different session (interactive selector) |
|
|
198
201
|
| `/login` | OAuth login for subscription-based models |
|
|
@@ -291,6 +294,10 @@ Toggle inline images via `/settings` or set `terminal.showImages: false` in sett
|
|
|
291
294
|
|
|
292
295
|
## Sessions
|
|
293
296
|
|
|
297
|
+
Sessions are stored as JSONL files with a **tree structure**. Each entry has an `id` and `parentId`, enabling in-place branching: navigate to any previous point with `/tree`, continue from there, and switch between branches while preserving all history in a single file.
|
|
298
|
+
|
|
299
|
+
See [docs/session.md](docs/session.md) for the file format and programmatic API.
|
|
300
|
+
|
|
294
301
|
### Session Management
|
|
295
302
|
|
|
296
303
|
Sessions auto-save to `~/.pi/agent/sessions/` organized by working directory.
|
|
@@ -319,14 +326,6 @@ Long sessions can exhaust context windows. Compaction summarizes older messages
|
|
|
319
326
|
|
|
320
327
|
When disabled, neither case triggers automatic compaction (use `/compact` manually if needed).
|
|
321
328
|
|
|
322
|
-
**How it works:**
|
|
323
|
-
1. Cut point calculated to keep ~20k tokens of recent messages
|
|
324
|
-
2. Messages before cut point are summarized
|
|
325
|
-
3. Summary replaces old messages as "context handoff"
|
|
326
|
-
4. Previous compaction summaries chain into new ones
|
|
327
|
-
|
|
328
|
-
Compaction does not create a new session, but continues the existing one, with a marker in the `.jsonl` file that encodes the compaction point.
|
|
329
|
-
|
|
330
329
|
**Configuration** (`~/.pi/agent/settings.json`):
|
|
331
330
|
|
|
332
331
|
```json
|
|
@@ -339,11 +338,20 @@ Compaction does not create a new session, but continues the existing one, with a
|
|
|
339
338
|
}
|
|
340
339
|
```
|
|
341
340
|
|
|
342
|
-
> **Note:** Compaction is lossy. The agent loses full conversation access afterward. Size tasks to avoid context limits when possible. For critical context, ask the agent to write a summary to a file, iterate on it until it covers everything, then start a new session with that file. The full session history is preserved in the JSONL file; use `/
|
|
341
|
+
> **Note:** Compaction is lossy. The agent loses full conversation access afterward. Size tasks to avoid context limits when possible. For critical context, ask the agent to write a summary to a file, iterate on it until it covers everything, then start a new session with that file. The full session history is preserved in the JSONL file; use `/tree` to revisit any previous point.
|
|
342
|
+
|
|
343
|
+
See [docs/compaction.md](docs/compaction.md) for how compaction works internally and how to customize it via hooks.
|
|
343
344
|
|
|
344
345
|
### Branching
|
|
345
346
|
|
|
346
|
-
|
|
347
|
+
**In-place navigation (`/tree`):** Navigate the session tree without creating new files. Select any previous point, continue from there, and switch between branches while preserving all history.
|
|
348
|
+
|
|
349
|
+
- Search by typing, page with ←/→
|
|
350
|
+
- Filter modes (Ctrl+O): default → no-tools → user-only → labeled-only → all
|
|
351
|
+
- Press `l` to label entries as bookmarks
|
|
352
|
+
- When switching branches, you're prompted whether to generate a summary of the abandoned branch (messages up to the common ancestor)
|
|
353
|
+
|
|
354
|
+
**Create new session (`/branch`):** Branch to a new session file:
|
|
347
355
|
|
|
348
356
|
1. Opens selector showing all your user messages
|
|
349
357
|
2. Select a message to branch from
|
|
@@ -473,6 +481,75 @@ Add custom models (Ollama, vLLM, LM Studio, etc.) via `~/.pi/agent/models.json`:
|
|
|
473
481
|
|
|
474
482
|
> pi can help you create custom provider and model configurations.
|
|
475
483
|
|
|
484
|
+
### Settings File
|
|
485
|
+
|
|
486
|
+
Settings are loaded from two locations and merged:
|
|
487
|
+
|
|
488
|
+
1. **Global:** `~/.pi/agent/settings.json` - user preferences
|
|
489
|
+
2. **Project:** `<cwd>/.pi/settings.json` - project-specific overrides (version control friendly)
|
|
490
|
+
|
|
491
|
+
Project settings override global settings. For nested objects, individual keys merge. Settings changed via TUI (model, thinking level, etc.) are saved to global preferences only.
|
|
492
|
+
|
|
493
|
+
Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|
494
|
+
|
|
495
|
+
```json
|
|
496
|
+
{
|
|
497
|
+
"theme": "dark",
|
|
498
|
+
"defaultProvider": "anthropic",
|
|
499
|
+
"defaultModel": "claude-sonnet-4-20250514",
|
|
500
|
+
"defaultThinkingLevel": "medium",
|
|
501
|
+
"enabledModels": ["anthropic/*", "*gpt*", "gemini-2.5-pro:high"],
|
|
502
|
+
"queueMode": "one-at-a-time",
|
|
503
|
+
"shellPath": "C:\\path\\to\\bash.exe",
|
|
504
|
+
"hideThinkingBlock": false,
|
|
505
|
+
"collapseChangelog": false,
|
|
506
|
+
"compaction": {
|
|
507
|
+
"enabled": true,
|
|
508
|
+
"reserveTokens": 16384,
|
|
509
|
+
"keepRecentTokens": 20000
|
|
510
|
+
},
|
|
511
|
+
"skills": {
|
|
512
|
+
"enabled": true
|
|
513
|
+
},
|
|
514
|
+
"retry": {
|
|
515
|
+
"enabled": true,
|
|
516
|
+
"maxRetries": 3,
|
|
517
|
+
"baseDelayMs": 2000
|
|
518
|
+
},
|
|
519
|
+
"terminal": {
|
|
520
|
+
"showImages": true
|
|
521
|
+
},
|
|
522
|
+
"hooks": ["/path/to/hook.ts"],
|
|
523
|
+
"customTools": ["/path/to/tool.ts"]
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
| Setting | Description | Default |
|
|
528
|
+
|---------|-------------|---------|
|
|
529
|
+
| `theme` | Color theme name | auto-detected |
|
|
530
|
+
| `defaultProvider` | Default model provider | - |
|
|
531
|
+
| `defaultModel` | Default model ID | - |
|
|
532
|
+
| `defaultThinkingLevel` | Thinking level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh` | - |
|
|
533
|
+
| `enabledModels` | Model patterns for cycling. Supports glob patterns (`github-copilot/*`, `*sonnet*`) and fuzzy matching. Same as `--models` CLI flag | - |
|
|
534
|
+
| `queueMode` | Message queue mode: `all` or `one-at-a-time` | `one-at-a-time` |
|
|
535
|
+
| `shellPath` | Custom bash path (Windows) | auto-detected |
|
|
536
|
+
| `hideThinkingBlock` | Hide thinking blocks in output (Ctrl+T to toggle) | `false` |
|
|
537
|
+
| `collapseChangelog` | Show condensed changelog after update | `false` |
|
|
538
|
+
| `compaction.enabled` | Enable auto-compaction | `true` |
|
|
539
|
+
| `compaction.reserveTokens` | Tokens to reserve before compaction triggers | `16384` |
|
|
540
|
+
| `compaction.keepRecentTokens` | Recent tokens to keep after compaction | `20000` |
|
|
541
|
+
| `skills.enabled` | Enable skills discovery | `true` |
|
|
542
|
+
| `retry.enabled` | Auto-retry on transient errors | `true` |
|
|
543
|
+
| `retry.maxRetries` | Maximum retry attempts | `3` |
|
|
544
|
+
| `retry.baseDelayMs` | Base delay for exponential backoff | `2000` |
|
|
545
|
+
| `terminal.showImages` | Render images inline (supported terminals) | `true` |
|
|
546
|
+
| `hooks` | Additional hook file paths | `[]` |
|
|
547
|
+
| `customTools` | Additional custom tool file paths | `[]` |
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Extensions
|
|
552
|
+
|
|
476
553
|
### Themes
|
|
477
554
|
|
|
478
555
|
Built-in themes: `dark` (default), `light`. Auto-detected on first run.
|
|
@@ -612,18 +689,23 @@ export default function (pi: HookAPI) {
|
|
|
612
689
|
|
|
613
690
|
**Sending messages from hooks:**
|
|
614
691
|
|
|
615
|
-
Use `pi.
|
|
692
|
+
Use `pi.sendMessage(message, triggerTurn?)` to inject messages into the session. Messages are persisted as `CustomMessageEntry` and sent to the LLM. If the agent is streaming, the message is queued; otherwise a new agent loop starts if `triggerTurn` is true.
|
|
616
693
|
|
|
617
694
|
```typescript
|
|
618
695
|
import * as fs from "node:fs";
|
|
619
696
|
import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
|
620
697
|
|
|
621
698
|
export default function (pi: HookAPI) {
|
|
622
|
-
pi.on("
|
|
623
|
-
if (event.reason !== "start") return;
|
|
699
|
+
pi.on("session_start", async () => {
|
|
624
700
|
fs.watch("/tmp/trigger.txt", () => {
|
|
625
701
|
const content = fs.readFileSync("/tmp/trigger.txt", "utf-8").trim();
|
|
626
|
-
if (content)
|
|
702
|
+
if (content) {
|
|
703
|
+
pi.sendMessage({
|
|
704
|
+
customType: "file-trigger",
|
|
705
|
+
content,
|
|
706
|
+
display: true,
|
|
707
|
+
}, true); // triggerTurn: start agent loop
|
|
708
|
+
}
|
|
627
709
|
});
|
|
628
710
|
});
|
|
629
711
|
}
|
|
@@ -659,10 +741,11 @@ const factory: CustomToolFactory = (pi) => ({
|
|
|
659
741
|
name: Type.String({ description: "Name to greet" }),
|
|
660
742
|
}),
|
|
661
743
|
|
|
662
|
-
async execute(toolCallId, params) {
|
|
744
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
745
|
+
const { name } = params as { name: string };
|
|
663
746
|
return {
|
|
664
|
-
content: [{ type: "text", text: `Hello, ${
|
|
665
|
-
details: { greeted:
|
|
747
|
+
content: [{ type: "text", text: `Hello, ${name}!` }],
|
|
748
|
+
details: { greeted: name },
|
|
666
749
|
};
|
|
667
750
|
},
|
|
668
751
|
});
|
|
@@ -682,71 +765,6 @@ export default factory;
|
|
|
682
765
|
|
|
683
766
|
> See [examples/custom-tools/](examples/custom-tools/) for working examples including a todo list with session state management and a question tool with UI interaction.
|
|
684
767
|
|
|
685
|
-
### Settings File
|
|
686
|
-
|
|
687
|
-
Settings are loaded from two locations and merged:
|
|
688
|
-
|
|
689
|
-
1. **Global:** `~/.pi/agent/settings.json` - user preferences
|
|
690
|
-
2. **Project:** `<cwd>/.pi/settings.json` - project-specific overrides (version control friendly)
|
|
691
|
-
|
|
692
|
-
Project settings override global settings. For nested objects, individual keys merge. Settings changed via TUI (model, thinking level, etc.) are saved to global preferences only.
|
|
693
|
-
|
|
694
|
-
Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|
695
|
-
|
|
696
|
-
```json
|
|
697
|
-
{
|
|
698
|
-
"theme": "dark",
|
|
699
|
-
"defaultProvider": "anthropic",
|
|
700
|
-
"defaultModel": "claude-sonnet-4-20250514",
|
|
701
|
-
"defaultThinkingLevel": "medium",
|
|
702
|
-
"queueMode": "one-at-a-time",
|
|
703
|
-
"shellPath": "C:\\path\\to\\bash.exe",
|
|
704
|
-
"hideThinkingBlock": false,
|
|
705
|
-
"collapseChangelog": false,
|
|
706
|
-
"compaction": {
|
|
707
|
-
"enabled": true,
|
|
708
|
-
"reserveTokens": 16384,
|
|
709
|
-
"keepRecentTokens": 20000
|
|
710
|
-
},
|
|
711
|
-
"skills": {
|
|
712
|
-
"enabled": true
|
|
713
|
-
},
|
|
714
|
-
"retry": {
|
|
715
|
-
"enabled": true,
|
|
716
|
-
"maxRetries": 3,
|
|
717
|
-
"baseDelayMs": 2000
|
|
718
|
-
},
|
|
719
|
-
"terminal": {
|
|
720
|
-
"showImages": true
|
|
721
|
-
},
|
|
722
|
-
"hooks": ["/path/to/hook.ts"],
|
|
723
|
-
"hookTimeout": 30000,
|
|
724
|
-
"customTools": ["/path/to/tool.ts"]
|
|
725
|
-
}
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
| Setting | Description | Default |
|
|
729
|
-
|---------|-------------|---------|
|
|
730
|
-
| `theme` | Color theme name | auto-detected |
|
|
731
|
-
| `defaultProvider` | Default model provider | - |
|
|
732
|
-
| `defaultModel` | Default model ID | - |
|
|
733
|
-
| `defaultThinkingLevel` | Thinking level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh` | - |
|
|
734
|
-
| `queueMode` | Message queue mode: `all` or `one-at-a-time` | `one-at-a-time` |
|
|
735
|
-
| `shellPath` | Custom bash path (Windows) | auto-detected |
|
|
736
|
-
| `hideThinkingBlock` | Hide thinking blocks in output (Ctrl+T to toggle) | `false` |
|
|
737
|
-
| `collapseChangelog` | Show condensed changelog after update | `false` |
|
|
738
|
-
| `compaction.enabled` | Enable auto-compaction | `true` |
|
|
739
|
-
| `compaction.reserveTokens` | Tokens to reserve before compaction triggers | `16384` |
|
|
740
|
-
| `compaction.keepRecentTokens` | Recent tokens to keep after compaction | `20000` |
|
|
741
|
-
| `skills.enabled` | Enable skills discovery | `true` |
|
|
742
|
-
| `retry.enabled` | Auto-retry on transient errors | `true` |
|
|
743
|
-
| `retry.maxRetries` | Maximum retry attempts | `3` |
|
|
744
|
-
| `retry.baseDelayMs` | Base delay for exponential backoff | `2000` |
|
|
745
|
-
| `terminal.showImages` | Render images inline (supported terminals) | `true` |
|
|
746
|
-
| `hooks` | Additional hook file paths | `[]` |
|
|
747
|
-
| `hookTimeout` | Timeout for hook operations (ms) | `30000` |
|
|
748
|
-
| `customTools` | Additional custom tool file paths | `[]` |
|
|
749
|
-
|
|
750
768
|
---
|
|
751
769
|
|
|
752
770
|
## CLI Reference
|
|
@@ -771,7 +789,7 @@ pi [options] [@files...] [messages...]
|
|
|
771
789
|
| `--session-dir <dir>` | Directory for session storage and lookup |
|
|
772
790
|
| `--continue`, `-c` | Continue most recent session |
|
|
773
791
|
| `--resume`, `-r` | Select session to resume |
|
|
774
|
-
| `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling (e.g., `sonnet
|
|
792
|
+
| `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling. Supports glob patterns (e.g., `anthropic/*`, `*sonnet*:high`) and fuzzy matching (e.g., `sonnet,haiku:low`) |
|
|
775
793
|
| `--tools <tools>` | Comma-separated tool list (default: `read,bash,edit,write`) |
|
|
776
794
|
| `--thinking <level>` | Thinking level: `off`, `minimal`, `low`, `medium`, `high` |
|
|
777
795
|
| `--hook <path>` | Load a hook file (can be used multiple times) |
|
|
@@ -823,6 +841,9 @@ pi --provider openai --model gpt-4o "Help me refactor"
|
|
|
823
841
|
# Model cycling with thinking levels
|
|
824
842
|
pi --models sonnet:high,haiku:low
|
|
825
843
|
|
|
844
|
+
# Limit to specific provider with glob pattern
|
|
845
|
+
pi --models "github-copilot/*"
|
|
846
|
+
|
|
826
847
|
# Read-only mode
|
|
827
848
|
pi --tools read,grep,find,ls -p "Review the architecture"
|
|
828
849
|
|
package/dist/cli/args.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE3C,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAE1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8F9C;AAED,wBAAgB,SAAS,IAAI,IAAI,CA2FhC","sourcesContent":["/**\n * CLI argument parsing and help display\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR } from \"../config.js\";\nimport { allTools, type ToolName } from \"../core/tools/index.js\";\n\nexport type Mode = \"text\" | \"json\" | \"rpc\";\n\nexport interface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\tthinking?: ThinkingLevel;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tsessionDir?: string;\n\tmodels?: string[];\n\ttools?: ToolName[];\n\thooks?: string[];\n\tcustomTools?: string[];\n\tprint?: boolean;\n\texport?: string;\n\tnoSkills?: boolean;\n\tskills?: string[];\n\tlistModels?: string | true;\n\tmessages: string[];\n\tfileArgs: string[];\n}\n\nconst VALID_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] as const;\n\nexport function isValidThinkingLevel(level: string): level is ThinkingLevel {\n\treturn VALID_THINKING_LEVELS.includes(level as ThinkingLevel);\n}\n\nexport function parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--version\" || arg === \"-v\") {\n\t\t\tresult.version = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--append-system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.appendSystemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (arg === \"--session-dir\" && i + 1 < args.length) {\n\t\t\tresult.sessionDir = args[++i];\n\t\t} else if (arg === \"--models\" && i + 1 < args.length) {\n\t\t\tresult.models = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--tools\" && i + 1 < args.length) {\n\t\t\tconst toolNames = args[++i].split(\",\").map((s) => s.trim());\n\t\t\tconst validTools: ToolName[] = [];\n\t\t\tfor (const name of toolNames) {\n\t\t\t\tif (name in allTools) {\n\t\t\t\t\tvalidTools.push(name as ToolName);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(`Warning: Unknown tool \"${name}\". Valid tools: ${Object.keys(allTools).join(\", \")}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.tools = validTools;\n\t\t} else if (arg === \"--thinking\" && i + 1 < args.length) {\n\t\t\tconst level = args[++i];\n\t\t\tif (isValidThinkingLevel(level)) {\n\t\t\t\tresult.thinking = level;\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t`Warning: Invalid thinking level \"${level}\". Valid values: ${VALID_THINKING_LEVELS.join(\", \")}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (arg === \"--print\" || arg === \"-p\") {\n\t\t\tresult.print = true;\n\t\t} else if (arg === \"--export\" && i + 1 < args.length) {\n\t\t\tresult.export = args[++i];\n\t\t} else if (arg === \"--hook\" && i + 1 < args.length) {\n\t\t\tresult.hooks = result.hooks ?? [];\n\t\t\tresult.hooks.push(args[++i]);\n\t\t} else if (arg === \"--tool\" && i + 1 < args.length) {\n\t\t\tresult.customTools = result.customTools ?? [];\n\t\t\tresult.customTools.push(args[++i]);\n\t\t} else if (arg === \"--no-skills\") {\n\t\t\tresult.noSkills = true;\n\t\t} else if (arg === \"--skills\" && i + 1 < args.length) {\n\t\t\t// Comma-separated glob patterns for skill filtering\n\t\t\tresult.skills = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--list-models\") {\n\t\t\t// Check if next arg is a search pattern (not a flag or file arg)\n\t\t\tif (i + 1 < args.length && !args[i + 1].startsWith(\"-\") && !args[i + 1].startsWith(\"@\")) {\n\t\t\t\tresult.listModels = args[++i];\n\t\t\t} else {\n\t\t\t\tresult.listModels = true;\n\t\t\t}\n\t\t} else if (arg.startsWith(\"@\")) {\n\t\t\tresult.fileArgs.push(arg.slice(1)); // Remove @ prefix\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function printHelp(): void {\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt\n --mode <mode> Output mode: text (default), json, or rpc\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --session-dir <dir> Directory for session storage and lookup\n --no-session Don't save session (ephemeral)\n --models <patterns> Comma-separated model patterns for quick cycling with Ctrl+P\n --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)\n Available: read, bash, edit, write, grep, find, ls\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh\n --hook <path> Load a hook file (can be used multiple times)\n --tool <path> Load a custom tool file (can be used multiple times)\n --no-skills Disable skills discovery and loading\n --skills <patterns> Comma-separated glob patterns to filter skills (e.g., git-*,docker)\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --help, -h Show this help\n --version, -v Show version number\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n OPENAI_API_KEY - OpenAI GPT API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n OPENROUTER_API_KEY - OpenRouter API key\n ZAI_API_KEY - ZAI API key\n ${ENV_AGENT_DIR.padEnd(23)} - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)\n\n${chalk.bold(\"Available Tools (default: read, bash, edit, write):\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE3C,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAE1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8F9C;AAED,wBAAgB,SAAS,IAAI,IAAI,CA+FhC","sourcesContent":["/**\n * CLI argument parsing and help display\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR } from \"../config.js\";\nimport { allTools, type ToolName } from \"../core/tools/index.js\";\n\nexport type Mode = \"text\" | \"json\" | \"rpc\";\n\nexport interface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\tthinking?: ThinkingLevel;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tsessionDir?: string;\n\tmodels?: string[];\n\ttools?: ToolName[];\n\thooks?: string[];\n\tcustomTools?: string[];\n\tprint?: boolean;\n\texport?: string;\n\tnoSkills?: boolean;\n\tskills?: string[];\n\tlistModels?: string | true;\n\tmessages: string[];\n\tfileArgs: string[];\n}\n\nconst VALID_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] as const;\n\nexport function isValidThinkingLevel(level: string): level is ThinkingLevel {\n\treturn VALID_THINKING_LEVELS.includes(level as ThinkingLevel);\n}\n\nexport function parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--version\" || arg === \"-v\") {\n\t\t\tresult.version = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--append-system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.appendSystemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (arg === \"--session-dir\" && i + 1 < args.length) {\n\t\t\tresult.sessionDir = args[++i];\n\t\t} else if (arg === \"--models\" && i + 1 < args.length) {\n\t\t\tresult.models = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--tools\" && i + 1 < args.length) {\n\t\t\tconst toolNames = args[++i].split(\",\").map((s) => s.trim());\n\t\t\tconst validTools: ToolName[] = [];\n\t\t\tfor (const name of toolNames) {\n\t\t\t\tif (name in allTools) {\n\t\t\t\t\tvalidTools.push(name as ToolName);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(`Warning: Unknown tool \"${name}\". Valid tools: ${Object.keys(allTools).join(\", \")}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.tools = validTools;\n\t\t} else if (arg === \"--thinking\" && i + 1 < args.length) {\n\t\t\tconst level = args[++i];\n\t\t\tif (isValidThinkingLevel(level)) {\n\t\t\t\tresult.thinking = level;\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t`Warning: Invalid thinking level \"${level}\". Valid values: ${VALID_THINKING_LEVELS.join(\", \")}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (arg === \"--print\" || arg === \"-p\") {\n\t\t\tresult.print = true;\n\t\t} else if (arg === \"--export\" && i + 1 < args.length) {\n\t\t\tresult.export = args[++i];\n\t\t} else if (arg === \"--hook\" && i + 1 < args.length) {\n\t\t\tresult.hooks = result.hooks ?? [];\n\t\t\tresult.hooks.push(args[++i]);\n\t\t} else if (arg === \"--tool\" && i + 1 < args.length) {\n\t\t\tresult.customTools = result.customTools ?? [];\n\t\t\tresult.customTools.push(args[++i]);\n\t\t} else if (arg === \"--no-skills\") {\n\t\t\tresult.noSkills = true;\n\t\t} else if (arg === \"--skills\" && i + 1 < args.length) {\n\t\t\t// Comma-separated glob patterns for skill filtering\n\t\t\tresult.skills = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--list-models\") {\n\t\t\t// Check if next arg is a search pattern (not a flag or file arg)\n\t\t\tif (i + 1 < args.length && !args[i + 1].startsWith(\"-\") && !args[i + 1].startsWith(\"@\")) {\n\t\t\t\tresult.listModels = args[++i];\n\t\t\t} else {\n\t\t\t\tresult.listModels = true;\n\t\t\t}\n\t\t} else if (arg.startsWith(\"@\")) {\n\t\t\tresult.fileArgs.push(arg.slice(1)); // Remove @ prefix\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function printHelp(): void {\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt\n --mode <mode> Output mode: text (default), json, or rpc\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --session-dir <dir> Directory for session storage and lookup\n --no-session Don't save session (ephemeral)\n --models <patterns> Comma-separated model patterns for Ctrl+P cycling\n Supports globs (anthropic/*, *sonnet*) and fuzzy matching\n --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)\n Available: read, bash, edit, write, grep, find, ls\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh\n --hook <path> Load a hook file (can be used multiple times)\n --tool <path> Load a custom tool file (can be used multiple times)\n --no-skills Disable skills discovery and loading\n --skills <patterns> Comma-separated glob patterns to filter skills (e.g., git-*,docker)\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --help, -h Show this help\n --version, -v Show version number\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Limit to a specific provider with glob pattern\n ${APP_NAME} --models \"github-copilot/*\"\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n OPENAI_API_KEY - OpenAI GPT API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n OPENROUTER_API_KEY - OpenRouter API key\n ZAI_API_KEY - ZAI API key\n ${ENV_AGENT_DIR.padEnd(23)} - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)\n\n${chalk.bold(\"Available Tools (default: read, bash, edit, write):\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
|
package/dist/cli/args.js
CHANGED
|
@@ -140,7 +140,8 @@ ${chalk.bold("Options:")}
|
|
|
140
140
|
--session <path> Use specific session file
|
|
141
141
|
--session-dir <dir> Directory for session storage and lookup
|
|
142
142
|
--no-session Don't save session (ephemeral)
|
|
143
|
-
--models <patterns> Comma-separated model patterns for
|
|
143
|
+
--models <patterns> Comma-separated model patterns for Ctrl+P cycling
|
|
144
|
+
Supports globs (anthropic/*, *sonnet*) and fuzzy matching
|
|
144
145
|
--tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)
|
|
145
146
|
Available: read, bash, edit, write, grep, find, ls
|
|
146
147
|
--thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
|
|
@@ -178,6 +179,9 @@ ${chalk.bold("Examples:")}
|
|
|
178
179
|
# Limit model cycling to specific models
|
|
179
180
|
${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o
|
|
180
181
|
|
|
182
|
+
# Limit to a specific provider with glob pattern
|
|
183
|
+
${APP_NAME} --models "github-copilot/*"
|
|
184
|
+
|
|
181
185
|
# Cycle models with fixed thinking levels
|
|
182
186
|
${APP_NAME} --models sonnet:high,haiku:low
|
|
183
187
|
|