Adds StdinBuffer class (adapted from OpenTUI, MIT license) to split
batched stdin into individual sequences before they reach components.
This fixes key presses being dropped when batched with release events,
which commonly occurs over SSH due to network buffering.
- Each handleInput() call now receives a single event
- matchesKey() and isKeyRelease() work correctly without batching awareness
- Properly buffers incomplete escape sequences across chunks
- Handles bracketed paste mode
Addresses #538
- Enable flag 2 in Kitty protocol for event type reporting
- Add isKeyRelease() and isKeyRepeat() functions
- Parse event type suffix (:1/:2/:3) in Kitty sequences
- Export KeyEventType type
- 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
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
feat(coding-agent): support searching/resuming sessions by ID
- Session picker (pi -r) now searches session IDs in addition to message content
- --session flag accepts UUID prefix (e.g., pi --session a8ec1c2a)
- Documented in README.md
fixes#495
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
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
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
- 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
- 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
- Add sessionId to StreamOptions for providers that support session-based caching
- OpenAI Codex provider uses sessionId for prompt_cache_key and routing headers
- Agent class now accepts and forwards sessionId to stream functions
- coding-agent passes session ID from SessionManager and updates on session changes
- Update ai package README with table of contents, OpenAI Codex OAuth docs, and env vars table
- Increase Codex instructions cache TTL from 15 minutes to 24 hours
- Add tests for sessionId forwarding in ai and agent packages
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>
- Remove per-thinking-level model variants (gpt-5.2-codex-high, etc.)
- Remove thinkingLevels from Model type
- Provider clamps reasoning effort internally
- Omit reasoning field when thinking is off
fixes#472
Only fall back to 256color for truly limited terminals (dumb, empty, linux).
Virtually all modern terminals support truecolor, no need to be conservative.
- 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
Extensions defined in settings.json were being ignored because SettingsManager was created after the extension loading step.
The fix moves SettingsManager.create() before discoverAndLoadExtensions() and merges settings extensions with CLI --extension args. CLI args take precedence (appended after settings).
Also clarifies SDK documentation about extension discovery behavior.
Co-authored-by: melihmucuk <melih@mucuk.co>
Previously the system prompt was converted to an input message in convertMessages,
then stripped out by filterPiSystemPrompts. Now the system prompt is passed directly
to transformRequestBody and appended after CODEX_PI_BRIDGE in the bridge message.
- Accept ExtensionFactory[] for inline extensions (merged with discovery)
- Mark preloadedExtensions as @internal (CLI implementation detail)
- Update sdk.md with inline extension example
- Update CHANGELOG