Commit Graph

131 Commits

  • Replace sharp with wasm-vips for image processing
    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
  • fix(coding-agent): resolve api keys by provider
    What:
    - resolve API keys using provider argument
    - add regression test for model-switch key resolution
    - update coding-agent changelog
    - document provider lookup in SDK
    
    Why:
    - prevent model-switch 401s from provider mismatch
    
    Tests:
    - npm run check
    - npm run test -w @mariozechner/pi-coding-agent -- sdk-api-key.test.ts
  • feat(plan-mode): enhanced plan mode with explicit step tracking (#694)
    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 PR #689: Add changelog attribution, coding-agent changelog, fix test types, add provider to test suites
    - 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
  • Improve light theme color contrast for WCAG compliance (#682)
    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>
  • feat(coding-agent): add session naming via /name command and extension API
    - 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
  • Rename /branch command to /fork
    - RPC: branch -> fork, get_branch_messages -> get_fork_messages
    - SDK: branch() -> fork(), getBranchMessages() -> getForkMessages()
    - AgentSession: branch() -> fork(), getUserMessagesForBranching() -> getUserMessagesForForking()
    - Extension events: session_before_branch -> session_before_fork, session_branch -> session_fork
    - Settings: doubleEscapeAction 'branch' -> 'fork'
    
    fixes #641
  • feat: Add skill slash commands and fuzzy matching for all commands
    - 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)
  • fix(coding-agent): remove -- from registerFlag calls
    This was causing the agent sometimes to pick up on the incorrect syntax when
    asked to write extensions with flags
  • Fix --no-skills flag not preventing skills from loading
    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
  • fix(coding-agent): --no-skills flag not preventing skills from loading (#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>
  • feat(coding-agent): add tool override support via extensions
    - 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
  • feat(coding-agent): add --no-tools flag to disable built-in tools
    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
  • feat(coding-agent): add --no-extensions flag to disable extension discovery
    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
  • refactor(coding-agent): simplify extension runtime architecture
    - 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.
  • fix: use defaultThinkingLevel from settings when enabledModels lacks explicit suffix (#540)
    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.
  • feat(coding-agent): add ctx.ui.setEditorComponent() extension API
    - Add setEditorComponent() to ctx.ui for custom editor components
    - Add CustomEditor base class for extensions (handles app keybindings)
    - Add keybindings parameter to ctx.ui.custom() factory (breaking change)
    - Add modal-editor.ts example (vim-like modes)
    - Add rainbow-editor.ts example (animated text highlighting)
    - Update docs: extensions.md, tui.md Pattern 7
    - Clean up terminal on TUI render errors
  • fix: preserve externally-added settings when saving
    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.
  • feat(coding-agent): allow explicit -e flags with --no-extensions
    --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
  • Add --no-extensions flag to disable extension discovery
    Similar to --no-skills, this flag disables extension discovery and loading.
    Useful for debugging or when extensions are causing issues.
  • Add ExtensionAPI methods, preset example, and TUI documentation improvements
    - ExtensionAPI: setModel(), getThinkingLevel(), setThinkingLevel() methods
    - New preset.ts example with plan/implement presets for model/thinking/tools switching
    - Export all UI components from pi-coding-agent for extension use
    - docs/tui.md: Common Patterns section with copy-paste code for SelectList, BorderedLoader, SettingsList, setStatus, setWidget, setFooter
    - docs/tui.md: Key Rules section for extension UI development
    - docs/extensions.md: Exhaustive example links for all ExtensionAPI methods and events
    - System prompt now references docs/tui.md for TUI development
    
    Fixes #509, relates to #347
  • Extensions: add pi.sendUserMessage() for sending user messages
    Adds sendUserMessage() to the extension API, allowing extensions to send
    actual user messages (role: user) rather than custom messages. Unlike
    sendMessage(), this always triggers a turn and behaves as if the user
    typed the message.
    
    - Add SendUserMessageHandler type and sendUserMessage() to ExtensionAPI
    - Wire handler through loader, runner, and all modes
    - Implement via prompt() with expandPromptTemplates: false
    - Add send-user-message.ts example with /ask, /steer, /followup commands
    - Document in extensions.md
    
    fixes #483
  • Add ctx.ui.setFooter() for extensions to replace footer component
    Extensions can now replace the built-in footer with a custom component:
    - setFooter(factory) replaces with custom component
    - setFooter(undefined) restores built-in footer
    
    Includes example extension demonstrating context usage display.
    
    Closes #481
  • Merge branch 'fix/image-paste-in-wayland'
    # Conflicts:
    #	packages/coding-agent/CHANGELOG.md
  • Add blockImages setting to prevent images from being sent to LLM providers
    - Setting controls filtering at convertToLlm layer (defense-in-depth)
    - Images are always stored in session, filtered dynamically based on current setting
    - Toggle mid-session works: LLM sees/doesn't see images already in session
    - Fixed SettingsManager.save() to handle inMemory mode for all setters
    
    Closes #492
  • fix(coding-agent): improve bash tool error handling (#479)
    - Validate working directory exists before spawning to provide clear error message
    - Add spawn error handler to prevent uncaught exceptions when shell not found or cwd invalid
    - Add tests for both error scenarios
    
    Without these fixes, spawn errors (e.g., ENOENT from missing cwd or shell) would
    cause uncaught exceptions that crash the entire agent session instead of being
    returned as clean tool errors.
    
    Co-authored-by: robinwander <robinwander@users.noreply.github.com>
  • Merge hooks and custom-tools into unified extensions system (#454)
    Breaking changes:
    - Settings: 'hooks' and 'customTools' arrays replaced with 'extensions'
    - CLI: '--hook' and '--tool' flags replaced with '--extension' / '-e'
    - API: HookMessage renamed to CustomMessage, role 'hookMessage' to 'custom'
    - API: FileSlashCommand renamed to PromptTemplate
    - API: discoverSlashCommands() renamed to discoverPromptTemplates()
    - Directories: commands/ renamed to prompts/ for prompt templates
    
    Migration:
    - Session version bumped to 3 (auto-migrates v2 sessions)
    - Old 'hookMessage' role entries converted to 'custom'
    
    Structural changes:
    - src/core/hooks/ and src/core/custom-tools/ merged into src/core/extensions/
    - src/core/slash-commands.ts renamed to src/core/prompt-templates.ts
    - examples/hooks/ and examples/custom-tools/ merged into examples/extensions/
    - docs/hooks.md and docs/custom-tools.md merged into docs/extensions.md
    
    New test coverage:
    - test/extensions-runner.test.ts (10 tests)
    - test/extensions-discovery.test.ts (26 tests)
    - test/prompt-templates.test.ts
  • Implement extension discovery with package.json manifest support
    Discovery rules:
    1. extensions/*.ts or *.js - direct files
    2. extensions/*/index.ts or index.js - subdirectory with index
    3. extensions/*/package.json with pi field - load declared paths
    
    No recursion beyond one level. Complex packages use package.json manifest.
    
    Added PiManifest type for future theme/skill bundling support.
    
    17 tests covering all discovery scenarios.
    
    refs #454
  • refactor: address PR feedback - merge setWidget, use KeyId for shortcuts
    1. Merge setWidget and setWidgetComponent into single overloaded method
       - Accepts either string[] or component factory function
       - Uses single Map<string, Component> internally
       - String arrays wrapped in Container with Text components
    
    2. Use KeyId type for registerShortcut instead of plain string
       - Import Key from @mariozechner/pi-tui
       - Update plan-mode example to use Key.shift('p')
       - Type-safe shortcut registration
    
    3. Fix tool API docs
       - Both built-in and custom tools can be enabled/disabled
       - Removed incorrect 'custom tools always active' statement
    
    4. Use matchesKey instead of matchShortcut (already done in rebase)
  • feat(hooks): add setWidgetComponent for custom TUI components
    - New ctx.ui.setWidgetComponent(key, factory) method
    - Allows custom Component to render as widget without taking focus
    - Unlike custom(), widget components render inline above editor
    - Components are disposed when cleared or replaced
    - Falls back to no-op in RPC/print modes
  • refactor(hooks): address PR feedback
    - Rename getTools/setTools to getActiveTools/setActiveTools
    - Add getAllTools to enumerate all configured tools
    - Remove text_delta event (use turn_end/agent_end instead)
    - Add shortcut conflict detection:
      - Skip shortcuts that conflict with built-in shortcuts (with warning)
      - Log warnings when hooks register same shortcut (last wins)
    - Add note about prompt cache invalidation in setActiveTools
    - Update plan-mode hook to use agent_end for [DONE:id] parsing
  • feat(hooks): add setWidget API for multi-line status displays
    - ctx.ui.setWidget(key, lines) for multi-line displays above editor
    - Widgets appear below 'Working...' indicator, above editor
    - Supports ANSI styling including strikethrough
    - Added theme.strikethrough() method
    - Plan-mode hook now shows todo list with checkboxes
    - Completed items show checked box and strikethrough text
  • feat(coding-agent): add hook API for CLI flags, shortcuts, and tool control
    Hook API additions:
    - pi.getTools() / pi.setTools(toolNames) - dynamically enable/disable tools
    - pi.registerFlag(name, options) / pi.getFlag(name) - register custom CLI flags
    - pi.registerShortcut(shortcut, options) - register keyboard shortcuts
    
    Plan mode hook (examples/hooks/plan-mode.ts):
    - /plan command or Shift+P shortcut to toggle
    - --plan CLI flag to start in plan mode
    - Read-only tools: read, bash, grep, find, ls
    - Bash restricted to non-destructive commands (blocks rm, mv, git commit, etc.)
    - Interactive prompt after each response: execute, stay, or refine
    - Shows plan indicator in footer when active
    - State persists across sessions
  • WIP: Add hook API for dynamic tool control with plan-mode hook example
    - Add pi.getTools() and pi.setTools(toolNames) to HookAPI
    - Hooks can now enable/disable tools dynamically
    - Changes take effect on next agent turn
    
    New example hook: plan-mode.ts
    - Claude Code-style read-only exploration mode
    - /plan command toggles plan mode on/off
    - Plan mode tools: read, bash, grep, find, ls
    - Edit/write tools disabled in plan mode
    - Injects context telling agent about restrictions
    - After each response, prompts to execute/stay/refine
    - State persists across sessions
  • feat(coding-agent): add $ARGUMENTS syntax for slash commands (#418)
    * feat(coding-agent): add $ARGUMENTS syntax for slash commands
    
    * test(coding-agent): add tests for slash command argument substitution
  • fix(ai): ensure maxTokens > thinkingBudget for Claude thinking models
    Claude requires max_tokens > thinking.budget_tokens. When caller specifies
    a small maxTokens (e.g. compaction with ~13k tokens) and reasoning is enabled
    with high budget (16k tokens), the constraint was violated.
    
    Fix: In mapOptionsForApi, add thinkingBudget on top of caller's maxTokens
    (capped at model.maxTokens). If still not enough room, reduce thinkingBudget
    to leave space for output.
    
    Applied to both anthropic-messages and google-gemini-cli APIs.
    
    Also adds test utilities for OAuth credential resolution and tests for
    compaction with thinking models.
    
    fixes #413