- Switched search/ast_grep/ast_edit/find inputs from scalar path fields to required `paths` arrays.
- Reworked path resolution to normalize and expand each `paths` entry via explicit helpers in `src/tools/path-utils.ts`.
- Updated search and find tool-call rendering to display explicit `paths` values in mode overlays and export views.
- Updated tool prompt docs and examples to document `paths` array inputs for search, grep, find, and AST tools.
- Raised the default search match limit from 20 to 500 and updated limit-reached messaging.
- Removed title-source aware branching from session terminal-title and accent helpers, and updated callers to use session name plus cwd only.
- Dropped UUID-based recent-session naming by preferring explicit header titles or first user prompts and generating an "Untitled · <time>" fallback.
- Adjusted welcome session-row rendering for width-aware name truncation and disabled reasoning in title generation requests to keep terminal titles concise.
- Added a unified eval framework with parser grammar, backend interfaces, and JS/Python execution result types.
- Added eval tool docs and updated prompts for fenced cells, `eval.py`/`eval.js`, and fallback behavior.
- Replaced the built-in `python` tool with `eval` across registry, rendering, interactive modes, and tool settings.
- Migrated Python execution runtime from `src/ipy` to `src/eval/py`, renamed state fields, and removed legacy introspection.
- Refactored browser tooling from in-process VM helpers to worker-managed tab supervisors and protocol transport.
- Added eval parser fallback and JS tool-bridge tests, updated imports, and removed obsolete python-mode suites.
- Documented and removed `utils/oauth` from the `ai` package entrypoint, noting it as a breaking change.
- Refactored `cli`, `auth-storage`, and `utils/oauth` to load provider modules via scoped dynamic `import()` calls.
- Removed top-level provider imports and barrel exports from `utils/oauth/index.ts`, streamlining oauth module loading.
- Consolidated OAuth symbol, type, and provider imports in coding-agent and tests to `@oh-my-pi/pi-ai/utils/oauth` modules.
- Defined `DEFAULT_LOCAL_TOKEN` locally in model-registry and removed its cross-package OAuth import usage.
- Added a new `loop.mode` enum setting and UI option entries for prompt, compact, and reset behaviors.
- Updated interactive mode's loop auto-submit flow to execute selected compact or reset actions before re-submitting the prompt.
- Registered a new `just.enabled` setting in the tools settings schema.
- Added loop-mode command handling in interactive mode, including enable/disable toggling, repeated auto-submission scheduling, and Escape-based cancellation.
- Propagated loop mode state to the status line via a renamed `mode` segment that now renders plan or loop status, and updated presets/theme assets for the new loop icon.
- Migrated persisted status-line segment usage from `plan_mode` to `mode` in configuration defaults and normalization so legacy settings continue to load.
- Renamed the built-in `grep` content-search tool to `search` across settings, schemas, and SDK exports.
- Switched execution wiring so `Task`, `Plan`, cursor, and shell mapping now invoke `search` instead of `grep`.
- Updated prompts, plan-mode docs, and example tool lists to replace `grep`/`ls` references with `search` guidance.
- Aligned `Grep*`/`grep` event, renderer, and hook types to `Search*`/`search` across runtime and tests.
- Documented and fixed `search` result rendering budget behavior and added internal-URL/path-list transcript notes.
Add explicit Basic auth credentials for SearXNG while preserving Bearer token fallback.
Keep optional SearXNG settings out of the TUI and allow empty RFC 7617 username/password fields.
- Added sanitizeText to edit renderer previews and diff rendering before line processing.
- Passed filePath into replaceTabs calls across edit previews, errors, and diff visualization paths.
- Grouped streaming edit strategies by file path and generated diff previews for each file, with a five-file preview cap.
- Updated patch and hashline preview generation to return per-file preview arrays instead of only the first file.
- Rendered multi-file streaming diffs with file headers in the edit tool UI and stored them when more than one preview is present.
- Removed `pi-natives` chunk language classifier modules and all core chunk subsystems (kind, state, render, edit, resolve).
- Removed chunk-mode CLI/read/edit entrypoints, including `read` command and chunk mode registration/prompt tooling.
- Removed chunk selectors from `read` and `grep` tools, switching behavior to raw/L-range handling.
- Fixed poll wait parsing to keep defaulting to `30s` when the provided value is empty.
- Session metadata now stores on-disk size bytes, populated from file stats when collecting sessions.
- The session selector metadata line now renders file size using formatBytes instead of message counts.
- Session test fixtures were updated with the new size property so they match the revised SessionInfo shape.
- Changed `todo_write` to an ordered `op`-array model with `replace`, `start`, `done`, `rm`, `drop`, `append`.
- Removed legacy multi-field todo payloads and updated tests/fixtures to use ordered `{op, task?, phase?, items?}[]` args.
- Reworked todo operation execution to apply entries sequentially and validate missing or unknown task/phase IDs.
- Updated todo rendering to use `todo.content` only and changed bash artifact labels from `full result` to `raw output`.
- Updated inline argument formatting in formatArgsInline to truncate key/value pairs by width and show ellipsis when values overflow.
- Fixed JSON-tree output to hide harness-internal INTENT_FIELD and __partialJson keys from top-level tool argument rendering.
- Fixed multiline scalar rendering and empty-structure display paths in renderJsonTreeLines after tree-prefix traversal changes.
- Added a regression test for tool argument coercion that preserves quoted edit arrays while stripping optional null fields.
- Updated footer branch-watcher initialization to clear cached branch state when resolving git head fails.
- Set the report_tool_issue tool definition to non-strict mode for looser argument handling.
- Added `CodeFrameMarker` and `formatCodeFrameLine()` to centralize code-frame gutter formatting.
- Extended diff rendering to preserve `|` and `│` separators, aligning gutter markers and line numbers.
- Reworked AST, grep, hashline, Vim, and diff renderers to use shared line formatting with computed `lineNumberWidth`.
- Updated atom editing flow and tests, including `resolveAtomEntryPaths` migration and new loc-based/edge-case coverage.
- Adjusted benchmark runner early-stop configuration by passing `buildEarlyStop` through prompt collection.
- 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.
- Expanded hashline and chunk bigram tables to 647 entries and moved chunk checksums to a 40-item namespace.
- Changed hashline anchors from `LINE#ID`/`:` to concatenated `LINEID`\t forms across parsing and tool outputs.
- Removed line-number padding and routed diff/read/grep/renderer output through raw numbers, tabs, and `toDisplayLine` formatting.
- Renamed atom ops to `pre`/`post`, removed `ins`, and updated schemas, prompts, and tests for new insertion behavior.
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
- Added helper utilities in the edit renderer to parse partial JSON fragments and extract the `path` field.
- Used the extracted path as a fallback when resolving the edit target file, enabling partial streamed edit calls to show the path.
- Built and stored the render context before call rendering, and added a test covering partial JSON edit path rendering.
- 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).
Slots a new "apply_patch" variant alongside the existing edit modes
(replace, patch, hashline, chunk, vim). The mode accepts a single input
string containing a Codex *** Begin Patch / *** End Patch envelope,
parses it with a new lenient parser (heredoc-tolerant), and fans each
file-op out to the existing executePatchSingle so LSP writethrough,
plan-mode guards, fs-cache invalidation and diagnostics are shared
with the patch mode.
Exposes both tool shapes from the spec: the JSON function-tool variant
(§1.2, {input: string}) and the OpenAI custom-tool / Lark-grammar
"freeform" variant (§1.1, raw patch string). The edit tool advertises
a Lark grammar via customFormat and a wire name via customWireName;
openai-responses emits it as a grammar-constrained custom tool when a
model opts in with applyPatchToolType: "freeform" in models.json.
custom_tool_call / custom_tool_call_output are plumbed end-to-end
through the shared responses code (emission, streaming, history
replay), and the agent-loop dispatcher matches tool calls by either
name or customWireName so returned calls route correctly.
Also threads preview/diff rendering for apply_patch through the TUI
(tool-execution + edit renderer) so streaming patches show per-file
diffs like the other edit modes.
Default edit mode is unchanged (hashline); opt in via edit.mode or
PI_EDIT_VARIANT=apply_patch.
- 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.
- PgUp/PgDn: when selection can't advance (at boundary or single
oversized entry), fall back to line-based scrolling so the middle
and bottom of tall entries are reachable
- Error messages: split on newlines and apply replaceTabs + truncateToWidth
per line to prevent raw tabs/newlines from corrupting TUI layout
- #scrollToSelectedEntry: when entry is taller than viewport, scroll to
show entry top instead of snapping to bottom, preventing long expanded
entries from being unreadable
- #renderTextLines collapsed path: apply replaceTabs + truncateToWidth
to each line, matching sanitization used by all other collapsed paths
Ctrl+S now opens the viewer immediately on the most recently active
sub-agent session — no intermediate picker list. If no sub-agents
exist, the overlay closes immediately.
- Removed picker mode entirely (setupPicker, refreshPickerItems,
buildPickerItems, Mode type, selectList field)
- Constructor finds most recent sub-agent (preferring active ones,
sorted by lastUpdate) and enters viewer directly
- Ctrl+S and Esc both close the overlay (no picker to go back to)
- Use [/] or Tab/Shift+Tab to cycle between agents inline
Previously ReadToolGroupComponent completely ignored the expanded
state and discarded result content, making read tool output invisible
in the TUI (only showed a one-line path summary with no file content).
Changes:
- Store expanded state in #expanded field (was discarded with _ prefix)
- Store result content text in ReadEntry.contentText (was thrown away)
- Show a small code preview (3 lines) by default in collapsed mode
- Show full file content when expanded via Ctrl+O
- Uses renderCodeCell with PREVIEW_LIMITS.OUTPUT_COLLAPSED for
consistent truncation with "... N more lines (Ctrl+O for more)" hint
This brings read tool output in line with bash and grep tools which
already show previews when collapsed.
Extract model from JSONL transcript (model_change entry or first assistant
message's model field) and display it in the viewer header:
ScanCodingAgent [active] explore (2/5) · anthropic/claude-sonnet-4-6
Also show model in the picker list from AgentProgress.modelOverride,
so users can see which model each sub-agent is using before entering.
While in viewer mode, press ] or Tab to jump to next sub-agent session,
[ or Shift+Tab for previous. Wraps around at boundaries.
- Header shows position indicator (2/5) when multiple sub-agents exist
- Footer hints updated to show [/]:prev/next agent
- Cycling resets scroll/selection and auto-skips to first non-user entry
- Clears transcript cache on switch for clean reload
When a model returns an error (connection error, rate limit, etc.),
the assistant message has content=[] and an errorMessage string.
Previously these were invisible because the content loop ran zero times.
Now renders them as '✗ Error: <message>' in the error color.
Use the TUI Markdown component and the active theme's markdown palette
for rendering content in the session observer viewer:
- Assistant text responses: markdown-rendered when expanded
- Thinking blocks: markdown-rendered when expanded (italic dim when collapsed)
- User/developer messages: markdown-rendered when expanded
- Tool results: unchanged (structured output, not markdown)
Uses getMarkdownTheme() which provides themed styling for headings,
code blocks, inline code, links, lists, bold, italic, blockquotes,
and syntax-highlighted fenced code blocks.
Two issues from testing:
- On viewer open, selectedEntryIndex=0 points at the user prompt message
which fills the entire viewport, hiding all actual work (thinking, tool
calls). Now auto-selects first non-user entry and scrolls to it.
- Collapsed user/developer messages showed the full first line which can
be very long. Now truncates to 60 chars with line count hint.
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.