@oh-my-pi/pi-coding-agent 3.37.0 → 4.0.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/README.md +44 -3
  3. package/docs/extensions.md +29 -4
  4. package/docs/sdk.md +3 -3
  5. package/package.json +5 -5
  6. package/src/cli/args.ts +8 -0
  7. package/src/config.ts +5 -15
  8. package/src/core/agent-session.ts +193 -47
  9. package/src/core/auth-storage.ts +16 -3
  10. package/src/core/bash-executor.ts +79 -14
  11. package/src/core/custom-commands/types.ts +1 -1
  12. package/src/core/custom-tools/types.ts +1 -1
  13. package/src/core/export-html/index.ts +33 -1
  14. package/src/core/export-html/template.css +99 -0
  15. package/src/core/export-html/template.generated.ts +1 -1
  16. package/src/core/export-html/template.js +133 -8
  17. package/src/core/extensions/index.ts +22 -4
  18. package/src/core/extensions/loader.ts +152 -214
  19. package/src/core/extensions/runner.ts +139 -79
  20. package/src/core/extensions/types.ts +143 -19
  21. package/src/core/extensions/wrapper.ts +5 -8
  22. package/src/core/hooks/types.ts +1 -1
  23. package/src/core/index.ts +2 -1
  24. package/src/core/keybindings.ts +4 -1
  25. package/src/core/model-registry.ts +1 -1
  26. package/src/core/model-resolver.ts +35 -26
  27. package/src/core/sdk.ts +96 -76
  28. package/src/core/settings-manager.ts +45 -14
  29. package/src/core/system-prompt.ts +5 -15
  30. package/src/core/tools/bash.ts +115 -54
  31. package/src/core/tools/find.ts +86 -7
  32. package/src/core/tools/grep.ts +27 -6
  33. package/src/core/tools/index.ts +15 -6
  34. package/src/core/tools/ls.ts +49 -18
  35. package/src/core/tools/render-utils.ts +2 -1
  36. package/src/core/tools/task/worker.ts +35 -12
  37. package/src/core/tools/web-search/auth.ts +37 -32
  38. package/src/core/tools/web-search/providers/anthropic.ts +35 -22
  39. package/src/index.ts +101 -9
  40. package/src/main.ts +60 -20
  41. package/src/migrations.ts +47 -2
  42. package/src/modes/index.ts +2 -2
  43. package/src/modes/interactive/components/assistant-message.ts +25 -7
  44. package/src/modes/interactive/components/bash-execution.ts +5 -0
  45. package/src/modes/interactive/components/branch-summary-message.ts +5 -0
  46. package/src/modes/interactive/components/compaction-summary-message.ts +5 -0
  47. package/src/modes/interactive/components/countdown-timer.ts +38 -0
  48. package/src/modes/interactive/components/custom-editor.ts +8 -0
  49. package/src/modes/interactive/components/custom-message.ts +5 -0
  50. package/src/modes/interactive/components/footer.ts +2 -5
  51. package/src/modes/interactive/components/hook-input.ts +29 -20
  52. package/src/modes/interactive/components/hook-selector.ts +52 -38
  53. package/src/modes/interactive/components/index.ts +39 -0
  54. package/src/modes/interactive/components/login-dialog.ts +160 -0
  55. package/src/modes/interactive/components/model-selector.ts +10 -2
  56. package/src/modes/interactive/components/session-selector.ts +5 -1
  57. package/src/modes/interactive/components/settings-defs.ts +9 -0
  58. package/src/modes/interactive/components/status-line/segments.ts +3 -3
  59. package/src/modes/interactive/components/tool-execution.ts +9 -16
  60. package/src/modes/interactive/components/tree-selector.ts +1 -6
  61. package/src/modes/interactive/interactive-mode.ts +466 -215
  62. package/src/modes/interactive/theme/theme.ts +50 -2
  63. package/src/modes/print-mode.ts +78 -31
  64. package/src/modes/rpc/rpc-mode.ts +186 -78
  65. package/src/modes/rpc/rpc-types.ts +10 -3
  66. package/src/prompts/system-prompt.md +36 -28
  67. package/src/utils/clipboard.ts +90 -50
  68. package/src/utils/image-convert.ts +1 -1
  69. package/src/utils/image-resize.ts +1 -1
  70. package/src/utils/tools-manager.ts +2 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,95 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [4.0.0] - 2026-01-10
6
+
7
+ ### Added
8
+
9
+ - Exported `InteractiveModeOptions` type for programmatic SDK usage
10
+ - Exported additional UI components for extensions: `ArminComponent`, `AssistantMessageComponent`, `BashExecutionComponent`, `BranchSummaryMessageComponent`, `CompactionSummaryMessageComponent`, `CustomEditor`, `CustomMessageComponent`, `FooterComponent`, `ExtensionEditorComponent`, `ExtensionInputComponent`, `ExtensionSelectorComponent`, `LoginDialogComponent`, `ModelSelectorComponent`, `OAuthSelectorComponent`, `SessionSelectorComponent`, `SettingsSelectorComponent`, `ShowImagesSelectorComponent`, `ThemeSelectorComponent`, `ThinkingSelectorComponent`, `ToolExecutionComponent`, `TreeSelectorComponent`, `UserMessageComponent`, `UserMessageSelectorComponent`
11
+ - Exported `renderDiff`, `truncateToVisualLines`, and related types for extension use
12
+ - `setFooter()` and `setHeader()` methods on `ExtensionUIContext` for custom footer/header components
13
+ - `setEditorComponent()` method on `ExtensionUIContext` for custom editor components
14
+ - `supportsUsageInStreaming` model config option to control `stream_options: { include_usage: true }` behavior
15
+ - Terminal setup documentation for Kitty keyboard protocol configuration (Ghostty, wezterm, Windows Terminal)
16
+ - Documentation for paid Cloud Code Assist subscriptions via `GOOGLE_CLOUD_PROJECT` env var
17
+ - Environment variables reference section in README
18
+ - `--no-tools` flag to disable all built-in tools, enabling extension-only setups
19
+ - `--no-extensions` flag to disable extension discovery while still allowing explicit `-e` paths
20
+ - `blockImages` setting to prevent images from being sent to LLM providers
21
+ - `thinkingBudgets` setting to customize token budgets per thinking level
22
+ - `PI_SKIP_VERSION_CHECK` environment variable to disable new version notifications at startup
23
+ - Anthropic OAuth support via `/login` to authenticate with Claude Pro/Max subscription
24
+ - OpenCode Zen provider support via `OPENCODE_API_KEY` env var and `opencode/<model-id>` syntax
25
+ - Session picker (`pi -r`) and `--session` flag support searching/resuming by session ID (UUID prefix)
26
+ - Session ID forwarding to LLM providers for session-based caching (used by OpenAI Codex for prompt caching)
27
+ - `dequeue` keybinding (`Alt+Up`) to restore queued steering/follow-up messages back into the editor
28
+ - Pluggable operations for built-in tools enabling remote execution via SSH or other transports (`ReadOperations`, `WriteOperations`, `EditOperations`, `BashOperations`, `LsOperations`, `GrepOperations`, `FindOperations`)
29
+ - `/model <search>` pre-filters the model selector or auto-selects on exact match; use `provider/model` syntax to disambiguate
30
+ - Managed binaries directory (`~/.omp/bin/`) for fd and rg tools
31
+ - `FooterDataProvider` for custom footers with `getGitBranch()`, `getExtensionStatuses()`, and `onBranchChange()`
32
+ - `ctx.ui.custom()` accepts `{ overlay: true }` option for floating modal components
33
+ - `ctx.ui.getAllThemes()`, `ctx.ui.getTheme(name)`, `ctx.ui.setTheme(name | Theme)` for theme management
34
+ - `setActiveTools()` for dynamic tool management
35
+ - `setModel()`, `getThinkingLevel()`, `setThinkingLevel()` methods for runtime model and thinking level changes
36
+ - `ctx.shutdown()` for requesting graceful shutdown
37
+ - `pi.sendUserMessage()` for sending user messages from extensions
38
+ - Extension UI dialogs (`select`, `confirm`, `input`) support `timeout` option with live countdown display
39
+ - Extension UI dialogs accept optional `AbortSignal` to programmatically dismiss dialogs
40
+ - Async extension factories for dynamic imports and lazy-loaded dependencies
41
+ - `user_bash` event for intercepting user `!`/`!!` commands
42
+ - Built-in renderers used automatically for tool overrides without custom `renderCall`/`renderResult`
43
+ - `InteractiveMode`, `runPrintMode()`, `runRpcMode()` exported for building custom run modes
44
+ - Copy link button on messages for deep linking to specific entries
45
+ - Codex injection info display showing system prompt modifications
46
+ - URL parameter support for `leafId` and `targetId` deep linking
47
+ - Wayland clipboard support for `/copy` command using wl-copy with xclip/xsel fallback
48
+
49
+ ### Changed
50
+
51
+ - Bash tool output truncation now recalculates on terminal resize instead of using cached width
52
+ - Web search tool headers updated to match Claude Code client format for better compatibility
53
+ - `discoverSkills()` return type documented as `{ skills: Skill[], warnings: SkillWarning[] }` in SDK docs
54
+ - Default model for OpenCode provider changed from `claude-sonnet-4-5` to `claude-opus-4-5`
55
+ - Terminal color mode detection defaults to truecolor for modern terminals instead of 256color
56
+ - System prompt restructured with XML tags and clearer instructions format
57
+ - `before_agent_start` event receives `systemPrompt` in the event object and returns `systemPrompt` (full replacement) instead of `systemPromptAppend`
58
+ - `discoverSkills()` returns `{ skills: Skill[], warnings: SkillWarning[] }` instead of `Skill[]`
59
+ - `ctx.ui.custom()` factory signature changed from `(tui, theme, done)` to `(tui, theme, keybindings, done)`
60
+ - `ExtensionRunner.initialize()` signature changed from options object to positional params `(actions, contextActions, commandContextActions?, uiContext?)`
61
+
62
+ ### Fixed
63
+
64
+ - Wayland clipboard copy (`wl-copy`) no longer blocks when the process doesn't exit promptly
65
+ - Empty `--tools` flag now correctly enables all built-in tools instead of disabling them
66
+ - Bash tool handles spawn errors gracefully instead of crashing the agent
67
+ - Components properly rebuild their content on theme change via `invalidate()` override
68
+ - `setTheme()` triggers a full rerender so previously rendered components update with new theme colors
69
+ - Session ID updates correctly when branching sessions
70
+ - External edits to `settings.json` while pi is running are preserved when pi saves settings
71
+ - Default thinking level from settings applies correctly when `enabledModels` is configured
72
+ - LM Studio compatibility for OpenAI Responses tool strict mapping
73
+ - Symlinked directories in `prompts/` folders are followed when loading prompt templates
74
+ - String `systemPrompt` in `createAgentSession()` works as a full replacement instead of having context files and skills appended
75
+ - Update notification for bun binary installs shows release download URL instead of npm command
76
+ - ESC key works during "Working..." state after auto-retry
77
+ - Abort messages show correct retry attempt count
78
+ - Antigravity provider returning 429 errors despite available quota
79
+ - Malformed thinking text in Gemini/Antigravity responses where thinking content appeared as regular text
80
+ - `--no-skills` flag correctly prevents skills from loading in interactive mode
81
+ - Overflow-based compaction skips if error came from a different model or was already handled
82
+ - OpenAI Codex context window reduced from 400k to 272k tokens to match Codex CLI defaults
83
+ - Context overflow detection recognizes `context_length_exceeded` errors
84
+ - Key presses no longer dropped when input is batched over SSH
85
+ - Clipboard image support works on Alpine Linux and other musl-based distros
86
+ - Queued steering/follow-up messages no longer wipe unsent editor input
87
+ - OAuth token refresh failure no longer crashes app at startup
88
+ - Status bar shows correct git branch when running in a git worktree
89
+ - Ctrl+V clipboard image paste works on Wayland sessions
90
+ - Extension directories in `settings.json` respect `package.json` manifests
91
+
92
+ ## [3.37.1] - 2026-01-10
93
+
5
94
  ## [3.37.0] - 2026-01-10
6
95
  ### Changed
7
96
 
package/README.md CHANGED
@@ -9,6 +9,7 @@ Works on Linux, macOS, and Windows (requires bash; see [Windows Setup](#windows-
9
9
  - [Getting Started](#getting-started)
10
10
  - [Installation](#installation)
11
11
  - [Windows Setup](#windows-setup)
12
+ - [Terminal Setup](#terminal-setup)
12
13
  - [API Keys & OAuth](#api-keys--oauth)
13
14
  - [Quick Start](#quick-start)
14
15
  - [Usage](#usage)
@@ -106,6 +107,30 @@ For most users, [Git for Windows](https://git-scm.com/download/win) is sufficien
106
107
  }
107
108
  ```
108
109
 
110
+ ### Terminal Setup
111
+
112
+ Pi uses the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/) for reliable modifier key detection. Most modern terminals support this protocol, but some require configuration.
113
+
114
+ **Kitty, iTerm2:** Work out of the box.
115
+
116
+ **Ghostty:** Add to your Ghostty config (`~/.config/ghostty/config`):
117
+
118
+ ```
119
+ keybind = alt+backspace=text:\x1b\x7f
120
+ keybind = shift+enter=text:\n
121
+ ```
122
+
123
+ **wezterm:** Create `~/.wezterm.lua`:
124
+
125
+ ```lua
126
+ local wezterm = require 'wezterm'
127
+ local config = wezterm.config_builder()
128
+ config.enable_kitty_keyboard = true
129
+ return config
130
+ ```
131
+
132
+ **Windows Terminal:** Does not support the Kitty keyboard protocol. Shift+Enter cannot be distinguished from Enter. Use Ctrl+Enter for multi-line input instead. All other keybindings work correctly.
133
+
109
134
  ### API Keys & OAuth
110
135
 
111
136
  **Option 1: Auth file** (recommended)
@@ -169,6 +194,7 @@ omp
169
194
  - Gemini CLI uses the production Cloud Code Assist endpoint (standard Gemini models)
170
195
  - Antigravity uses a sandbox endpoint with access to Gemini 3, Claude (sonnet/opus thinking), and GPT-OSS models
171
196
  - Both are free with any Google account, subject to rate limits
197
+ - Paid Cloud Code Assist subscriptions: set `GOOGLE_CLOUD_PROJECT` or `GOOGLE_CLOUD_PROJECT_ID` env var to your project ID
172
198
 
173
199
  Credentials stored in `~/.omp/agent/auth.json`. Use `/logout` to clear.
174
200
 
@@ -196,7 +222,7 @@ The agent reads, writes, and edits files, and executes commands via bash.
196
222
  | Command | Description |
197
223
  | ------------------------- | --------------------------------------------------------------------------- |
198
224
  | `/settings` | Open settings menu (thinking, theme, queue mode, toggles) |
199
- | `/model` | Switch models mid-session (fuzzy search, arrow keys, Enter to select) |
225
+ | `/model` | Switch models mid-session. Use `/model <search>` or `provider/model` to prefilter/disambiguate. |
200
226
  | `/export [file\|--copy]` | Export session to HTML file or copy to clipboard |
201
227
  | `/share` | Upload session as secret GitHub gist, get shareable URL (requires `gh` CLI) |
202
228
  | `/session` | Show session info: path, message counts, token usage, cost |
@@ -239,7 +265,7 @@ The agent reads, writes, and edits files, and executes commands via bash.
239
265
  | Key | Action |
240
266
  | ------------------------- | ---------------------------- |
241
267
  | Enter | Send message |
242
- | Shift+Enter / Alt+Enter | New line (Ctrl+Enter on WSL) |
268
+ | Shift+Enter | New line (Ctrl+Enter on Windows Terminal) |
243
269
  | Ctrl+W / Option+Backspace | Delete word backwards |
244
270
  | Ctrl+U | Delete to start of line |
245
271
  | Ctrl+K | Delete to end of line |
@@ -320,8 +346,11 @@ omp -r # Short form
320
346
  omp --no-session # Ephemeral mode (don't save)
321
347
 
322
348
  omp --session /path/to/file.jsonl # Use specific session file
349
+ omp --session a8ec1c2a # Resume by session ID (partial UUID)
323
350
  ```
324
351
 
352
+ **Resuming by session ID:** The `--session` flag accepts a session UUID (or prefix). Session IDs are visible in filenames under `~/.omp/agent/sessions/<project>/` (e.g., `2025-12-13T17-47-46-817Z_a8ec1c2a-5a5f-4699-88cb-03e7d3cb9292.jsonl`). The UUID is the part after the underscore. You can also search by session ID in the `omp -r` picker.
353
+
325
354
  ### Context Compaction
326
355
 
327
356
  Long sessions can exhaust context windows. Compaction summarizes older messages while keeping recent ones.
@@ -493,6 +522,7 @@ Add custom models (Ollama, vLLM, LM Studio, etc.) via `~/.omp/agent/models.json`
493
522
  | `supportsStore` | Whether provider supports `store` field |
494
523
  | `supportsDeveloperRole` | Use `developer` vs `system` role |
495
524
  | `supportsReasoningEffort` | Support for `reasoning_effort` parameter |
525
+ | `supportsUsageInStreaming` | Whether provider supports `stream_options: { include_usage: true }`. Default: `true` |
496
526
  | `maxTokensField` | Use `max_completion_tokens` or `max_tokens` |
497
527
 
498
528
  **Live reload:** The file reloads each time you open `/model`. Edit during session; no restart needed.
@@ -831,9 +861,11 @@ omp [options] [@files...] [messages...]
831
861
  | `--continue`, `-c` | Continue most recent session |
832
862
  | `--resume`, `-r` | Select session to resume |
833
863
  | `--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`) |
864
+ | `--no-tools` | Disable all built-in tools |
834
865
  | `--tools <tools>` | Comma-separated tool list (default: `read,bash,edit,write`) |
835
866
  | `--thinking <level>` | Thinking level: `off`, `minimal`, `low`, `medium`, `high` |
836
- | `--hook <path>` | Load a hook file (can be used multiple times) |
867
+ | `--extension <path>`, `-e` | Load an extension file (can be used multiple times) |
868
+ | `--no-extensions` | Disable extension discovery (explicit `-e` paths still work) |
837
869
  | `--no-skills` | Disable skills discovery and loading |
838
870
  | `--skills <patterns>` | Comma-separated glob patterns to filter skills (e.g., `git-*,docker`) |
839
871
  | `--export <file> [output]` | Export session to HTML |
@@ -892,6 +924,15 @@ omp --tools read,grep,find,ls -p "Review the architecture"
892
924
  omp --export session.jsonl output.html
893
925
  ```
894
926
 
927
+ ### Environment Variables
928
+
929
+ | Variable | Description |
930
+ |----------|-------------|
931
+ | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc. | API keys for providers (see [API Keys & OAuth](#api-keys--oauth)) |
932
+ | `PI_CODING_AGENT_DIR` | Override the agent config directory (default: `~/.omp/agent`) |
933
+ | `PI_SKIP_VERSION_CHECK` | Skip new version check at startup (useful for Nix or other package manager installs) |
934
+ | `VISUAL`, `EDITOR` | External editor for Ctrl+G (e.g., `vim`, `code --wait`) |
935
+
895
936
  ---
896
937
 
897
938
  ## Tools
@@ -260,7 +260,7 @@ pi starts
260
260
 
261
261
  user sends prompt ─────────────────────────────────────────┐
262
262
  │ │
263
- ├─► before_agent_start (can inject message, append to system prompt)
263
+ ├─► before_agent_start (can inject message, modify system prompt)
264
264
  ├─► agent_start │
265
265
  │ │
266
266
  │ ┌─── turn (repeats while LLM calls tools) ───┐ │
@@ -311,6 +311,8 @@ pi.on("session_start", async (_event, ctx) => {
311
311
  });
312
312
  ```
313
313
 
314
+ **Examples:** [claude-rules.ts](../examples/extensions/claude-rules.ts), [custom-header.ts](../examples/extensions/custom-header.ts), [file-trigger.ts](../examples/extensions/file-trigger.ts), [status-line.ts](../examples/extensions/status-line.ts), [todo.ts](../examples/extensions/todo.ts), [tools.ts](../examples/extensions/tools.ts)
315
+
314
316
  #### session_before_switch / session_switch
315
317
 
316
318
  Fired when starting a new session (`/new`) or switching sessions (`/resume`).
@@ -332,6 +334,8 @@ pi.on("session_switch", async (event, ctx) => {
332
334
  });
333
335
  ```
334
336
 
337
+ **Examples:** [confirm-destructive.ts](../examples/extensions/confirm-destructive.ts), [dirty-repo-guard.ts](../examples/extensions/dirty-repo-guard.ts), [status-line.ts](../examples/extensions/status-line.ts), [todo.ts](../examples/extensions/todo.ts)
338
+
335
339
  #### session_before_branch / session_branch
336
340
 
337
341
  Fired when branching via `/branch`.
@@ -349,6 +353,8 @@ pi.on("session_branch", async (event, ctx) => {
349
353
  });
350
354
  ```
351
355
 
356
+ **Examples:** [confirm-destructive.ts](../examples/extensions/confirm-destructive.ts), [dirty-repo-guard.ts](../examples/extensions/dirty-repo-guard.ts), [git-checkpoint.ts](../examples/extensions/git-checkpoint.ts), [todo.ts](../examples/extensions/todo.ts), [tools.ts](../examples/extensions/tools.ts)
357
+
352
358
  #### session_before_compact / session_compact
353
359
 
354
360
  Fired on compaction. See [compaction.md](compaction.md) for details.
@@ -376,6 +382,8 @@ pi.on("session_compact", async (event, ctx) => {
376
382
  });
377
383
  ```
378
384
 
385
+ **Examples:** [custom-compaction.ts](../examples/extensions/custom-compaction.ts)
386
+
379
387
  #### session_before_tree / session_tree
380
388
 
381
389
  Fired on `/tree` navigation.
@@ -393,6 +401,8 @@ pi.on("session_tree", async (event, ctx) => {
393
401
  });
394
402
  ```
395
403
 
404
+ **Examples:** [todo.ts](../examples/extensions/todo.ts), [tools.ts](../examples/extensions/tools.ts)
405
+
396
406
  #### session_shutdown
397
407
 
398
408
  Fired on exit (Ctrl+C, Ctrl+D, SIGTERM).
@@ -403,16 +413,19 @@ pi.on("session_shutdown", async (_event, ctx) => {
403
413
  });
404
414
  ```
405
415
 
416
+ **Examples:** [auto-commit-on-exit.ts](../examples/extensions/auto-commit-on-exit.ts)
417
+
406
418
  ### Agent Events
407
419
 
408
420
  #### before_agent_start
409
421
 
410
- Fired after user submits prompt, before agent loop. Can inject a message and/or append to the system prompt.
422
+ Fired after user submits prompt, before agent loop. Can inject a message and/or modify the system prompt.
411
423
 
412
424
  ```typescript
413
425
  pi.on("before_agent_start", async (event, ctx) => {
414
426
  // event.prompt - user's prompt text
415
427
  // event.images - attached images (if any)
428
+ // event.systemPrompt - current system prompt
416
429
 
417
430
  return {
418
431
  // Inject a persistent message (stored in session, sent to LLM)
@@ -421,12 +434,14 @@ pi.on("before_agent_start", async (event, ctx) => {
421
434
  content: "Additional context for the LLM",
422
435
  display: true,
423
436
  },
424
- // Append to system prompt for this turn only
425
- systemPromptAppend: "Extra instructions for this turn...",
437
+ // Replace the system prompt for this turn (chained across extensions)
438
+ systemPrompt: event.systemPrompt + "\n\nExtra instructions for this turn...",
426
439
  };
427
440
  });
428
441
  ```
429
442
 
443
+ **Examples:** [claude-rules.ts](../examples/extensions/claude-rules.ts), [pirate.ts](../examples/extensions/pirate.ts), [plan-mode.ts](../examples/extensions/plan-mode.ts), [preset.ts](../examples/extensions/preset.ts), [ssh.ts](../examples/extensions/ssh.ts)
444
+
430
445
  #### agent_start / agent_end
431
446
 
432
447
  Fired once per user prompt.
@@ -439,6 +454,8 @@ pi.on("agent_end", async (event, ctx) => {
439
454
  });
440
455
  ```
441
456
 
457
+ **Examples:** [chalk-logger.ts](../examples/extensions/chalk-logger.ts), [git-checkpoint.ts](../examples/extensions/git-checkpoint.ts), [plan-mode.ts](../examples/extensions/plan-mode.ts)
458
+
442
459
  #### turn_start / turn_end
443
460
 
444
461
  Fired for each turn (one LLM response + tool calls).
@@ -453,6 +470,8 @@ pi.on("turn_end", async (event, ctx) => {
453
470
  });
454
471
  ```
455
472
 
473
+ **Examples:** [git-checkpoint.ts](../examples/extensions/git-checkpoint.ts), [plan-mode.ts](../examples/extensions/plan-mode.ts), [status-line.ts](../examples/extensions/status-line.ts)
474
+
456
475
  #### context
457
476
 
458
477
  Fired before each LLM call. Modify messages non-destructively.
@@ -465,6 +484,8 @@ pi.on("context", async (event, ctx) => {
465
484
  });
466
485
  ```
467
486
 
487
+ **Examples:** [plan-mode.ts](../examples/extensions/plan-mode.ts)
488
+
468
489
  ### Tool Events
469
490
 
470
491
  #### tool_call
@@ -483,6 +504,8 @@ pi.on("tool_call", async (event, ctx) => {
483
504
  });
484
505
  ```
485
506
 
507
+ **Examples:** [chalk-logger.ts](../examples/extensions/chalk-logger.ts), [permission-gate.ts](../examples/extensions/permission-gate.ts), [plan-mode.ts](../examples/extensions/plan-mode.ts), [protected-paths.ts](../examples/extensions/protected-paths.ts)
508
+
486
509
  #### tool_result
487
510
 
488
511
  Fired after tool executes. **Can modify result.**
@@ -503,6 +526,8 @@ pi.on("tool_result", async (event, ctx) => {
503
526
  });
504
527
  ```
505
528
 
529
+ **Examples:** [git-checkpoint.ts](../examples/extensions/git-checkpoint.ts), [plan-mode.ts](../examples/extensions/plan-mode.ts)
530
+
506
531
  ## ExtensionContext
507
532
 
508
533
  Every handler receives `ctx: ExtensionContext`:
package/docs/sdk.md CHANGED
@@ -532,7 +532,7 @@ Hook API methods:
532
532
  import { createAgentSession, discoverSkills, type Skill } from "@oh-my-pi/pi-coding-agent";
533
533
 
534
534
  // Discover and filter
535
- const allSkills = discoverSkills();
535
+ const { skills: allSkills, warnings } = discoverSkills();
536
536
  const filtered = allSkills.filter((s) => s.name.includes("search"));
537
537
 
538
538
  // Custom skill
@@ -554,7 +554,7 @@ const { session } = await createAgentSession({
554
554
  });
555
555
 
556
556
  // Discovery with settings filter
557
- const skills = discoverSkills(process.cwd(), undefined, {
557
+ const { skills } = discoverSkills(process.cwd(), undefined, {
558
558
  ignoredSkills: ["browser-*"], // glob patterns to exclude
559
559
  includeSkills: ["search-*"], // glob patterns to include (empty = all)
560
560
  });
@@ -753,7 +753,7 @@ const model = modelRegistry.find("provider", "id"); // Find specific model
753
753
  const builtIn = getModel("anthropic", "claude-opus-4-5"); // Built-in only
754
754
 
755
755
  // Skills
756
- const skills = discoverSkills(cwd, agentDir, skillsSettings);
756
+ const { skills, warnings } = discoverSkills(cwd, agentDir, skillsSettings);
757
757
 
758
758
  // Hooks (async - loads TypeScript)
759
759
  const hooks = await discoverHooks(cwd, agentDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "3.37.0",
3
+ "version": "4.0.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "ompConfig": {
@@ -39,10 +39,10 @@
39
39
  "prepublishOnly": "bun run generate-template && bun run clean && bun run build"
40
40
  },
41
41
  "dependencies": {
42
- "@oh-my-pi/pi-ai": "3.37.0",
43
- "@oh-my-pi/pi-agent-core": "3.37.0",
44
- "@oh-my-pi/pi-git-tool": "3.37.0",
45
- "@oh-my-pi/pi-tui": "3.37.0",
42
+ "@oh-my-pi/pi-ai": "4.0.0",
43
+ "@oh-my-pi/pi-agent-core": "4.0.0",
44
+ "@oh-my-pi/pi-git-tool": "4.0.0",
45
+ "@oh-my-pi/pi-tui": "4.0.0",
46
46
  "@openai/agents": "^0.3.7",
47
47
  "@sinclair/typebox": "^0.34.46",
48
48
  "ajv": "^8.17.1",
package/src/cli/args.ts CHANGED
@@ -30,8 +30,10 @@ export interface Args {
30
30
  sessionDir?: string;
31
31
  models?: string[];
32
32
  tools?: string[];
33
+ noTools?: boolean;
33
34
  hooks?: string[];
34
35
  extensions?: string[];
36
+ noExtensions?: boolean;
35
37
  print?: boolean;
36
38
  export?: string;
37
39
  noSkills?: boolean;
@@ -96,6 +98,8 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
96
98
  result.sessionDir = args[++i];
97
99
  } else if (arg === "--models" && i + 1 < args.length) {
98
100
  result.models = args[++i].split(",").map((s) => s.trim());
101
+ } else if (arg === "--no-tools") {
102
+ result.noTools = true;
99
103
  } else if (arg === "--tools" && i + 1 < args.length) {
100
104
  const toolNames = args[++i].split(",").map((s) => s.trim());
101
105
  const validTools: string[] = [];
@@ -132,6 +136,8 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
132
136
  } else if ((arg === "--extension" || arg === "-e") && i + 1 < args.length) {
133
137
  result.extensions = result.extensions ?? [];
134
138
  result.extensions.push(args[++i]);
139
+ } else if (arg === "--no-extensions") {
140
+ result.noExtensions = true;
135
141
  } else if (arg === "--no-skills") {
136
142
  result.noSkills = true;
137
143
  } else if (arg === "--skills" && i + 1 < args.length) {
@@ -189,11 +195,13 @@ ${chalk.bold("Options:")}
189
195
  --no-session Don't save session (ephemeral)
190
196
  --models <patterns> Comma-separated model patterns for Ctrl+P cycling
191
197
  Supports globs (anthropic/*, *sonnet*) and fuzzy matching
198
+ --no-tools Disable all built-in tools
192
199
  --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)
193
200
  Available: read, bash, edit, write, grep, find, ls
194
201
  --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
195
202
  --hook <path> Load a hook/extension file (can be used multiple times)
196
203
  --extension, -e <path> Load an extension file (can be used multiple times)
204
+ --no-extensions Disable extension discovery (explicit -e paths still work)
197
205
  --no-skills Disable skills discovery and loading
198
206
  --skills <patterns> Comma-separated glob patterns to filter skills (e.g., git-*,docker)
199
207
  --export <file> Export session file to HTML and exit
package/src/config.ts CHANGED
@@ -45,21 +45,6 @@ export function getPackageDir(): string {
45
45
  return process.cwd();
46
46
  }
47
47
 
48
- /** Get path to README.md (optional, may not exist in binary) */
49
- export function getReadmePath(): string {
50
- return resolve(join(getPackageDir(), "README.md"));
51
- }
52
-
53
- /** Get path to docs directory (optional, may not exist in binary) */
54
- export function getDocsPath(): string {
55
- return resolve(join(getPackageDir(), "docs"));
56
- }
57
-
58
- /** Get path to examples directory (optional, may not exist in binary) */
59
- export function getExamplesPath(): string {
60
- return resolve(join(getPackageDir(), "examples"));
61
- }
62
-
63
48
  /** Get path to CHANGELOG.md (optional, may not exist in binary) */
64
49
  export function getChangelogPath(): string {
65
50
  return resolve(join(getPackageDir(), "CHANGELOG.md"));
@@ -99,6 +84,11 @@ export function getToolsDir(): string {
99
84
  return join(getAgentDir(), "tools");
100
85
  }
101
86
 
87
+ /** Get path to managed binaries directory (fd, rg) */
88
+ export function getBinDir(): string {
89
+ return join(getAgentDir(), "bin");
90
+ }
91
+
102
92
  /** Get path to slash commands directory */
103
93
  export function getCommandsDir(): string {
104
94
  return join(getAgentDir(), "commands");