- Added an `irc_message` session event carrying custom IRC messages and emitted it when IRC records are created.
- Registered an IRC message handler in EventController that skips duplicate messages by role, custom type, and timestamp.
- The handler now appends IRC messages to chat, resets read grouping, and triggers a UI render.
- Replaced `AgentTool` `nointent` and `deriveIntent` with a unified `intent` option that supports `omit`, `optional`, `require`, or a callback function.
- Updated agent tool schema injection and execution paths to inject `_i` as required/optional/omitted and to derive intent through the new `intent` callback.
- Aligned atom-edit tests with the updated default sed behavior (`g` now off by default and explicit `g: true` for global replacement).
- Added `nointent` and `deriveIntent` to `AgentTool`, and made intent-schema injection honor `PI_NO_INTENT` plus per-tool opt-outs.
- Updated tool execution and streaming UI handling to derive a fallback intent when `_i` is absent, without aborting on derivation failures.
- Marked several coding tools as `nointent` and added `deriveIntent` callbacks where needed, then relaxed prompt language to indicate intent is present on most tools.
- dropSession: close persist writer before deletion to prevent EPERM
on Windows where an open file handle blocks unlink
- #runNewSessionFlow: guard UI reset on newSession return value;
session_before_switch hook cancellation now prevents chat state
being cleared and success banner being shown
- Added `AgentRegistry` singleton with session registration/unregistration and IRC routing metadata for peer lookups.
- Added IRC messaging prompts and tooling with `irc.enabled` setting, `list/send` tool paths, and peer roster rendering.
- Changed `/btw` to session-side `runEphemeralTurn`, added background IRC exchange flushing, and fixed empty-input checks.
- Added unit tests for IRC tool and BtwController ephemeral behavior, including disabled, busy, not-found, and abort cases.
/drop works like /new but permanently deletes the current session file
and artifacts instead of flushing (saving) it. Useful when the session
should not be kept.
- add drop?: boolean to NewSessionOptions
- branch in AgentSession.newSession(): skip flush, delete via
FileSessionStorage.deleteSessionWithArtifacts when drop=true;
deletion failure is non-fatal (logged, new session still starts)
- wire handleDropCommand() through InteractiveModeContext interface,
InteractiveMode delegation, and CommandController implementation
- guard: shows error if session has not been saved yet (no file to drop)
- register /drop in builtin-registry adjacent to /new
- Added `note` support to todo-write with `op: "note"` and required `text` input.
- Added optional `notes: string[]` to todo models and preserved notes in cloning and session task mapping.
- Implemented `op: "note"` append flow and markdown `>` block serialization/parsing for todo import/export.
- Updated HUD todo rendering to append superscript `+N` note markers and show in-progress note bodies.
- Documented note operation, required text field, and note rendering rules in todo-write docs and changelog.
- Added /todo export and /todo import commands to write/read markdown todos, defaulting to TODO.md.
- Changed /todo append from JSON payloads to tokenized [<phase>] <task...> input with quoted tokens.
- Changed /todo start/done/drop/rm matching to fuzzy-resolve task or phase names in TodoCommandController.
- Removed /todo replace from todo-command builtins in CHANGELOG and command registry.
- Added a private #currentPhases helper that reads todo phases from the latest session entries.
- Updated /todo handlers to use #currentPhases so existing todo states are loaded from entries when available.
- Added a fallback to session.getTodoPhases when no entry-derived phases exist.
- Added `openai` and `openai-codex` as image providers and let `providers.image=auto` prefer GPT images.
- Updated settings, selector, and SDK wiring so OpenAI image providers pass through `setPreferredImageProvider`.
- Replaced Gemini-only image tooling with `image-gen` and added OpenAI/Codex hosted-image execution with SSE parsing.
- Added image-gen and handoff tests, including final-yield no-compaction regression and OpenAI payload/header assertions.
Two regressions from 33dfce738:
1. selector-controller.ts imported nonexistent clearPluginRootsAndCaches
(was clearClaudePluginRootsCache). The previous commit collapsed the
inline closure that invalidated fs caches for plugin JSON files into
a direct function reference that doesn't exist. Restored the original
closure with its fs cache invalidation logic.
2. scrollToSelectedEntry() snapped oversized entries back to their top
on every PgDn/PgUp, defeating the line-scroll fallback. The condition
'entryTop < scrollOffset' fires whenever the user pages down within
a tall entry. Fixed: only snap when the viewport has no overlap with
the entry (completely above or completely below it).
- Replace `ReturnType<typeof this.ctx.ui.showOverlay>` with concrete
`OverlayHandle` type from @oh-my-pi/pi-tui
- Remove `as any` casts and redundant `as SessionMessageEntry` in
#loadTranscript; discriminated union narrowing on `entry.type` and
`msg.role` is sufficient
- Add missing `replaceTabs()` on collapsed user/developer preview text,
matching every other collapsed render path
- Canonicalized file and CLI defaults from `read` to `open` across tool registration and prompts.
- Added `resolveToolAlias()` and applied alias-normalized tool selection so legacy `read` maps to `open`.
- Updated runtime, UI, and export layers to treat `open` as first-class while preserving `read` compatibility.
- Renamed read prompt docs to `open.md`/`open-chunk.md` and refreshed system guidance to recommend `open`.
- Updated tool-related tests and expectations from `read` to `open` (including test fixtures and aliases).
- Standardized missing-file read errors and now return `File not found: <path>` for absent edit targets.
- Centralized AI provider, usage, and OAuth helpers into shared modules to remove duplicated logic.
- Migrated OAuth/API-key login flows to shared factory helpers and removed inline prompt/token-exchange code.
- Reused shared tools and formatter utilities for discovery, stream tails, LSP batching, and source formatting.
- Consolidated repeated test helpers and fixtures into shared modules, replacing inline helper duplicates.
- Added a new read.toolResultPreview boolean setting defaulting to false to control inline read result rendering.
- Updated read tool group rendering to show inline previews only when enabled and to hide duplicate summary rows for previewed entries.
- Passed the setting through event and UI helper constructors and added tests for default-off behavior and the duplicate-preview summary case.
Three issues from first test:
1. Viewer was cramped at bottom of screen because it replaced the
editor container inline. Now uses TUI's showOverlay system with
anchor=bottom-center, width=100%, maxHeight=100% for full terminal.
2. Text was truncated at hardcoded 90 chars. Removed MAX_TOOL_RESULT_LINE_WIDTH
— let the TUI framework handle wrapping at actual terminal width.
3. Enter key didn't trigger expand/collapse. Added matchesKey(keyData, 'enter')
alongside raw '\r'/'\n' checks.
Also: overrides Container.render() in viewer mode to produce viewport-
sliced output directly, with proper height computation from terminal rows.
- Added vim tool-call IDs across EventController, UiHelpers, and ToolExecution for per-call preview mapping.
- Extended Vim type and command parsing with update/write, edit, global, yank, and put handling.
- Added Vim engine support for new commands and motions, including gJ, g*, g#, g_, |, and gu/gU/g~.
- Reworked Vim tool flow to cache per-file engine clones, reuse tool details, and stream inserts in chunks.
- Updated vim.md and changelog to document new vim keys, ex aliases, and fixed :global preview behavior.
- Added parser and renderer tests plus a tmp/vim_test.txt fixture for chunked, cursor, and partial-insert cases.
- Removed `SearchDb` APIs and `searchDb` fields, dropping db-backed state from native and agent sessions.
- Replaced crate export `fff` with `fd`, moving fuzzy-find bindings into `fd.rs`.
- Removed `SearchDb`/picker fast-path logic from `glob` and `grep`, simplifying scan flow and dropping db args.
- Removed `SearchDb`/`getSearchDb` wiring from extension, tool, and task context constructors across coding-agent.
- Added over-indentation validation warnings in chunk-edit normalization for suspicious `~` body line formatting.
- Removed `bytes`, `fff-grep`, `fff-search`, and `blake3` deps, adding `grep-searcher = "0.1"`.
- Added multi-file edit payload support by requiring per-entry `edits` arrays across patch, hashline, replace, and chunk modes.
- Changed edit schemas and validators to move `path` (and `sel`->`path`) and op data into each edit entry.
- Changed edit execution flow to parse `file:selector` paths, run single-entry executors per file, and return grouped per-file results.
- Updated chunk diff rendering and test expectations to emit consistent anchor gutters with spaced pipes and `^` head-line markers.
- Propagated session title source through terminal-title update calls so auto and user names are handled consistently across controllers.
- Suppressed auto-generated names in status-line segments and completion messages by falling back to cwd-based titles.
- Updated title formatter tests to verify auto-generated and user-specified session titles produce different terminal labels.
- Add /rename <title> slash command to set an explicit session name,
updating the session header, terminal tab title, and status line
- Add session_name status segment: displays the session name on the
right side of the status bar with a stable djb2-hash-derived accent
color unique to each name; shown in all presets when a name is set
- Add setSessionName source tracking ('user' vs 'auto'): auto-generated
titles are silently ignored once the user has explicitly set a name,
preventing the async title generation from overwriting a /rename
- Sanitize session names at storage time: strip C0/C1 control characters
(including ANSI ESC) via static #sanitizeName before storing, blocking
escape sequence injection into the TUI, terminal title, and session file
- Extend sanitizeStatusText to cover the full C0/C1 range as
defense-in-depth (superset of the previous \r\n\t-only strip)
- Use stored (sanitized) name for showStatus message and terminal title
in handleRenameCommand, not the raw user input
- Guard terminal title update in auto-title path via titleSource === 'auto'
so a user rename is never overwritten by a late-resolving LLM call
- Reset #titleSource in #newSessionSync so each new session starts fresh
- Thread source parameter through AgentSession.setSessionName wrapper;
extension API and RPC set_session_name treated as 'user' intent
Closes#658
- Added canonical model equivalence types, cache helpers, and registry APIs for provider variant lookup.
- Changed model resolution to apply canonical ID overrides/excludes with provider order before fallback matching.
- Added canonical and provider model views in list-models and selector UI with canonical sorting/persistence.
- Updated role/model persistence to store selectors while runtime now resolves concrete canonical-backed provider models.
- Document session name getter/setter methods in extensions.md
- Add stub methods to ExtensionProxy that throw if called before init
- Add delegating implementations to ExtensionProxyInit
- Wire up getSessionName and setSessionName in extension runtime
- Add method signatures to ExtensionContext interface and type
- Add getSessionName to session manager API
- Add getSessionName and setSessionName to all mode contexts:
- ACP agent
- Extension UI controller (also updates terminal title)
- Print mode
- RPC mode
- Fixed usage report generation to preserve partial data when parsing payloads are incomplete.
- Fixed planType resolution to fall back to raw `plan_type` when parsed planType is missing.
- Fixed usage metadata population to set accountId and keep the original raw payload when parsed raw output is absent.
- Fixed usage report rendering to label unlimited plans and display a clear `-- no limits` status line.
- Extracted large switch statement into 16 dedicated event handler methods for improved maintainability and type safety.
- Introduced AgentSessionEventHandlers type and handler dispatch map to enable compile-time verification of event coverage.
- Enhanced slash command handlers to return remaining text as prompt input instead of consuming input entirely.
- Updated slash command parser to recognize both whitespace and colon (`:`) as command argument separators.
- Modified executeBuiltinSlashCommand return type to support string (remaining text) or boolean (consumed/not matched).
- Updated input controller to handle remaining text from slash commands and use it as prompt input.
- Extracted image metadata detection and MIME type utilities to @oh-my-pi/pi-utils package for shared use across projects.
- Consolidated image-input.ts and mime.ts modules into image-loading.ts with simplified API removing redundant metadata parameters.
- Updated all import paths across coding-agent to use readImageMetadata from @oh-my-pi/pi-utils instead of local utilities.
- Added peek-file utility module to @oh-my-pi/pi-utils with buffer pooling for efficient file header reading.
- Added asynchronous LSP server discovery and warmup at startup via `discoverStartupLspServers()` function.
- Added LSP startup event channel (`lsp:startup`) for real-time server status notifications during warmup.
- Added `LspStartupServerInfo` type to track LSP server status (connecting, ready, error) throughout lifecycle.
- Changed LSP server warmup from blocking synchronous operation to non-blocking background task.
- Refactored interactive mode to subscribe to LSP startup events and display real-time server status updates.
- Extracted prompt rendering and formatting utilities from coding-agent to centralized pi-utils package with new API surface (prompt.render, prompt.format, prompt.registerHelper).
- Migrated parseFrontmatter utility from coding-agent to pi-utils package; updated 8 files to import from @oh-my-pi/pi-utils.
- Removed 170-line prompt-format.ts module and consolidated 192 lines of Handlebars helper registrations into pi-utils prompt module.
- Updated 60+ files across coding-agent and typescript-edit-benchmark to use new prompt.render() and prompt.format() API from pi-utils.
- Simplified prompt-templates.ts by delegating core functionality to pi-utils while retaining custom helper registrations (jtdToTypeScript, jsonStringify, etc.).
- Migrated native bindings from TypeScript wrappers to NAPI-RS generated modules with auto-generated type definitions and runtime enums.
- Replaced chunk tree API with stateful ChunkState class supporting render, edit, and resolve operations with improved error handling.
- Converted callback signatures to error-first pattern (error, result) for shell, PTY, glob, and grep operations.
- Introduced type-safe enums for MacOSAppearance, GrepOutputMode, KeyEventType, ImageFormat, and AstMatchStrictness replacing string literals.
- Refactored chunk tree implementation with dedicated modules for edit, indent, resolve, and state management with comprehensive validation.
- Moved clipboard utilities from native bindings to coding-agent package with improved OSC 52 and Termux compatibility.
- Fixed memory leak by cancelling idle compaction timer on event controller disposal.
- Fixed session resumption to preserve last non-empty session when starting fresh.
- Fixed stash detection to use git ref resolution instead of output parsing for reliability.
- Fixed secret obfuscation to deobfuscate restored session messages locally while keeping LLM messages obfuscated.
- Fixed stash pop operation to preserve staged changes with --index flag after task branch merges.
- Changed idle compaction settings from enum to numeric type for flexible configuration.
- Move lifecycle end event after finalizeSubprocessOutput() so
submit_result({status:'aborted'}) is correctly reflected in the
observer instead of showing completed/failed (P1)
- Reset observer registry on session resume and /new command so
stale subagent sessions from prior conversations are cleared (P2)
- Cache parsed JSONL transcript incrementally: track byte offset,
only read and parse new bytes on each refresh instead of reparsing
the entire file, avoiding render loop blocking on large sessions (P2)
Wire EventBus through task runtime so subagent lifecycle and progress
events propagate to the TUI. Add SessionObserverRegistry to track
active sessions, and a session observer overlay accessible via Ctrl+S
that shows a picker of running subagents and a read-only transcript
viewer that reads the subagent's session JSONL file to display
thinking, text, tool calls, and results.
- Add TASK_SUBAGENT_LIFECYCLE_CHANNEL for start/end events
- Add SubagentProgressPayload.sessionFile for session file tracking
- Pass eventBus through sdk.ts -> main.ts -> InteractiveMode
- SessionObserverRegistry with multi-listener onChange pattern
- Overlay picker preserves selection position across live refreshes
- Viewer renders full transcript from session JSONL (thinking, text,
tool calls with smart arg summaries, inline tool results)
- Added external editor callback support to extension UI dialogs and hook selector for opening plans in external editor.
- Added `matchesAppExternalEditor()` keybinding matcher to detect external editor shortcuts (ctrl+g) across components.
- Added `trimTrailingNewline` option to `openInEditor()` function to preserve trailing newlines when editing externally.
- Modified plan review flow to re-read plan content from disk before approval to reflect external editor changes.
- Refactored plan preview rendering to cache and reuse UI container instead of recreating children on each render.
- Refactored Promise creation in external editor utility to use `Promise.withResolvers()` for cleaner async handling.
- Added `/tools` slash command to display agent-visible tools in interactive sessions.
- Added `handleToolsCommand()` method to InteractiveMode to delegate tools display to command controller.
- Added `buildToolsMarkdown()` utility function to generate formatted markdown table of available tools.
- Refactored `showMarkdownPanel()` helper to reduce duplication in markdown display logic across commands.
When a plugin is installed in both user and project scope, the selector
now shows separate scoped entries (e.g. 'plugin-name@1.0 [project]' and
'plugin-name@1.0 [user]') and forwards the selected scope to
uninstallPlugin(), preventing the disambiguation error introduced when
dual-scope support was added.