@mariozechner/pi-coding-agent 0.34.2 → 0.36.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 +210 -0
- package/README.md +246 -107
- package/dist/cli/args.d.ts +3 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +13 -18
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +39 -50
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +166 -197
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +6 -5
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/exec.d.ts +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/extensions/index.d.ts +10 -0
- package/dist/core/extensions/index.d.ts.map +1 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/index.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +21 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +400 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +88 -0
- package/dist/core/extensions/runner.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/runner.js +52 -141
- package/dist/core/extensions/runner.js.map +1 -0
- package/dist/core/extensions/types.d.ts +461 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/types.js +7 -4
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts +25 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -0
- package/dist/core/{hooks/tool-wrapper.js → extensions/wrapper.js} +39 -24
- package/dist/core/extensions/wrapper.js.map +1 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +7 -7
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +4 -4
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +40 -0
- package/dist/core/prompt-templates.d.ts.map +1 -0
- package/dist/core/{slash-commands.js → prompt-templates.js} +31 -31
- package/dist/core/prompt-templates.js.map +1 -0
- package/dist/core/sdk.d.ts +29 -52
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +111 -211
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +17 -17
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +25 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -6
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -11
- 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 +4 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +36 -33
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +7 -2
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +93 -4
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +4 -4
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +18 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-message.js → custom-message.js} +3 -3
- package/dist/modes/interactive/components/custom-message.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +2 -2
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +2 -2
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/{hook-editor.d.ts → extension-editor.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-editor.js → extension-editor.js} +4 -4
- package/dist/modes/interactive/components/extension-editor.js.map +1 -0
- package/dist/modes/interactive/components/{hook-input.d.ts → extension-input.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-input.js → extension-input.js} +3 -3
- package/dist/modes/interactive/components/extension-input.js.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.d.ts → extension-selector.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.js → extension-selector.js} +3 -3
- package/dist/modes/interactive/components/extension-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +3 -3
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +3 -3
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +9 -9
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +37 -44
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +143 -189
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +10 -33
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -3
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -3
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +33 -57
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +16 -16
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/extensions.md +1053 -0
- package/docs/rpc.md +4 -4
- package/docs/sdk.md +62 -93
- package/docs/session.md +22 -19
- package/docs/skills.md +1 -1
- package/docs/tui.md +1 -1
- package/examples/README.md +9 -15
- package/examples/extensions/README.md +141 -0
- package/examples/{hooks → extensions}/auto-commit-on-exit.ts +3 -3
- package/examples/extensions/chalk-logger.ts +26 -0
- package/examples/{hooks → extensions}/confirm-destructive.ts +3 -3
- package/examples/{hooks → extensions}/custom-compaction.ts +6 -6
- package/examples/{hooks → extensions}/dirty-repo-guard.ts +8 -4
- package/examples/{hooks → extensions}/file-trigger.ts +3 -3
- package/examples/{hooks → extensions}/git-checkpoint.ts +3 -3
- package/examples/{hooks → extensions}/handoff.ts +3 -3
- package/examples/extensions/hello.ts +25 -0
- package/examples/{hooks → extensions}/permission-gate.ts +3 -3
- package/examples/{hooks → extensions}/pirate.ts +5 -5
- package/examples/{hooks → extensions}/plan-mode.ts +6 -6
- package/examples/{hooks → extensions}/protected-paths.ts +3 -3
- package/examples/{hooks → extensions}/qna.ts +3 -3
- package/examples/{custom-tools/question/index.ts → extensions/question.ts} +13 -17
- package/examples/{hooks → extensions}/snake.ts +3 -3
- package/examples/{hooks → extensions}/status-line.ts +3 -3
- package/examples/{custom-tools → extensions}/subagent/README.md +15 -15
- package/examples/{custom-tools → extensions}/subagent/index.ts +22 -43
- package/examples/{custom-tools/todo/index.ts → extensions/todo.ts} +122 -39
- package/examples/{hooks → extensions}/tools.ts +5 -5
- package/examples/extensions/with-deps/index.ts +36 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +16 -0
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/05-tools.ts +7 -41
- package/examples/sdk/06-extensions.ts +81 -0
- package/examples/sdk/08-prompt-templates.ts +42 -0
- package/examples/sdk/12-full-control.ts +10 -29
- package/examples/sdk/README.md +5 -5
- package/package.json +4 -4
- package/dist/core/custom-tools/index.d.ts +0 -7
- package/dist/core/custom-tools/index.d.ts.map +0 -1
- package/dist/core/custom-tools/index.js +0 -6
- package/dist/core/custom-tools/index.js.map +0 -1
- package/dist/core/custom-tools/loader.d.ts +0 -30
- package/dist/core/custom-tools/loader.d.ts.map +0 -1
- package/dist/core/custom-tools/loader.js +0 -276
- package/dist/core/custom-tools/loader.js.map +0 -1
- package/dist/core/custom-tools/types.d.ts +0 -144
- package/dist/core/custom-tools/types.d.ts.map +0 -1
- package/dist/core/custom-tools/types.js +0 -8
- package/dist/core/custom-tools/types.js.map +0 -1
- package/dist/core/custom-tools/wrapper.d.ts +0 -15
- package/dist/core/custom-tools/wrapper.d.ts.map +0 -1
- package/dist/core/custom-tools/wrapper.js +0 -23
- package/dist/core/custom-tools/wrapper.js.map +0 -1
- package/dist/core/hooks/index.d.ts +0 -6
- package/dist/core/hooks/index.d.ts.map +0 -1
- package/dist/core/hooks/index.js +0 -6
- package/dist/core/hooks/index.js.map +0 -1
- package/dist/core/hooks/loader.d.ts +0 -146
- package/dist/core/hooks/loader.d.ts.map +0 -1
- package/dist/core/hooks/loader.js +0 -275
- package/dist/core/hooks/loader.js.map +0 -1
- package/dist/core/hooks/runner.d.ts +0 -173
- package/dist/core/hooks/runner.d.ts.map +0 -1
- package/dist/core/hooks/runner.js.map +0 -1
- package/dist/core/hooks/tool-wrapper.d.ts +0 -17
- package/dist/core/hooks/tool-wrapper.d.ts.map +0 -1
- package/dist/core/hooks/tool-wrapper.js.map +0 -1
- package/dist/core/hooks/types.d.ts +0 -767
- package/dist/core/hooks/types.d.ts.map +0 -1
- package/dist/core/hooks/types.js.map +0 -1
- package/dist/core/slash-commands.d.ts +0 -40
- package/dist/core/slash-commands.d.ts.map +0 -1
- package/dist/core/slash-commands.js.map +0 -1
- package/dist/modes/interactive/components/hook-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-editor.js.map +0 -1
- package/dist/modes/interactive/components/hook-input.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-input.js.map +0 -1
- package/dist/modes/interactive/components/hook-message.d.ts +0 -18
- package/dist/modes/interactive/components/hook-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-message.js.map +0 -1
- package/dist/modes/interactive/components/hook-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-selector.js.map +0 -1
- package/docs/custom-tools.md +0 -514
- package/docs/extension-loading.md +0 -1004
- package/docs/hooks.md +0 -979
- package/docs/session-tree-plan.md +0 -441
- package/examples/custom-tools/README.md +0 -114
- package/examples/custom-tools/hello/index.ts +0 -21
- package/examples/hooks/README.md +0 -60
- package/examples/hooks/todo/index.ts +0 -134
- package/examples/sdk/06-hooks.ts +0 -61
- package/examples/sdk/08-slash-commands.ts +0 -42
- /package/examples/{custom-tools → extensions}/subagent/agents/planner.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/reviewer.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/scout.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/worker.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents.ts +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement-and-review.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/scout-and-plan.md +0 -0
package/README.md
CHANGED
|
@@ -36,12 +36,11 @@ Works on Linux, macOS, and Windows (requires bash; see [Windows Setup](#windows-
|
|
|
36
36
|
- [Custom System Prompt](#custom-system-prompt)
|
|
37
37
|
- [Custom Models and Providers](#custom-models-and-providers)
|
|
38
38
|
- [Settings File](#settings-file)
|
|
39
|
-
- [
|
|
39
|
+
- [Customization](#customization)
|
|
40
40
|
- [Themes](#themes)
|
|
41
|
-
- [
|
|
41
|
+
- [Prompt Templates](#prompt-templates)
|
|
42
42
|
- [Skills](#skills)
|
|
43
|
-
- [
|
|
44
|
-
- [Custom Tools](#custom-tools)
|
|
43
|
+
- [Extensions](#extensions)
|
|
45
44
|
- [CLI Reference](#cli-reference)
|
|
46
45
|
- [Tools](#tools)
|
|
47
46
|
- [Programmatic Usage](#programmatic-usage)
|
|
@@ -156,6 +155,7 @@ Use `/login` to authenticate with subscription-based or free-tier providers:
|
|
|
156
155
|
| GitHub Copilot | GPT-4o, Claude, Gemini via Copilot subscription | Subscription |
|
|
157
156
|
| Google Gemini CLI | Gemini 2.0/2.5 models | Free (Google account) |
|
|
158
157
|
| Google Antigravity | Gemini 3, Claude, GPT-OSS | Free (Google account) |
|
|
158
|
+
| OpenAI Codex (ChatGPT Plus/Pro) | Codex models via ChatGPT subscription | Subscription |
|
|
159
159
|
|
|
160
160
|
```bash
|
|
161
161
|
pi
|
|
@@ -173,8 +173,18 @@ pi
|
|
|
173
173
|
- Antigravity uses a sandbox endpoint with access to Gemini 3, Claude (sonnet/opus thinking), and GPT-OSS models
|
|
174
174
|
- Both are free with any Google account, subject to rate limits
|
|
175
175
|
|
|
176
|
+
**OpenAI Codex notes:**
|
|
177
|
+
- Requires ChatGPT Plus/Pro OAuth (`/login openai-codex`)
|
|
178
|
+
- Prompt cache stored under `~/.pi/agent/cache/openai-codex/`
|
|
179
|
+
- Intended for personal use with your own subscription; not for resale or multi-user services. For production, use the OpenAI Platform API.
|
|
180
|
+
|
|
176
181
|
Credentials stored in `~/.pi/agent/auth.json`. Use `/logout` to clear.
|
|
177
182
|
|
|
183
|
+
**Troubleshooting (OAuth):**
|
|
184
|
+
- **Port 1455 in use:** Close the conflicting process or paste the auth code/URL when prompted.
|
|
185
|
+
- **Token expired / refresh failed:** Run `/login` again for the provider to refresh credentials.
|
|
186
|
+
- **Usage limits (429):** Wait for the reset window; pi will surface a friendly message with the approximate retry time.
|
|
187
|
+
|
|
178
188
|
### Quick Start
|
|
179
189
|
|
|
180
190
|
```bash
|
|
@@ -374,10 +384,9 @@ The output becomes part of your next prompt, formatted as:
|
|
|
374
384
|
|
|
375
385
|
```
|
|
376
386
|
Ran `ls -la`
|
|
377
|
-
|
|
387
|
+
|
|
378
388
|
<output here>
|
|
379
389
|
```
|
|
380
|
-
```
|
|
381
390
|
|
|
382
391
|
Run multiple commands before prompting; all outputs are included together.
|
|
383
392
|
|
|
@@ -453,7 +462,7 @@ When disabled, neither case triggers automatic compaction (use `/compact` manual
|
|
|
453
462
|
|
|
454
463
|
> **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.
|
|
455
464
|
|
|
456
|
-
See [docs/compaction.md](docs/compaction.md) for how compaction works internally and how to customize it via
|
|
465
|
+
See [docs/compaction.md](docs/compaction.md) for how compaction works internally and how to customize it via extensions.
|
|
457
466
|
|
|
458
467
|
### Branching
|
|
459
468
|
|
|
@@ -547,7 +556,7 @@ Add custom models (Ollama, vLLM, LM Studio, etc.) via `~/.pi/agent/models.json`:
|
|
|
547
556
|
}
|
|
548
557
|
```
|
|
549
558
|
|
|
550
|
-
**Supported APIs:** `openai-completions`, `openai-responses`, `anthropic-messages`, `google-generative-ai`
|
|
559
|
+
**Supported APIs:** `openai-completions`, `openai-responses`, `openai-codex-responses`, `anthropic-messages`, `google-generative-ai`
|
|
551
560
|
|
|
552
561
|
**API key resolution:** The `apiKey` field is checked as environment variable name first, then used as literal value.
|
|
553
562
|
|
|
@@ -667,8 +676,7 @@ Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|
|
667
676
|
"images": {
|
|
668
677
|
"autoResize": true
|
|
669
678
|
},
|
|
670
|
-
"
|
|
671
|
-
"customTools": ["/path/to/tool.ts"]
|
|
679
|
+
"extensions": ["/path/to/extension.ts"]
|
|
672
680
|
}
|
|
673
681
|
```
|
|
674
682
|
|
|
@@ -694,12 +702,11 @@ Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|
|
694
702
|
| `terminal.showImages` | Render images inline (supported terminals) | `true` |
|
|
695
703
|
| `images.autoResize` | Auto-resize images to 2000x2000 max for better model compatibility | `true` |
|
|
696
704
|
| `doubleEscapeAction` | Action for double-escape with empty editor: `tree` or `branch` | `tree` |
|
|
697
|
-
| `
|
|
698
|
-
| `customTools` | Additional custom tool file paths | `[]` |
|
|
705
|
+
| `extensions` | Additional extension file paths | `[]` |
|
|
699
706
|
|
|
700
707
|
---
|
|
701
708
|
|
|
702
|
-
##
|
|
709
|
+
## Customization
|
|
703
710
|
|
|
704
711
|
### Themes
|
|
705
712
|
|
|
@@ -720,13 +727,13 @@ Select with `/settings`, then edit the file. Changes apply on save.
|
|
|
720
727
|
|
|
721
728
|
**VS Code terminal fix:** Set `terminal.integrated.minimumContrastRatio` to `1` for accurate colors.
|
|
722
729
|
|
|
723
|
-
###
|
|
730
|
+
### Prompt Templates
|
|
724
731
|
|
|
725
732
|
Define reusable prompts as Markdown files:
|
|
726
733
|
|
|
727
734
|
**Locations:**
|
|
728
|
-
- Global: `~/.pi/agent/
|
|
729
|
-
- Project: `.pi/
|
|
735
|
+
- Global: `~/.pi/agent/prompts/*.md`
|
|
736
|
+
- Project: `.pi/prompts/*.md`
|
|
730
737
|
|
|
731
738
|
**Format:**
|
|
732
739
|
|
|
@@ -755,7 +762,7 @@ Usage: `/component Button "onClick handler" "disabled support"`
|
|
|
755
762
|
- `$1` = `Button`
|
|
756
763
|
- `$@` or `$ARGUMENTS` = all arguments joined (`Button onClick handler disabled support`)
|
|
757
764
|
|
|
758
|
-
**Namespacing:** Subdirectories create prefixes. `.pi/
|
|
765
|
+
**Namespacing:** Subdirectories create prefixes. `.pi/prompts/frontend/component.md` → `/component (project:frontend)`
|
|
759
766
|
|
|
760
767
|
|
|
761
768
|
### Skills
|
|
@@ -807,120 +814,251 @@ cd /path/to/brave-search && npm install
|
|
|
807
814
|
|
|
808
815
|
> See [docs/skills.md](docs/skills.md) for details, examples, and links to skill repositories. pi can help you create new skills.
|
|
809
816
|
|
|
810
|
-
###
|
|
817
|
+
### Extensions
|
|
818
|
+
|
|
819
|
+
Extensions are TypeScript modules that extend pi's behavior.
|
|
820
|
+
|
|
821
|
+
**Use cases:**
|
|
822
|
+
- **Custom tools** - Register tools callable by the LLM with custom UI and rendering
|
|
823
|
+
- **Custom commands** - Add `/commands` for users (e.g., `/deploy`, `/stats`)
|
|
824
|
+
- **Event interception** - Block tool calls, modify results, customize compaction
|
|
825
|
+
- **State persistence** - Store data in session, reconstruct on reload/branch
|
|
826
|
+
- **External integrations** - File watchers, webhooks, git checkpointing
|
|
827
|
+
- **Custom UI** - Full TUI control from tools, commands, or event handlers
|
|
811
828
|
|
|
812
|
-
|
|
829
|
+
**Locations:**
|
|
830
|
+
- Global: `~/.pi/agent/extensions/*.ts` or `~/.pi/agent/extensions/*/index.ts`
|
|
831
|
+
- Project: `.pi/extensions/*.ts` or `.pi/extensions/*/index.ts`
|
|
832
|
+
- CLI: `--extension <path>` or `-e <path>`
|
|
813
833
|
|
|
814
|
-
|
|
815
|
-
- **Checkpoint code state** (git stash at each turn, restore on `/branch`)
|
|
816
|
-
- **Protect paths** (block writes to `.env`, `node_modules/`, etc.)
|
|
817
|
-
- **Modify tool output** (filter or transform results before the LLM sees them)
|
|
818
|
-
- **Inject messages from external sources to wake up the agent** (file watchers, webhooks, CI systems)
|
|
834
|
+
**Dependencies:** Extensions can have their own dependencies. Place a `package.json` next to the extension (or in a parent directory), run `npm install`, and imports are resolved via [jiti](https://github.com/unjs/jiti). See [examples/extensions/with-deps/](examples/extensions/with-deps/).
|
|
819
835
|
|
|
820
|
-
|
|
821
|
-
- Global: `~/.pi/agent/hooks/*.ts`
|
|
822
|
-
- Project: `.pi/hooks/*.ts`
|
|
823
|
-
- CLI: `--hook <path>` (for debugging)
|
|
836
|
+
#### Custom Tools
|
|
824
837
|
|
|
825
|
-
|
|
838
|
+
Tools are functions the LLM can call. They appear in the system prompt and can have custom rendering.
|
|
826
839
|
|
|
827
840
|
```typescript
|
|
828
|
-
import type {
|
|
841
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
842
|
+
import { Type } from "@sinclair/typebox";
|
|
843
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
844
|
+
|
|
845
|
+
export default function (pi: ExtensionAPI) {
|
|
846
|
+
pi.registerTool({
|
|
847
|
+
name: "deploy",
|
|
848
|
+
label: "Deploy",
|
|
849
|
+
description: "Deploy the application to production",
|
|
850
|
+
parameters: Type.Object({
|
|
851
|
+
environment: Type.String({ description: "Target environment" }),
|
|
852
|
+
}),
|
|
853
|
+
|
|
854
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
855
|
+
// Show progress via onUpdate
|
|
856
|
+
onUpdate({ status: "Deploying..." });
|
|
857
|
+
|
|
858
|
+
// Ask user for confirmation
|
|
859
|
+
const ok = await ctx.ui.confirm("Deploy?", `Deploy to ${params.environment}?`);
|
|
860
|
+
if (!ok) {
|
|
861
|
+
return { content: [{ type: "text", text: "Cancelled" }], details: { cancelled: true } };
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Run shell commands
|
|
865
|
+
const result = await ctx.exec("./deploy.sh", [params.environment], { signal });
|
|
866
|
+
|
|
867
|
+
return {
|
|
868
|
+
content: [{ type: "text", text: result.stdout }],
|
|
869
|
+
details: { environment: params.environment, exitCode: result.exitCode },
|
|
870
|
+
};
|
|
871
|
+
},
|
|
872
|
+
|
|
873
|
+
// Custom TUI rendering (optional)
|
|
874
|
+
renderCall(args, theme) {
|
|
875
|
+
return new Text(theme.bold("deploy ") + theme.fg("accent", args.environment), 0, 0);
|
|
876
|
+
},
|
|
877
|
+
renderResult(result, options, theme) {
|
|
878
|
+
const ok = result.details?.exitCode === 0;
|
|
879
|
+
return new Text(ok ? theme.fg("success", "✓ Deployed") : theme.fg("error", "✗ Failed"), 0, 0);
|
|
880
|
+
},
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
```
|
|
829
884
|
|
|
830
|
-
|
|
885
|
+
#### Custom Commands
|
|
886
|
+
|
|
887
|
+
Commands are user-invoked via `/name`. They can show custom UI, modify state, or trigger agent turns.
|
|
888
|
+
|
|
889
|
+
```typescript
|
|
890
|
+
export default function (pi: ExtensionAPI) {
|
|
891
|
+
pi.registerCommand("stats", {
|
|
892
|
+
description: "Show session statistics",
|
|
893
|
+
handler: async (args, ctx) => {
|
|
894
|
+
// Simple notification
|
|
895
|
+
ctx.ui.notify(`${ctx.sessionManager.getEntries().length} entries`, "info");
|
|
896
|
+
},
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
pi.registerCommand("todos", {
|
|
900
|
+
description: "Interactive todo viewer",
|
|
901
|
+
handler: async (args, ctx) => {
|
|
902
|
+
// Full custom UI with keyboard handling
|
|
903
|
+
await ctx.ui.custom((tui, theme, done) => {
|
|
904
|
+
return {
|
|
905
|
+
render(width) {
|
|
906
|
+
return [
|
|
907
|
+
theme.bold("Todos"),
|
|
908
|
+
"- [ ] Item 1",
|
|
909
|
+
"- [x] Item 2",
|
|
910
|
+
"",
|
|
911
|
+
theme.fg("dim", "Press Escape to close"),
|
|
912
|
+
];
|
|
913
|
+
},
|
|
914
|
+
handleInput(data) {
|
|
915
|
+
if (matchesKey(data, "escape")) done();
|
|
916
|
+
},
|
|
917
|
+
};
|
|
918
|
+
});
|
|
919
|
+
},
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
#### Event Interception
|
|
925
|
+
|
|
926
|
+
Subscribe to lifecycle events to block, modify, or observe agent behavior.
|
|
927
|
+
|
|
928
|
+
```typescript
|
|
929
|
+
export default function (pi: ExtensionAPI) {
|
|
930
|
+
// Block dangerous commands
|
|
831
931
|
pi.on("tool_call", async (event, ctx) => {
|
|
832
|
-
if (event.toolName === "bash" && /
|
|
833
|
-
const ok = await ctx.ui.confirm("
|
|
932
|
+
if (event.toolName === "bash" && /rm -rf/.test(event.input.command as string)) {
|
|
933
|
+
const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
|
|
834
934
|
if (!ok) return { block: true, reason: "Blocked by user" };
|
|
835
935
|
}
|
|
836
|
-
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
// Modify tool results
|
|
939
|
+
pi.on("tool_result", async (event, ctx) => {
|
|
940
|
+
if (event.toolName === "read") {
|
|
941
|
+
// Redact secrets from file contents
|
|
942
|
+
return { modifiedResult: event.result.replace(/API_KEY=\w+/g, "API_KEY=***") };
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
// Custom compaction
|
|
947
|
+
pi.on("session_before_compact", async (event, ctx) => {
|
|
948
|
+
return { customSummary: "My custom summary of the conversation so far..." };
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// Git checkpoint on each turn
|
|
952
|
+
pi.on("turn_end", async (event, ctx) => {
|
|
953
|
+
await ctx.exec("git", ["stash", "push", "-m", `pi-checkpoint-${Date.now()}`]);
|
|
837
954
|
});
|
|
838
955
|
}
|
|
839
956
|
```
|
|
840
957
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
Use `pi.sendMessage(message, options?)` to inject messages into the session. Messages are persisted as `CustomMessageEntry` and sent to the LLM.
|
|
958
|
+
#### State Persistence
|
|
844
959
|
|
|
845
|
-
|
|
846
|
-
- `triggerTurn`: If true and agent is idle, starts a new agent turn. Default: false.
|
|
847
|
-
- `deliverAs`: When agent is streaming, controls delivery timing:
|
|
848
|
-
- `"steer"` (default): Delivered after current tool execution, interrupts remaining tools.
|
|
849
|
-
- `"followUp"`: Delivered only after agent finishes all work.
|
|
960
|
+
Store state in session entries that survive reload and work correctly with branching.
|
|
850
961
|
|
|
851
962
|
```typescript
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
if (
|
|
860
|
-
|
|
861
|
-
customType: "file-trigger",
|
|
862
|
-
content,
|
|
863
|
-
display: true,
|
|
864
|
-
}, true); // triggerTurn: start agent loop
|
|
963
|
+
export default function (pi: ExtensionAPI) {
|
|
964
|
+
let counter = 0;
|
|
965
|
+
|
|
966
|
+
// Reconstruct state from session history
|
|
967
|
+
const reconstruct = (ctx) => {
|
|
968
|
+
counter = 0;
|
|
969
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
970
|
+
if (entry.type === "custom" && entry.customType === "my_counter") {
|
|
971
|
+
counter = entry.data.value;
|
|
865
972
|
}
|
|
866
|
-
}
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
pi.on("session_start", async (e, ctx) => reconstruct(ctx));
|
|
977
|
+
pi.on("session_branch", async (e, ctx) => reconstruct(ctx));
|
|
978
|
+
pi.on("session_tree", async (e, ctx) => reconstruct(ctx));
|
|
979
|
+
|
|
980
|
+
pi.registerCommand("increment", {
|
|
981
|
+
handler: async (args, ctx) => {
|
|
982
|
+
counter++;
|
|
983
|
+
ctx.appendEntry("my_counter", { value: counter }); // Persisted in session
|
|
984
|
+
ctx.ui.notify(`Counter: ${counter}`, "info");
|
|
985
|
+
},
|
|
867
986
|
});
|
|
868
987
|
}
|
|
869
988
|
```
|
|
870
989
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
> See [examples/hooks/](examples/hooks/) for working examples including permission gates, git checkpointing, and path protection.
|
|
990
|
+
#### Keyboard Shortcuts
|
|
874
991
|
|
|
875
|
-
|
|
992
|
+
Register custom keyboard shortcuts (shown in `/hotkeys`):
|
|
876
993
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
994
|
+
```typescript
|
|
995
|
+
export default function (pi: ExtensionAPI) {
|
|
996
|
+
pi.registerShortcut("ctrl+shift+d", {
|
|
997
|
+
description: "Deploy to production",
|
|
998
|
+
handler: async (ctx) => {
|
|
999
|
+
ctx.ui.notify("Deploying...", "info");
|
|
1000
|
+
await ctx.exec("./deploy.sh", []);
|
|
1001
|
+
},
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
```
|
|
882
1005
|
|
|
883
|
-
|
|
884
|
-
- CLI: `--tool <path>` (any .ts file)
|
|
885
|
-
- Settings: `customTools` array in `settings.json`
|
|
1006
|
+
#### CLI Flags
|
|
886
1007
|
|
|
887
|
-
|
|
1008
|
+
Register custom CLI flags (parsed automatically, shown in `--help`):
|
|
888
1009
|
|
|
889
1010
|
```typescript
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
label: "Greeting",
|
|
896
|
-
description: "Generate a greeting",
|
|
897
|
-
parameters: Type.Object({
|
|
898
|
-
name: Type.String({ description: "Name to greet" }),
|
|
899
|
-
}),
|
|
900
|
-
|
|
901
|
-
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
902
|
-
const { name } = params as { name: string };
|
|
903
|
-
return {
|
|
904
|
-
content: [{ type: "text", text: `Hello, ${name}!` }],
|
|
905
|
-
details: { greeted: name },
|
|
906
|
-
};
|
|
907
|
-
},
|
|
908
|
-
});
|
|
1011
|
+
export default function (pi: ExtensionAPI) {
|
|
1012
|
+
pi.registerFlag("--dry-run", {
|
|
1013
|
+
description: "Run without making changes",
|
|
1014
|
+
type: "boolean",
|
|
1015
|
+
});
|
|
909
1016
|
|
|
910
|
-
|
|
1017
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
1018
|
+
if (pi.getFlag("dry-run") && event.toolName === "write") {
|
|
1019
|
+
return { block: true, reason: "Dry run mode" };
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
911
1023
|
```
|
|
912
1024
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
- Custom rendering via `renderCall()` and `renderResult()` methods
|
|
917
|
-
- Streaming results via `onUpdate` callback
|
|
918
|
-
- Abort handling via `signal` parameter
|
|
919
|
-
- Multiple tools from one factory (return an array)
|
|
1025
|
+
#### Custom UI
|
|
1026
|
+
|
|
1027
|
+
Extensions have full TUI access via `ctx.ui`:
|
|
920
1028
|
|
|
921
|
-
|
|
1029
|
+
```typescript
|
|
1030
|
+
// Simple prompts
|
|
1031
|
+
const confirmed = await ctx.ui.confirm("Title", "Are you sure?");
|
|
1032
|
+
const choice = await ctx.ui.select("Pick one", ["Option A", "Option B"]);
|
|
1033
|
+
const text = await ctx.ui.input("Enter value");
|
|
1034
|
+
|
|
1035
|
+
// Notifications
|
|
1036
|
+
ctx.ui.notify("Done!", "success"); // success, info, warning, error
|
|
1037
|
+
|
|
1038
|
+
// Status line (persistent in footer, multiple extensions can set their own)
|
|
1039
|
+
ctx.ui.setStatus("my-ext", "Processing...");
|
|
1040
|
+
ctx.ui.setStatus("my-ext", null); // Clear
|
|
1041
|
+
|
|
1042
|
+
// Widgets (above editor)
|
|
1043
|
+
ctx.ui.setWidget("my-ext", ["Line 1", "Line 2"]);
|
|
1044
|
+
|
|
1045
|
+
// Full custom component with keyboard handling
|
|
1046
|
+
await ctx.ui.custom((tui, theme, done) => ({
|
|
1047
|
+
render(width) {
|
|
1048
|
+
return [
|
|
1049
|
+
theme.bold("My Component"),
|
|
1050
|
+
theme.fg("dim", "Press Escape to close"),
|
|
1051
|
+
];
|
|
1052
|
+
},
|
|
1053
|
+
handleInput(data) {
|
|
1054
|
+
if (matchesKey(data, "escape")) done();
|
|
1055
|
+
},
|
|
1056
|
+
}));
|
|
1057
|
+
```
|
|
922
1058
|
|
|
923
|
-
> See [
|
|
1059
|
+
> See [docs/extensions.md](docs/extensions.md) for full API reference.
|
|
1060
|
+
> See [docs/tui.md](docs/tui.md) for TUI components and custom rendering.
|
|
1061
|
+
> See [examples/extensions/](examples/extensions/) for working examples.
|
|
924
1062
|
|
|
925
1063
|
---
|
|
926
1064
|
|
|
@@ -934,7 +1072,7 @@ pi [options] [@files...] [messages...]
|
|
|
934
1072
|
|
|
935
1073
|
| Option | Description |
|
|
936
1074
|
|--------|-------------|
|
|
937
|
-
| `--provider <name>` | Provider: `anthropic`, `openai`, `google`, `mistral`, `xai`, `groq`, `cerebras`, `openrouter`, `zai`, `github-copilot`, `google-gemini-cli`, `google-antigravity`, or custom |
|
|
1075
|
+
| `--provider <name>` | Provider: `anthropic`, `openai`, `openai-codex`, `google`, `mistral`, `xai`, `groq`, `cerebras`, `openrouter`, `zai`, `github-copilot`, `google-gemini-cli`, `google-antigravity`, or custom |
|
|
938
1076
|
| `--model <id>` | Model ID |
|
|
939
1077
|
| `--api-key <key>` | API key (overrides environment) |
|
|
940
1078
|
| `--system-prompt <text\|file>` | Custom system prompt (text or file path) |
|
|
@@ -949,7 +1087,7 @@ pi [options] [@files...] [messages...]
|
|
|
949
1087
|
| `--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`) |
|
|
950
1088
|
| `--tools <tools>` | Comma-separated tool list (default: `read,bash,edit,write`) |
|
|
951
1089
|
| `--thinking <level>` | Thinking level: `off`, `minimal`, `low`, `medium`, `high` |
|
|
952
|
-
| `--
|
|
1090
|
+
| `--extension <path>`, `-e` | Load an extension file (can be used multiple times) |
|
|
953
1091
|
| `--no-skills` | Disable skills discovery and loading |
|
|
954
1092
|
| `--skills <patterns>` | Comma-separated glob patterns to filter skills (e.g., `git-*,docker`) |
|
|
955
1093
|
| `--export <file> [output]` | Export session to HTML |
|
|
@@ -1033,7 +1171,7 @@ Available via `--tools` flag:
|
|
|
1033
1171
|
|
|
1034
1172
|
Example: `--tools read,grep,find,ls` for code review without modification.
|
|
1035
1173
|
|
|
1036
|
-
For adding new tools, see [
|
|
1174
|
+
For adding new tools, see [Extensions](#extensions) in the Customization section.
|
|
1037
1175
|
|
|
1038
1176
|
---
|
|
1039
1177
|
|
|
@@ -1068,8 +1206,8 @@ The SDK provides full control over:
|
|
|
1068
1206
|
- Model selection and thinking level
|
|
1069
1207
|
- System prompt (replace or modify)
|
|
1070
1208
|
- Tools (built-in subsets, custom tools)
|
|
1071
|
-
-
|
|
1072
|
-
- Skills, context files,
|
|
1209
|
+
- Extensions (discovered or via paths)
|
|
1210
|
+
- Skills, context files, prompt templates
|
|
1073
1211
|
- Session persistence (`SessionManager`)
|
|
1074
1212
|
- Settings (`SettingsManager`)
|
|
1075
1213
|
- API key resolution and OAuth
|
|
@@ -1101,7 +1239,7 @@ pi --export session.jsonl # Auto-generated filename
|
|
|
1101
1239
|
pi --export session.jsonl output.html # Custom filename
|
|
1102
1240
|
```
|
|
1103
1241
|
|
|
1104
|
-
Works with
|
|
1242
|
+
Works with session files.
|
|
1105
1243
|
|
|
1106
1244
|
---
|
|
1107
1245
|
|
|
@@ -1111,13 +1249,13 @@ Pi is opinionated about what it won't do. These are intentional design decisions
|
|
|
1111
1249
|
|
|
1112
1250
|
**No MCP.** Build CLI tools with READMEs (see [Skills](#skills)). The agent reads them on demand. [Would you like to know more?](https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/)
|
|
1113
1251
|
|
|
1114
|
-
**No sub-agents.** Spawn pi instances via tmux, or [build your own sub-agent tool](examples/
|
|
1252
|
+
**No sub-agents.** Spawn pi instances via tmux, or [build your own sub-agent tool](examples/extensions/subagent/) with [Extensions](#extensions). Full observability and steerability.
|
|
1115
1253
|
|
|
1116
|
-
**No permission popups.** Security theater. Run in a container or build your own with [
|
|
1254
|
+
**No permission popups.** Security theater. Run in a container or build your own with [Extensions](#extensions).
|
|
1117
1255
|
|
|
1118
1256
|
**No plan mode.** Gather context in one session, write plans to file, start fresh for implementation.
|
|
1119
1257
|
|
|
1120
|
-
**No built-in to-dos.** They confuse models. Use a TODO.md file, or [build your own](examples/
|
|
1258
|
+
**No built-in to-dos.** They confuse models. Use a TODO.md file, or [build your own](examples/extensions/todo.ts) with [Extensions](#extensions).
|
|
1121
1259
|
|
|
1122
1260
|
**No background bash.** Use tmux. Full observability, direct interaction.
|
|
1123
1261
|
|
|
@@ -1168,3 +1306,4 @@ MIT
|
|
|
1168
1306
|
|
|
1169
1307
|
- [@mariozechner/pi-ai](https://www.npmjs.com/package/@mariozechner/pi-ai): Core LLM toolkit
|
|
1170
1308
|
- [@mariozechner/pi-agent](https://www.npmjs.com/package/@mariozechner/pi-agent): Agent framework
|
|
1309
|
+
- [@mariozechner/pi-tui](https://www.npmjs.com/package/@mariozechner/pi-tui): Terminal UI components
|
package/dist/cli/args.d.ts
CHANGED
|
@@ -21,8 +21,7 @@ export interface Args {
|
|
|
21
21
|
sessionDir?: string;
|
|
22
22
|
models?: string[];
|
|
23
23
|
tools?: ToolName[];
|
|
24
|
-
|
|
25
|
-
customTools?: string[];
|
|
24
|
+
extensions?: string[];
|
|
26
25
|
print?: boolean;
|
|
27
26
|
export?: string;
|
|
28
27
|
noSkills?: boolean;
|
|
@@ -30,11 +29,11 @@ export interface Args {
|
|
|
30
29
|
listModels?: string | true;
|
|
31
30
|
messages: string[];
|
|
32
31
|
fileArgs: string[];
|
|
33
|
-
/** Unknown flags (potentially
|
|
32
|
+
/** Unknown flags (potentially extension flags) - map of flag name to value */
|
|
34
33
|
unknownFlags: Map<string, boolean | string>;
|
|
35
34
|
}
|
|
36
35
|
export declare function isValidThinkingLevel(level: string): level is ThinkingLevel;
|
|
37
|
-
export declare function parseArgs(args: string[],
|
|
36
|
+
export declare function parseArgs(args: string[], extensionFlags?: Map<string, {
|
|
38
37
|
type: "boolean" | "string";
|
|
39
38
|
}>): Args;
|
|
40
39
|
export declare function printHelp(): void;
|
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;IACnB,yEAAyE;IACzE,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;CAC5C;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAE1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC,GAAG,IAAI,CA2GvG;AAED,wBAAgB,SAAS,IAAI,IAAI,CAiGhC","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\t/** Unknown flags (potentially hook flags) - map of flag name to value */\n\tunknownFlags: Map<string, boolean | 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[], hookFlags?: Map<string, { type: \"boolean\" | \"string\" }>): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t\tunknownFlags: new Map(),\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(\"--\") && hookFlags) {\n\t\t\t// Check if it's a hook-registered flag\n\t\t\tconst flagName = arg.slice(2);\n\t\t\tconst hookFlag = hookFlags.get(flagName);\n\t\t\tif (hookFlag) {\n\t\t\t\tif (hookFlag.type === \"boolean\") {\n\t\t\t\t\tresult.unknownFlags.set(flagName, true);\n\t\t\t\t} else if (hookFlag.type === \"string\" && i + 1 < args.length) {\n\t\t\t\t\tresult.unknownFlags.set(flagName, args[++i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Unknown flags without hookFlags are silently ignored (first pass)\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\nHooks can register additional flags (e.g., --plan from plan-mode hook).\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"]}
|
|
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,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,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;IACnB,8EAA8E;IAC9E,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;CAC5C;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAE1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC,GAAG,IAAI,CAwG5G;AAED,wBAAgB,SAAS,IAAI,IAAI,CAgGhC","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\textensions?: string[];\n\tprint?: boolean;\n\texport?: string;\n\tnoSkills?: boolean;\n\tskills?: string[];\n\tlistModels?: string | true;\n\tmessages: string[];\n\tfileArgs: string[];\n\t/** Unknown flags (potentially extension flags) - map of flag name to value */\n\tunknownFlags: Map<string, boolean | 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[], extensionFlags?: Map<string, { type: \"boolean\" | \"string\" }>): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t\tunknownFlags: new Map(),\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 === \"--extension\" || arg === \"-e\") && i + 1 < args.length) {\n\t\t\tresult.extensions = result.extensions ?? [];\n\t\t\tresult.extensions.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(\"--\") && extensionFlags) {\n\t\t\t// Check if it's an extension-registered flag\n\t\t\tconst flagName = arg.slice(2);\n\t\t\tconst extFlag = extensionFlags.get(flagName);\n\t\t\tif (extFlag) {\n\t\t\t\tif (extFlag.type === \"boolean\") {\n\t\t\t\t\tresult.unknownFlags.set(flagName, true);\n\t\t\t\t} else if (extFlag.type === \"string\" && i + 1 < args.length) {\n\t\t\t\t\tresult.unknownFlags.set(flagName, args[++i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Unknown flags without extensionFlags are silently ignored (first pass)\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 --extension, -e <path> Load an extension 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\nExtensions can register additional flags (e.g., --plan from plan-mode extension).\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"]}
|