- New /models command with toggle UI for each available model
- Changes persist to enabledModels in settings.json
- Updates take effect immediately for Ctrl+P cycling
The problem: I wanted to be able to select my session (either from
`/resume` or `--resume`) with different keybindings.
The issue: when running `pi --resume`, custom keybindings from
`~/.pi/agent/keybindings.json` were not being applied to the session
picker. This happened because `KeybindingsManager.create()` was only
called when `InteractiveMode` initialized, but the session picker runs
before that in `main.ts`.
The session picker uses `getEditorKeybindings()` for navigation
(selectUp/selectDown etc.), which returns the global default keybindings
if `setEditorKeybindings()` hasn't been called yet.
Fix: Call `KeybindingsManager.create()` inside the `--resume` block
before showing the session picker. This loads user keybindings and sets
them globally.
The current fix results in double-init of keybindings when entering
interactive mode which _should_ be harmless, since it's the same same
config loaded twice, but is minimal and only affects the `--resume`
path.
I considered passing keybindings from `main()` to `InteractiveMode` -
it's cleaner but requires API changes.
Also documented the `select*` keybindings in README.md.
- Skills registered as /skill:name commands for quick access
- Toggle via /settings or skills.enableSkillCommands in settings.json
- Fuzzy matching for all slash command autocomplete (type /skbra for /skill:brave-search)
- Moved fuzzy module from coding-agent to tui package for reuse
Closes#630 by @Dwsy (reimplemented with fixes)
Applied streaming TextDecoder fix to executeBashWithOperations(), matching
the fix in executeBash() from PR #433. Remote execution (SSH, containers)
was still using Buffer.toString() which corrupts multi-byte UTF-8 sequences
split across chunk boundaries.
fixes#608
- /model <search> pre-filters selector or auto-selects on exact match
- Support provider/model syntax for disambiguation (e.g., /model openai/gpt-4)
- Auto-select logic moved to InteractiveMode to avoid selector UI flicker
Closes#587
Expose data that extensions cannot otherwise access: git branch and
extension statuses from setStatus(). Token stats, model info, etc.
remain computable via ctx.sessionManager and ctx.model.
The --no-skills flag set options.skills = [] in main.ts, but the
interactive mode UI would rediscover skills anyway because it called
loadSkills() directly instead of using the already-loaded skills.
Changes:
- Add AgentSession.skills and AgentSession.skillWarnings properties
- discoverSkills() now returns { skills, warnings } instead of Skill[]
- Interactive mode uses session.skills instead of calling loadSkills()
- Update SDK docs and examples for new return type
Fixes#577
The --no-skills flag set options.skills = [] in main.ts, but the interactive mode UI would rediscover skills anyway because it called loadSkills() directly.
Changes:
- Add AgentSession.skills and AgentSession.skillWarnings properties
- discoverSkills() now returns { skills, warnings } instead of Skill[]
- Interactive mode uses session.skills instead of calling loadSkills()
Co-authored-by: Carlos Villela <cv@lixo.org>
Adds overlay rendering capability to the TUI, enabling floating modal
components that render on top of existing content without clearing the screen.
- Add showOverlay(), hideOverlay(), hasOverlay() methods to TUI
- Implement ANSI-aware line compositing via extractSegments()
- Support overlay stack (multiple overlays, later on top)
- Add { overlay: true } option to ctx.ui.custom()
- Add overlay-test.ts example extension
Also fixes pre-existing bug where bash tool output cached visual lines
at fixed terminal width, causing crashes on terminal resize.
Co-authored-by: Nico Bailon <nico.bailon@gmail.com>
- user_bash event for intercepting ! and !! commands (#528)
- Extensions can return { operations } or { result } to redirect/replace
- executeBashWithOperations() for custom BashOperations execution
- session.recordBashResult() for extensions handling bash themselves
- Theme API: getAllThemes(), getTheme(), setTheme() on ctx.ui
- mac-system-theme.ts example: sync with macOS dark/light mode
- Updated ssh.ts to use user_bash event
When passing a string systemPrompt to createAgentSession(), it is now
used as-is without appending context files and skills. This matches the
documented behavior: 'String replaces default, function receives default
and returns final.'
Previously, string systemPrompt would have context files and skills
appended, causing duplication if they were already in the string.
fixes#543
- Add systemPrompt to BeforeAgentStartEvent so extensions can see current prompt
- Change systemPromptAppend to systemPrompt in BeforeAgentStartEventResult for full replacement
- Extensions can now chain modifications (each sees the result of previous)
- Update ssh.ts to replace local cwd with remote cwd in system prompt
- Update pirate.ts, claude-rules.ts, preset.ts to use new API
fixes#575
When overriding a built-in tool (read, bash, edit, write, grep, find, ls)
without providing renderCall/renderResult, the built-in renderer is now
used automatically. This allows wrapping built-in tools for logging or
access control without reimplementing the UI (syntax highlighting, diffs, etc.).
- Add setActiveTools() to ExtensionAPI for dynamic tool management
- Extensions can now override, wrap, or disable built-in tools
- Add tool-override.ts example demonstrating the pattern
- Update documentation for tool override capabilities
When aborting a retry attempt, surface the retry-aware abort message
in the assistant output and tool results instead of a generic "Aborted".
- Set errorMessage for aborted streaming messages
- Render abort message without forcing a leading newline when no content
Three related fixes:
1. google-gemini-cli: Handle abort signal in stream reading loop
- Add abort event listener to cancel reader immediately when signal fires
- Fix AbortError detection in retry catch block (fetch throws AbortError,
not our custom message)
- Swallow reader.cancel() rejection to avoid unhandled promise
2. agent-session: Fix retry attempt counter showing 0 on cancel
- abortRetry() was resetting _retryAttempt before the catch block could
read it for the error message
3. interactive-mode: Restore main escape handler on agent_start
- When auto-retry starts, onEscape is replaced with retry-specific handler
- auto_retry_end (which restores it) fires on turn_end, after streaming begins
- Now restore immediately on agent_start if retry handler is still active
Amended: suppress reader.cancel() rejection on abort.
Add --no-tools flag that allows starting pi without any built-in tools,
enabling extension-only tool setups (e.g., pi-ssh-remote).
- Add --no-tools flag to CLI args parsing
- Handle --tools '' (empty string) as equivalent to no tools
- Fix system prompt to not show READ-ONLY mode when no tools (extensions may provide write capabilities)
- Add tests for new flag and system prompt behavior
fixes#555