Commit graph

376 commits

Author SHA1 Message Date
Mario Zechner
5d39074a35 refactor(coding-agent): simplify InteractiveMode API
- Replace 11-param runInteractiveMode with InteractiveModeOptions
- Add InteractiveMode.run() that handles init, warnings, prompts, and loop
- Move version check, changelog loading, fdPath discovery inside InteractiveMode
- Detect resumed sessions via session.state.messages.length
- Export InteractiveModeOptions from modes/index.ts
2026-01-08 01:38:12 +01:00
Mario Zechner
cb3ac0ba9e 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.
2026-01-07 23:50:18 +01:00
Mario Zechner
09471ebc7d 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
2026-01-07 16:11:49 +01:00
Nico Bailon
77477f6166 feat(coding-agent): add timeout option to extension dialogs with live countdown
Extension UI dialogs (select, confirm, input) now support a timeout option
that auto-dismisses with a live countdown display. Simpler alternative to
manually managing AbortSignal for timed dialogs.

Also adds ExtensionUIDialogOptions type export and updates RPC mode to
forward timeout to clients.
2026-01-06 21:49:27 -08:00
Mario Zechner
2015964c40
Merge pull request #512 from nicobailon/feat/abort-signal-ui-dialogs
Add AbortSignal support to extension UI dialogs
2026-01-07 00:10:20 +01:00
Nico Bailon
9771fa1e44 Add AbortSignal support to extension UI dialogs
Closes #474
2026-01-06 15:01:15 -08:00
Mario Zechner
03e3f0d801
Merge pull request #510 from mitsuhiko/annotate-bridge-prompt
Annotate bridge prompt
2026-01-06 23:47:02 +01:00
Mario Zechner
59d8b7948c 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
2026-01-06 23:24:23 +01:00
Mario Zechner
c35a18b2b3 Export all UI components for extensions 2026-01-06 23:09:58 +01:00
Mario Zechner
999f97cd49 fix(coding-agent): update help text for ctrl+k and add !! shortcut 2026-01-06 21:27:35 +01:00
Tudor Oancea
f755f69e0a added custom header support and example extension 2026-01-06 21:20:19 +01:00
Mario Zechner
d2f3b42deb fix: OAuth token refresh failure returns undefined instead of throwing
When OAuth refresh fails during model discovery, getApiKey() now returns
undefined instead of throwing. This allows the app to start and fall back
to other providers, so the user can /login to re-authenticate.

fixes #498
2026-01-06 20:57:42 +01:00
Thomas Mustier
3964984f59 fix(coding-agent): keep editor text on queued steering 2026-01-06 17:02:35 +00:00
Armin Ronacher
6a5f04ce1f Add the codex bridge prompt in the html export 2026-01-06 14:21:34 +01:00
Mario Zechner
7210086677 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
2026-01-06 13:40:24 +01:00
Mario Zechner
f023af0dab 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
2026-01-06 12:39:45 +01:00
Mario Zechner
90e0b95c81 Merge branch 'fix/image-paste-in-wayland'
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
2026-01-06 12:12:17 +01:00
Zhou Rui
538ae6a083 fix(coding-agent): paste clipboard images on Wayland via wl-paste/xclip 2026-01-06 12:11:43 +01:00
Mario Zechner
a1d0b1c151 Merge PR #492: Add blockImages setting
- Setting controls filtering at convertToLlm layer
- 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
2026-01-06 12:00:15 +01:00
Mario Zechner
1fc2a912d4 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
2026-01-06 11:59:09 +01:00
Kevin
6cb3135695 Fix status bar git branch detection in worktrees and submodules 2026-01-06 11:13:22 +01:00
Josh
b582a6b70d
feat(coding-agent): add blockImages setting to prevent image uploads 2026-01-06 00:34:23 -06:00
Mario Zechner
e182b123a9 feat(coding-agent): queue compaction submissions, closes #475
Messages submitted during compaction are queued and delivered after
compaction completes, preserving steer vs follow-up behavior. Extension
commands execute immediately during compaction.

Co-authored-by: Thomas Mustier <tmustier@users.noreply.github.com>
2026-01-05 23:47:40 +01:00
badlogic
1349f02cdd docs: document Windows Terminal Shift+Enter limitation
Windows Terminal does not support the Kitty keyboard protocol, so
Shift+Enter cannot be distinguished from Enter. Document that users
should use Ctrl+Enter for multi-line input instead.

- Add Windows Terminal note in Terminal Setup section
- Update Keyboard Shortcuts table with Windows note
- Show Windows-specific hint in /hotkeys command
2026-01-05 23:17:58 +01:00
Mario Zechner
b4fb6770e4 Assume truecolor for most terminals (fixes SSH color detection)
Only fall back to 256color for truly limited terminals (dumb, empty, linux).
Virtually all modern terminals support truecolor, no need to be conservative.
2026-01-05 20:11:10 +01:00
Mario Zechner
9c87eeb805 Fix Anthropic login not showing URL (showPrompt should not clear content) 2026-01-05 20:03:07 +01:00
Mario Zechner
9b12719ab1 Improve OAuth login UI with consistent dialog component
- Add LoginDialogComponent with proper borders (top/bottom DynamicBorder)
- Refactor all OAuth providers to use racing approach (browser callback vs manual paste)
- Add onEscape handler to Input component for cancellation
- Add abortable sleep for GitHub Copilot polling (instant cancel on Escape)
- Show OS-specific click hint (Cmd+click on macOS, Ctrl+click elsewhere)
- Clear content between login phases (fixes GitHub Copilot two-phase flow)
- Use InteractiveMode's showStatus/showError for result messages
- Reorder providers: Anthropic, ChatGPT, GitHub Copilot, Gemini CLI, Antigravity
2026-01-05 19:58:44 +01:00
Christian Catalan
05b9d55656
feat(oauth): show paste input immediately during OpenAI Codex login (#468)
Previously, users had to wait up to 60 seconds for the browser callback
to timeout before being prompted to paste the authorization code. This
was problematic for SSH/VPS sessions where the callback cannot work.

Now the paste input is shown immediately alongside the browser flow:
- Browser callback and manual paste race - whichever completes first wins
- Desktop users: browser callback succeeds, input is cleaned up
- SSH/VPS users: paste code immediately without waiting

Changes:
- Add cancelWait() to OAuth server for early termination of polling loop
- Add onManualCodeInput callback that races with browser callback
- Show paste input immediately in TUI for openai-codex provider
- Clean up input on success, error, or when browser callback wins

Co-authored-by: cc-vps <crcatala+vps@gmail.com>
2026-01-05 18:47:58 +01:00
Mario Zechner
c6fc084534 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
2026-01-05 01:43:35 +01:00
Aliou Diallo
5cb7af1ddc
feat(hooks): expose setTitle to HookUIContext (#446) 2026-01-04 20:55:52 +01:00
Mario Zechner
00fa8b71c8 revert: remove unnecessary themeOverride params from theme functions
The optional theme parameter was added as a workaround for tsx dev mode,
but that's a dev-only issue. Users running the built package don't need it.
2026-01-04 20:27:46 +01:00
Mario Zechner
c447e62662 fix(theme): add optional themeOverride param to getSettingsListTheme/getSelectListTheme
When hooks are loaded via jiti, they get a separate module instance from
the main app. This means the global 'theme' variable in the hook's module
is never initialized. Adding an optional theme parameter allows hooks to
pass the theme from ctx.ui.custom() callback.

Usage in hooks:
  getSettingsListTheme(theme)  // theme from ctx.ui.custom callback
2026-01-04 18:39:00 +01:00
Mario Zechner
6390ff87ef fix(hooks): add stack traces to hook errors, fix tools.ts theme bug
- HookError now includes optional stack field
- Hook error display shows stack trace in dim color below error message
- tools.ts: create SettingsListTheme using the theme passed to ctx.ui.custom()
  instead of using getSettingsListTheme() which depends on global theme
2026-01-04 18:33:28 +01:00
Helmut Januschka
8ecb1d6c0b 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)
2026-01-04 18:13:30 +01:00
Helmut Januschka
277d7bd83b fix: remove inline imports and debug logging
- Convert all inline import() types to top-level imports
- Remove debug console.error statements from plan-mode hook
2026-01-04 18:13:29 +01:00
Helmut Januschka
ce88ebcd68 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
2026-01-04 18:13:29 +01:00
Helmut Januschka
9b53b89bd5 fix(widgets): add max line limit and document multi-hook behavior
- Limit total widget lines to 10 to prevent viewport overflow/flicker
- Show '... (widget truncated)' when limit exceeded
- Document that multiple hooks stack widgets vertically
- Add caution about keeping widgets small
2026-01-04 18:13:29 +01:00
Helmut Januschka
4ecf3f9422 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
2026-01-04 18:13:29 +01:00
Helmut Januschka
dc44816051 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
2026-01-04 18:13:28 +01:00
Helmut Januschka
056f40b00b feat(coding-agent): show hook shortcuts in /hotkeys command 2026-01-04 18:13:28 +01:00
Helmut Januschka
c956a726ed 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
2026-01-04 18:13:28 +01:00
Helmut Januschka
059292ead1 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
2026-01-04 18:13:28 +01:00
Armin Ronacher
5b95ccf830
Add consistent, configurable image placeholders (#442)
* Add consistent, configurable image placeholders

* Kill the placeholders
2026-01-04 18:12:55 +01:00
Aliou Diallo
0d477d39f9
fix(tui): expand paste markers when opening external editor (#444)
* fix(tui): expand paste markers when opening external editor

Add getExpandedText() method to Editor that substitutes paste markers
with actual content. Use it in Ctrl-G external editor flow so users
see full pasted content instead of [paste #N ...] placeholders.

* docs: add changelog entries for #444
2026-01-04 18:11:42 +01:00
Mario Zechner
5c5084481b feat(coding-agent): clipboard image paste support via Ctrl+V (fixes #419) 2026-01-04 01:05:22 +01:00
Mario Zechner
f2b89d5ec5 Merge branch 'feat/ctrl-n-external-editor' - configurable keybindings (#405) 2026-01-03 22:51:12 +01:00
Ben Vargas
8f5466f42a
feat(coding-agent): add /quit and /exit slash commands to exit (#426)
Add new slash commands for gracefully exiting the interactive mode:
- /quit - exit the application
- /exit - alias for /quit (common CLI convention)

Both commands await shutdown() which emits session_shutdown events
to hooks and custom tools before exiting. Unlike Ctrl+C (twice) which
uses void (fire-and-forget), these commands properly wait for hooks
and tools to complete their shutdown handlers.
2026-01-03 22:38:55 +01:00
Mario Zechner
79c56475e0 Fix non-PNG images not displaying in Kitty protocol terminals
JPEG/GIF/WebP images were not rendering in terminals using the Kitty
graphics protocol (Kitty, Ghostty, WezTerm) because it requires PNG
format (f=100). Non-PNG images are now converted to PNG using sharp
before being sent to the terminal.
2026-01-03 16:58:57 +01:00
Mario Zechner
e9cf3c1835 Fix slash commands and hook commands during streaming
- Hook commands now execute immediately during streaming (they manage their own LLM interaction via pi.sendMessage())
- File-based slash commands are expanded and queued via steer/followUp during streaming
- prompt() accepts new streamingBehavior option ('steer' or 'followUp') for explicit queueing during streaming
- steer() and followUp() now expand file-based slash commands and error on hook commands
- RPC prompt command accepts optional streamingBehavior field
- Updated docs: rpc.md, sdk.md, CHANGELOG.md

fixes #420
2026-01-03 15:36:54 +01:00
Helmut Januschka
f79256ac3b fix: update /hotkeys and startup hints to use configured keybindings
Both the startup instructions and /hotkeys command now display the
actual configured keybindings from keybindings.json instead of
hardcoded defaults.
2026-01-03 15:01:26 +01:00