- Manifest extensions/skills/prompts/themes arrays now support glob patterns
- Use !pattern for exclusions (e.g., '!**/deprecated/*')
- Enables packages to bundle dependencies and selectively include resources
- Support glob patterns and ! exclusions in package filter arrays
- Support glob patterns and ! exclusions in top-level settings arrays
- Add helper functions: isPattern, hasPatterns, collectFiles, collectSkillEntries, applyPatterns
- Add resolveLocalEntries for pattern-aware resolution of top-level arrays
- Add applyPackageFilter and collectAllPackageFiles for package filter patterns
- Add comprehensive tests for both top-level and package filter patterns
- Add PackageSource type for npm/git sources with optional filtering
- Migrate npm:/git: sources from extensions to packages array
- Add getPackages(), setPackages(), setProjectPackages() methods
- Update package-manager to resolve from packages array
- Support selective loading: extensions, skills, prompts, themes per package
- Update pi list to show packages
- Add migration tests for settings
closes#645
- Add progress callbacks to PackageManager for TUI status during install/remove/update
- Add extension conflict detection (tools, commands, flags with same names)
- Accept raw GitHub/GitLab URLs without git: prefix
- Add tests for package-manager.ts and resource-loader.ts
- Add empty fixture directories for skills tests
- Add ResourceLoader interface and DefaultResourceLoader implementation
- Add PackageManager for npm/git extension sources with install/remove/update
- Add session.reload() and session.bindExtensions() APIs
- Add /reload command in interactive mode
- Add CLI flags: --skill, --theme, --prompt-template, --no-themes, --no-prompt-templates
- Add pi install/remove/update commands for extension management
- Refactor settings.json to use arrays for skills, prompts, themes
- Remove legacy SkillsSettings source flags and filters
- Update SDK examples and documentation for ResourceLoader pattern
- Add theme registration and loadThemeFromPath for dynamic themes
- Add getShellEnv to include bin dir in PATH for bash commands
* Support shell command execution for API key resolution in models.json
Add ! prefix support to apiKey field in models.json to execute shell commands
and use stdout as the API key. This allows users to store API keys in secure
credential managers like macOS Keychain, 1Password, Bitwarden, or HashiCorp Vault.
Example: "apiKey": "!security find-generic-password -ws 'anthropic'"
The apiKey field now supports three formats:
- !command - executes shell command, uses trimmed stdout
- ENV_VAR_NAME - uses environment variable value
- literal - uses value directly
fixes#697
* feat(coding-agent): cache API key command results for process lifetime
Shell commands (! prefix) are now executed once and cached. Environment
variables and literal values are not cached, so changes are picked up.
Addresses review feedback on #762.
---------
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
When 429/500 errors occur during tool execution, empty assistant messages
with stopReason='error' get persisted. These break the tool_use -> tool_result
chain for Claude/Gemini APIs.
Added centralized filtering in transformMessages to skip assistant messages
with empty content and no tool calls. Provider-level filters remain for
defense-in-depth.
Implements support for ${@:N} and ${@:N:L} syntax to slice argument arrays
in prompt templates, following bash conventions.
Syntax:
- ${@:N} - All arguments from Nth position onwards (1-indexed)
- ${@:N:L} - L arguments starting from Nth position
Features:
- Bash-style slicing familiar to shell users
- 1-indexed for consistency with $1, $2, etc.
- Processes before simple $@ to avoid conflicts
- No recursive substitution of patterns in arguments
- Comprehensive edge case handling
Examples:
- ${@:2} with ["a", "b", "c"] -> "b c"
- ${@:2:1} with ["a", "b", "c"] -> "b"
- ${@:99} with ["a", "b"] -> "" (empty, out of range)
Test coverage: 24 new tests, all passing (73 total)
Closes#769
* feat(coding-agent): add input event for extension input interception
Extensions can now intercept, transform, or handle user input before the
agent processes it. Three result types: continue (pass through), transform
(modify text/images), handled (respond without LLM). Handlers chain
transforms and short-circuit on handled. Source field identifies origin.
* fix: make source public, use if/else over ternary
* fix: remove response field, extension handles own UI
Fixes#696
- Replaced sharp dependency with wasm-vips (WebAssembly build of libvips)
- Eliminates native build requirements that caused installation failures
- Added vips.ts singleton wrapper for async initialization
- Updated image-resize.ts and image-convert.ts to use wasm-vips API
- Added unit tests for image processing functionality
Changes from the original:
- Explicit [DONE:n] tag tracking (more accurate than auto-marking on tool_result)
- Plan: header requirement - only extracts todos from 'Plan:' sections
- Utils extracted to separate file for testability
- Better session resume - only scans messages after plan-mode-execute marker
- Context filtering - properly filters plan-mode-context custom type messages
- Refactored to directory structure (index.ts + utils.ts + README.md)
The original auto-completed steps on every tool_result, which was inaccurate
for multi-tool steps. This version uses explicit [DONE:n] markers that the
agent outputs after completing each step.
- Fix ai/CHANGELOG.md: add PR link and author attribution
- Add coding-agent/CHANGELOG.md entry for vercel-ai-gateway provider
- Fix model-resolver.test.ts: use anthropic-messages API type to match generated models
- Add vercel-ai-gateway to test suites: tokens, abort, empty, context-overflow, unicode-surrogate, tool-call-without-result, image-tool-result, total-tokens, image-limits
Adjust base colors (teal, blue, green, red, yellow, dimGray) to meet
4.5:1 contrast ratio against white backgrounds. Update thinking level
colors to reference theme vars for consistency.
Refactor test-theme-colors.ts into a CLI with contrast, test, and theme
commands for easier color validation.
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
- Add SessionInfoEntry type for session metadata
- Add /name <name> command to set session display name
- Add pi.setSessionName() and pi.getSessionName() extension API
- Session selector shows name (in warning color) instead of first message when set
- Session name included in fuzzy search
- /session command displays name when set
closes#650
- 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)
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>
- 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
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
Adds --no-extensions CLI flag that skips automatic extension discovery
while still allowing explicit -e paths. Three modes now available:
1. Default: auto-discover + any -e additions
2. --no-extensions: no extensions at all
3. --no-extensions -e foo.js: only load explicit extensions
Useful for debugging or running subagent instances without auto-discovered
extensions.
closes#524
- Replace per-extension closures with shared ExtensionRuntime
- Split context actions: ExtensionContextActions (required) + ExtensionCommandContextActions (optional)
- Rename LoadedExtension to Extension, remove setter methods
- Change runner.initialize() from options object to positional params
- Derive hasUI from uiContext presence (no separate param)
- Add warning when extensions override built-in tools
- RPC and print modes now provide full command context actions
BREAKING CHANGE: Extension system types and initialization API changed.
See CHANGELOG.md for migration details.
When enabledModels is configured without thinking level suffixes (e.g.,
'claude-opus-4-5' instead of 'claude-opus-4-5:high'), the scoped model's
default 'off' thinking level was overriding defaultThinkingLevel from
settings.
Now thinkingLevel in ScopedModel is optional (undefined means 'not
explicitly specified'). When passing to SDK, undefined values are filled
with defaultThinkingLevel from settings.
When a user edits settings.json while pi is running (e.g., adding
enabledModels), those settings would be lost when pi saved other
changes (e.g., changing thinking level via Shift+Tab).
The fix re-reads the file before saving and merges the current file
contents with in-memory changes, so external edits are preserved.
Adds test coverage for SettingsManager.
--no-extensions now skips discovery but still loads extensions
specified via -e flags. This gives users three modes:
1. Default: auto-discover + any -e additions
2. --no-extensions: no extensions at all
3. --no-extensions -e foo.js: only load foo.js, skip discovery
fixes#524