@mariozechner/pi-coding-agent 0.34.2 → 0.35.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 +204 -0
- package/README.md +233 -105
- 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/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/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 +40 -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)
|
|
@@ -374,10 +373,9 @@ The output becomes part of your next prompt, formatted as:
|
|
|
374
373
|
|
|
375
374
|
```
|
|
376
375
|
Ran `ls -la`
|
|
377
|
-
|
|
376
|
+
|
|
378
377
|
<output here>
|
|
379
378
|
```
|
|
380
|
-
```
|
|
381
379
|
|
|
382
380
|
Run multiple commands before prompting; all outputs are included together.
|
|
383
381
|
|
|
@@ -453,7 +451,7 @@ When disabled, neither case triggers automatic compaction (use `/compact` manual
|
|
|
453
451
|
|
|
454
452
|
> **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
453
|
|
|
456
|
-
See [docs/compaction.md](docs/compaction.md) for how compaction works internally and how to customize it via
|
|
454
|
+
See [docs/compaction.md](docs/compaction.md) for how compaction works internally and how to customize it via extensions.
|
|
457
455
|
|
|
458
456
|
### Branching
|
|
459
457
|
|
|
@@ -667,8 +665,7 @@ Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|
|
667
665
|
"images": {
|
|
668
666
|
"autoResize": true
|
|
669
667
|
},
|
|
670
|
-
"
|
|
671
|
-
"customTools": ["/path/to/tool.ts"]
|
|
668
|
+
"extensions": ["/path/to/extension.ts"]
|
|
672
669
|
}
|
|
673
670
|
```
|
|
674
671
|
|
|
@@ -694,12 +691,11 @@ Global `~/.pi/agent/settings.json` stores persistent preferences:
|
|
|
694
691
|
| `terminal.showImages` | Render images inline (supported terminals) | `true` |
|
|
695
692
|
| `images.autoResize` | Auto-resize images to 2000x2000 max for better model compatibility | `true` |
|
|
696
693
|
| `doubleEscapeAction` | Action for double-escape with empty editor: `tree` or `branch` | `tree` |
|
|
697
|
-
| `
|
|
698
|
-
| `customTools` | Additional custom tool file paths | `[]` |
|
|
694
|
+
| `extensions` | Additional extension file paths | `[]` |
|
|
699
695
|
|
|
700
696
|
---
|
|
701
697
|
|
|
702
|
-
##
|
|
698
|
+
## Customization
|
|
703
699
|
|
|
704
700
|
### Themes
|
|
705
701
|
|
|
@@ -720,13 +716,13 @@ Select with `/settings`, then edit the file. Changes apply on save.
|
|
|
720
716
|
|
|
721
717
|
**VS Code terminal fix:** Set `terminal.integrated.minimumContrastRatio` to `1` for accurate colors.
|
|
722
718
|
|
|
723
|
-
###
|
|
719
|
+
### Prompt Templates
|
|
724
720
|
|
|
725
721
|
Define reusable prompts as Markdown files:
|
|
726
722
|
|
|
727
723
|
**Locations:**
|
|
728
|
-
- Global: `~/.pi/agent/
|
|
729
|
-
- Project: `.pi/
|
|
724
|
+
- Global: `~/.pi/agent/prompts/*.md`
|
|
725
|
+
- Project: `.pi/prompts/*.md`
|
|
730
726
|
|
|
731
727
|
**Format:**
|
|
732
728
|
|
|
@@ -755,7 +751,7 @@ Usage: `/component Button "onClick handler" "disabled support"`
|
|
|
755
751
|
- `$1` = `Button`
|
|
756
752
|
- `$@` or `$ARGUMENTS` = all arguments joined (`Button onClick handler disabled support`)
|
|
757
753
|
|
|
758
|
-
**Namespacing:** Subdirectories create prefixes. `.pi/
|
|
754
|
+
**Namespacing:** Subdirectories create prefixes. `.pi/prompts/frontend/component.md` → `/component (project:frontend)`
|
|
759
755
|
|
|
760
756
|
|
|
761
757
|
### Skills
|
|
@@ -807,120 +803,251 @@ cd /path/to/brave-search && npm install
|
|
|
807
803
|
|
|
808
804
|
> See [docs/skills.md](docs/skills.md) for details, examples, and links to skill repositories. pi can help you create new skills.
|
|
809
805
|
|
|
810
|
-
###
|
|
806
|
+
### Extensions
|
|
807
|
+
|
|
808
|
+
Extensions are TypeScript modules that extend pi's behavior.
|
|
809
|
+
|
|
810
|
+
**Use cases:**
|
|
811
|
+
- **Custom tools** - Register tools callable by the LLM with custom UI and rendering
|
|
812
|
+
- **Custom commands** - Add `/commands` for users (e.g., `/deploy`, `/stats`)
|
|
813
|
+
- **Event interception** - Block tool calls, modify results, customize compaction
|
|
814
|
+
- **State persistence** - Store data in session, reconstruct on reload/branch
|
|
815
|
+
- **External integrations** - File watchers, webhooks, git checkpointing
|
|
816
|
+
- **Custom UI** - Full TUI control from tools, commands, or event handlers
|
|
817
|
+
|
|
818
|
+
**Locations:**
|
|
819
|
+
- Global: `~/.pi/agent/extensions/*.ts` or `~/.pi/agent/extensions/*/index.ts`
|
|
820
|
+
- Project: `.pi/extensions/*.ts` or `.pi/extensions/*/index.ts`
|
|
821
|
+
- CLI: `--extension <path>` or `-e <path>`
|
|
811
822
|
|
|
812
|
-
|
|
823
|
+
**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/).
|
|
824
|
+
|
|
825
|
+
#### Custom Tools
|
|
826
|
+
|
|
827
|
+
Tools are functions the LLM can call. They appear in the system prompt and can have custom rendering.
|
|
828
|
+
|
|
829
|
+
```typescript
|
|
830
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
831
|
+
import { Type } from "@sinclair/typebox";
|
|
832
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
833
|
+
|
|
834
|
+
export default function (pi: ExtensionAPI) {
|
|
835
|
+
pi.registerTool({
|
|
836
|
+
name: "deploy",
|
|
837
|
+
label: "Deploy",
|
|
838
|
+
description: "Deploy the application to production",
|
|
839
|
+
parameters: Type.Object({
|
|
840
|
+
environment: Type.String({ description: "Target environment" }),
|
|
841
|
+
}),
|
|
842
|
+
|
|
843
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
844
|
+
// Show progress via onUpdate
|
|
845
|
+
onUpdate({ status: "Deploying..." });
|
|
846
|
+
|
|
847
|
+
// Ask user for confirmation
|
|
848
|
+
const ok = await ctx.ui.confirm("Deploy?", `Deploy to ${params.environment}?`);
|
|
849
|
+
if (!ok) {
|
|
850
|
+
return { content: [{ type: "text", text: "Cancelled" }], details: { cancelled: true } };
|
|
851
|
+
}
|
|
813
852
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
853
|
+
// Run shell commands
|
|
854
|
+
const result = await ctx.exec("./deploy.sh", [params.environment], { signal });
|
|
855
|
+
|
|
856
|
+
return {
|
|
857
|
+
content: [{ type: "text", text: result.stdout }],
|
|
858
|
+
details: { environment: params.environment, exitCode: result.exitCode },
|
|
859
|
+
};
|
|
860
|
+
},
|
|
861
|
+
|
|
862
|
+
// Custom TUI rendering (optional)
|
|
863
|
+
renderCall(args, theme) {
|
|
864
|
+
return new Text(theme.bold("deploy ") + theme.fg("accent", args.environment), 0, 0);
|
|
865
|
+
},
|
|
866
|
+
renderResult(result, options, theme) {
|
|
867
|
+
const ok = result.details?.exitCode === 0;
|
|
868
|
+
return new Text(ok ? theme.fg("success", "✓ Deployed") : theme.fg("error", "✗ Failed"), 0, 0);
|
|
869
|
+
},
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
```
|
|
819
873
|
|
|
820
|
-
|
|
821
|
-
- Global: `~/.pi/agent/hooks/*.ts`
|
|
822
|
-
- Project: `.pi/hooks/*.ts`
|
|
823
|
-
- CLI: `--hook <path>` (for debugging)
|
|
874
|
+
#### Custom Commands
|
|
824
875
|
|
|
825
|
-
|
|
876
|
+
Commands are user-invoked via `/name`. They can show custom UI, modify state, or trigger agent turns.
|
|
826
877
|
|
|
827
878
|
```typescript
|
|
828
|
-
|
|
879
|
+
export default function (pi: ExtensionAPI) {
|
|
880
|
+
pi.registerCommand("stats", {
|
|
881
|
+
description: "Show session statistics",
|
|
882
|
+
handler: async (args, ctx) => {
|
|
883
|
+
// Simple notification
|
|
884
|
+
ctx.ui.notify(`${ctx.sessionManager.getEntries().length} entries`, "info");
|
|
885
|
+
},
|
|
886
|
+
});
|
|
829
887
|
|
|
830
|
-
|
|
888
|
+
pi.registerCommand("todos", {
|
|
889
|
+
description: "Interactive todo viewer",
|
|
890
|
+
handler: async (args, ctx) => {
|
|
891
|
+
// Full custom UI with keyboard handling
|
|
892
|
+
await ctx.ui.custom((tui, theme, done) => {
|
|
893
|
+
return {
|
|
894
|
+
render(width) {
|
|
895
|
+
return [
|
|
896
|
+
theme.bold("Todos"),
|
|
897
|
+
"- [ ] Item 1",
|
|
898
|
+
"- [x] Item 2",
|
|
899
|
+
"",
|
|
900
|
+
theme.fg("dim", "Press Escape to close"),
|
|
901
|
+
];
|
|
902
|
+
},
|
|
903
|
+
handleInput(data) {
|
|
904
|
+
if (matchesKey(data, "escape")) done();
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
});
|
|
908
|
+
},
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
#### Event Interception
|
|
914
|
+
|
|
915
|
+
Subscribe to lifecycle events to block, modify, or observe agent behavior.
|
|
916
|
+
|
|
917
|
+
```typescript
|
|
918
|
+
export default function (pi: ExtensionAPI) {
|
|
919
|
+
// Block dangerous commands
|
|
831
920
|
pi.on("tool_call", async (event, ctx) => {
|
|
832
|
-
if (event.toolName === "bash" && /
|
|
833
|
-
const ok = await ctx.ui.confirm("
|
|
921
|
+
if (event.toolName === "bash" && /rm -rf/.test(event.input.command as string)) {
|
|
922
|
+
const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
|
|
834
923
|
if (!ok) return { block: true, reason: "Blocked by user" };
|
|
835
924
|
}
|
|
836
|
-
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
// Modify tool results
|
|
928
|
+
pi.on("tool_result", async (event, ctx) => {
|
|
929
|
+
if (event.toolName === "read") {
|
|
930
|
+
// Redact secrets from file contents
|
|
931
|
+
return { modifiedResult: event.result.replace(/API_KEY=\w+/g, "API_KEY=***") };
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
// Custom compaction
|
|
936
|
+
pi.on("session_before_compact", async (event, ctx) => {
|
|
937
|
+
return { customSummary: "My custom summary of the conversation so far..." };
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
// Git checkpoint on each turn
|
|
941
|
+
pi.on("turn_end", async (event, ctx) => {
|
|
942
|
+
await ctx.exec("git", ["stash", "push", "-m", `pi-checkpoint-${Date.now()}`]);
|
|
837
943
|
});
|
|
838
944
|
}
|
|
839
945
|
```
|
|
840
946
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
Use `pi.sendMessage(message, options?)` to inject messages into the session. Messages are persisted as `CustomMessageEntry` and sent to the LLM.
|
|
947
|
+
#### State Persistence
|
|
844
948
|
|
|
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.
|
|
949
|
+
Store state in session entries that survive reload and work correctly with branching.
|
|
850
950
|
|
|
851
951
|
```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
|
|
952
|
+
export default function (pi: ExtensionAPI) {
|
|
953
|
+
let counter = 0;
|
|
954
|
+
|
|
955
|
+
// Reconstruct state from session history
|
|
956
|
+
const reconstruct = (ctx) => {
|
|
957
|
+
counter = 0;
|
|
958
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
959
|
+
if (entry.type === "custom" && entry.customType === "my_counter") {
|
|
960
|
+
counter = entry.data.value;
|
|
865
961
|
}
|
|
866
|
-
}
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
pi.on("session_start", async (e, ctx) => reconstruct(ctx));
|
|
966
|
+
pi.on("session_branch", async (e, ctx) => reconstruct(ctx));
|
|
967
|
+
pi.on("session_tree", async (e, ctx) => reconstruct(ctx));
|
|
968
|
+
|
|
969
|
+
pi.registerCommand("increment", {
|
|
970
|
+
handler: async (args, ctx) => {
|
|
971
|
+
counter++;
|
|
972
|
+
ctx.appendEntry("my_counter", { value: counter }); // Persisted in session
|
|
973
|
+
ctx.ui.notify(`Counter: ${counter}`, "info");
|
|
974
|
+
},
|
|
867
975
|
});
|
|
868
976
|
}
|
|
869
977
|
```
|
|
870
978
|
|
|
871
|
-
|
|
979
|
+
#### Keyboard Shortcuts
|
|
872
980
|
|
|
873
|
-
|
|
981
|
+
Register custom keyboard shortcuts (shown in `/hotkeys`):
|
|
874
982
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
983
|
+
```typescript
|
|
984
|
+
export default function (pi: ExtensionAPI) {
|
|
985
|
+
pi.registerShortcut("ctrl+shift+d", {
|
|
986
|
+
description: "Deploy to production",
|
|
987
|
+
handler: async (ctx) => {
|
|
988
|
+
ctx.ui.notify("Deploying...", "info");
|
|
989
|
+
await ctx.exec("./deploy.sh", []);
|
|
990
|
+
},
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
```
|
|
882
994
|
|
|
883
|
-
|
|
884
|
-
- CLI: `--tool <path>` (any .ts file)
|
|
885
|
-
- Settings: `customTools` array in `settings.json`
|
|
995
|
+
#### CLI Flags
|
|
886
996
|
|
|
887
|
-
|
|
997
|
+
Register custom CLI flags (parsed automatically, shown in `--help`):
|
|
888
998
|
|
|
889
999
|
```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
|
-
});
|
|
1000
|
+
export default function (pi: ExtensionAPI) {
|
|
1001
|
+
pi.registerFlag("--dry-run", {
|
|
1002
|
+
description: "Run without making changes",
|
|
1003
|
+
type: "boolean",
|
|
1004
|
+
});
|
|
909
1005
|
|
|
910
|
-
|
|
1006
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
1007
|
+
if (pi.getFlag("dry-run") && event.toolName === "write") {
|
|
1008
|
+
return { block: true, reason: "Dry run mode" };
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
911
1012
|
```
|
|
912
1013
|
|
|
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)
|
|
1014
|
+
#### Custom UI
|
|
1015
|
+
|
|
1016
|
+
Extensions have full TUI access via `ctx.ui`:
|
|
920
1017
|
|
|
921
|
-
|
|
1018
|
+
```typescript
|
|
1019
|
+
// Simple prompts
|
|
1020
|
+
const confirmed = await ctx.ui.confirm("Title", "Are you sure?");
|
|
1021
|
+
const choice = await ctx.ui.select("Pick one", ["Option A", "Option B"]);
|
|
1022
|
+
const text = await ctx.ui.input("Enter value");
|
|
1023
|
+
|
|
1024
|
+
// Notifications
|
|
1025
|
+
ctx.ui.notify("Done!", "success"); // success, info, warning, error
|
|
1026
|
+
|
|
1027
|
+
// Status line (persistent in footer, multiple extensions can set their own)
|
|
1028
|
+
ctx.ui.setStatus("my-ext", "Processing...");
|
|
1029
|
+
ctx.ui.setStatus("my-ext", null); // Clear
|
|
1030
|
+
|
|
1031
|
+
// Widgets (above editor)
|
|
1032
|
+
ctx.ui.setWidget("my-ext", ["Line 1", "Line 2"]);
|
|
1033
|
+
|
|
1034
|
+
// Full custom component with keyboard handling
|
|
1035
|
+
await ctx.ui.custom((tui, theme, done) => ({
|
|
1036
|
+
render(width) {
|
|
1037
|
+
return [
|
|
1038
|
+
theme.bold("My Component"),
|
|
1039
|
+
theme.fg("dim", "Press Escape to close"),
|
|
1040
|
+
];
|
|
1041
|
+
},
|
|
1042
|
+
handleInput(data) {
|
|
1043
|
+
if (matchesKey(data, "escape")) done();
|
|
1044
|
+
},
|
|
1045
|
+
}));
|
|
1046
|
+
```
|
|
922
1047
|
|
|
923
|
-
> See [
|
|
1048
|
+
> See [docs/extensions.md](docs/extensions.md) for full API reference.
|
|
1049
|
+
> See [docs/tui.md](docs/tui.md) for TUI components and custom rendering.
|
|
1050
|
+
> See [examples/extensions/](examples/extensions/) for working examples.
|
|
924
1051
|
|
|
925
1052
|
---
|
|
926
1053
|
|
|
@@ -949,7 +1076,7 @@ pi [options] [@files...] [messages...]
|
|
|
949
1076
|
| `--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
1077
|
| `--tools <tools>` | Comma-separated tool list (default: `read,bash,edit,write`) |
|
|
951
1078
|
| `--thinking <level>` | Thinking level: `off`, `minimal`, `low`, `medium`, `high` |
|
|
952
|
-
| `--
|
|
1079
|
+
| `--extension <path>`, `-e` | Load an extension file (can be used multiple times) |
|
|
953
1080
|
| `--no-skills` | Disable skills discovery and loading |
|
|
954
1081
|
| `--skills <patterns>` | Comma-separated glob patterns to filter skills (e.g., `git-*,docker`) |
|
|
955
1082
|
| `--export <file> [output]` | Export session to HTML |
|
|
@@ -1033,7 +1160,7 @@ Available via `--tools` flag:
|
|
|
1033
1160
|
|
|
1034
1161
|
Example: `--tools read,grep,find,ls` for code review without modification.
|
|
1035
1162
|
|
|
1036
|
-
For adding new tools, see [
|
|
1163
|
+
For adding new tools, see [Extensions](#extensions) in the Customization section.
|
|
1037
1164
|
|
|
1038
1165
|
---
|
|
1039
1166
|
|
|
@@ -1068,8 +1195,8 @@ The SDK provides full control over:
|
|
|
1068
1195
|
- Model selection and thinking level
|
|
1069
1196
|
- System prompt (replace or modify)
|
|
1070
1197
|
- Tools (built-in subsets, custom tools)
|
|
1071
|
-
-
|
|
1072
|
-
- Skills, context files,
|
|
1198
|
+
- Extensions (discovered or via paths)
|
|
1199
|
+
- Skills, context files, prompt templates
|
|
1073
1200
|
- Session persistence (`SessionManager`)
|
|
1074
1201
|
- Settings (`SettingsManager`)
|
|
1075
1202
|
- API key resolution and OAuth
|
|
@@ -1101,7 +1228,7 @@ pi --export session.jsonl # Auto-generated filename
|
|
|
1101
1228
|
pi --export session.jsonl output.html # Custom filename
|
|
1102
1229
|
```
|
|
1103
1230
|
|
|
1104
|
-
Works with
|
|
1231
|
+
Works with session files.
|
|
1105
1232
|
|
|
1106
1233
|
---
|
|
1107
1234
|
|
|
@@ -1111,13 +1238,13 @@ Pi is opinionated about what it won't do. These are intentional design decisions
|
|
|
1111
1238
|
|
|
1112
1239
|
**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
1240
|
|
|
1114
|
-
**No sub-agents.** Spawn pi instances via tmux, or [build your own sub-agent tool](examples/
|
|
1241
|
+
**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
1242
|
|
|
1116
|
-
**No permission popups.** Security theater. Run in a container or build your own with [
|
|
1243
|
+
**No permission popups.** Security theater. Run in a container or build your own with [Extensions](#extensions).
|
|
1117
1244
|
|
|
1118
1245
|
**No plan mode.** Gather context in one session, write plans to file, start fresh for implementation.
|
|
1119
1246
|
|
|
1120
|
-
**No built-in to-dos.** They confuse models. Use a TODO.md file, or [build your own](examples/
|
|
1247
|
+
**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
1248
|
|
|
1122
1249
|
**No background bash.** Use tmux. Full observability, direct interaction.
|
|
1123
1250
|
|
|
@@ -1168,3 +1295,4 @@ MIT
|
|
|
1168
1295
|
|
|
1169
1296
|
- [@mariozechner/pi-ai](https://www.npmjs.com/package/@mariozechner/pi-ai): Core LLM toolkit
|
|
1170
1297
|
- [@mariozechner/pi-agent](https://www.npmjs.com/package/@mariozechner/pi-agent): Agent framework
|
|
1298
|
+
- [@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"]}
|
package/dist/cli/args.js
CHANGED
|
@@ -8,7 +8,7 @@ const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh
|
|
|
8
8
|
export function isValidThinkingLevel(level) {
|
|
9
9
|
return VALID_THINKING_LEVELS.includes(level);
|
|
10
10
|
}
|
|
11
|
-
export function parseArgs(args,
|
|
11
|
+
export function parseArgs(args, extensionFlags) {
|
|
12
12
|
const result = {
|
|
13
13
|
messages: [],
|
|
14
14
|
fileArgs: [],
|
|
@@ -89,13 +89,9 @@ export function parseArgs(args, hookFlags) {
|
|
|
89
89
|
else if (arg === "--export" && i + 1 < args.length) {
|
|
90
90
|
result.export = args[++i];
|
|
91
91
|
}
|
|
92
|
-
else if (arg === "--
|
|
93
|
-
result.
|
|
94
|
-
result.
|
|
95
|
-
}
|
|
96
|
-
else if (arg === "--tool" && i + 1 < args.length) {
|
|
97
|
-
result.customTools = result.customTools ?? [];
|
|
98
|
-
result.customTools.push(args[++i]);
|
|
92
|
+
else if ((arg === "--extension" || arg === "-e") && i + 1 < args.length) {
|
|
93
|
+
result.extensions = result.extensions ?? [];
|
|
94
|
+
result.extensions.push(args[++i]);
|
|
99
95
|
}
|
|
100
96
|
else if (arg === "--no-skills") {
|
|
101
97
|
result.noSkills = true;
|
|
@@ -116,19 +112,19 @@ export function parseArgs(args, hookFlags) {
|
|
|
116
112
|
else if (arg.startsWith("@")) {
|
|
117
113
|
result.fileArgs.push(arg.slice(1)); // Remove @ prefix
|
|
118
114
|
}
|
|
119
|
-
else if (arg.startsWith("--") &&
|
|
120
|
-
// Check if it's
|
|
115
|
+
else if (arg.startsWith("--") && extensionFlags) {
|
|
116
|
+
// Check if it's an extension-registered flag
|
|
121
117
|
const flagName = arg.slice(2);
|
|
122
|
-
const
|
|
123
|
-
if (
|
|
124
|
-
if (
|
|
118
|
+
const extFlag = extensionFlags.get(flagName);
|
|
119
|
+
if (extFlag) {
|
|
120
|
+
if (extFlag.type === "boolean") {
|
|
125
121
|
result.unknownFlags.set(flagName, true);
|
|
126
122
|
}
|
|
127
|
-
else if (
|
|
123
|
+
else if (extFlag.type === "string" && i + 1 < args.length) {
|
|
128
124
|
result.unknownFlags.set(flagName, args[++i]);
|
|
129
125
|
}
|
|
130
126
|
}
|
|
131
|
-
// Unknown flags without
|
|
127
|
+
// Unknown flags without extensionFlags are silently ignored (first pass)
|
|
132
128
|
}
|
|
133
129
|
else if (!arg.startsWith("-")) {
|
|
134
130
|
result.messages.push(arg);
|
|
@@ -160,8 +156,7 @@ ${chalk.bold("Options:")}
|
|
|
160
156
|
--tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)
|
|
161
157
|
Available: read, bash, edit, write, grep, find, ls
|
|
162
158
|
--thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
|
|
163
|
-
--
|
|
164
|
-
--tool <path> Load a custom tool file (can be used multiple times)
|
|
159
|
+
--extension, -e <path> Load an extension file (can be used multiple times)
|
|
165
160
|
--no-skills Disable skills discovery and loading
|
|
166
161
|
--skills <patterns> Comma-separated glob patterns to filter skills (e.g., git-*,docker)
|
|
167
162
|
--export <file> Export session file to HTML and exit
|
|
@@ -169,7 +164,7 @@ ${chalk.bold("Options:")}
|
|
|
169
164
|
--help, -h Show this help
|
|
170
165
|
--version, -v Show version number
|
|
171
166
|
|
|
172
|
-
|
|
167
|
+
Extensions can register additional flags (e.g., --plan from plan-mode extension).
|
|
173
168
|
|
|
174
169
|
${chalk.bold("Examples:")}
|
|
175
170
|
# Interactive mode
|