Commit Graph

2071 Commits

Author SHA1 Message Date
can1357 9498032d68 feat(coding-agent): enabled archive entry writes with automatic creation support
- Added support for writing to archive entries using `archive.ext:path/inside/archive` syntax for .tar, .tar.gz, .tgz, and .zip formats.
- Added ability to create new archives automatically when writing to non-existent archive subpaths with nested directory support.
- Implemented archive path resolution and validation with fallback to plain file writes for non-archive filenames.
- Added comprehensive test coverage for archive write operations including entry updates, archive creation, and fallback behavior.
2026-04-01 21:25:36 +02:00
can1357 d8f5bb4be2 feat(coding-agent): replaced markitdown CLI with native markit-ai library for document conversion
- Replaced Python-based markitdown CLI with native markit-ai library for document and notebook conversion.
- Added support for converting Jupyter notebooks (.ipynb) to markdown via markit-ai integration.
- Created markit utility module with file/buffer conversion wrappers and standardized error handling.
- Removed markitdown from Python tools manager and eliminated external CLI dependency.
- Updated fetch, read, and scraper tools to use new markit conversion API across codebase.
- Added test coverage for ipynb file conversion through markit utility.
2026-04-01 20:51:29 +02:00
can1357 9281e6b50e feat(coding-agent): added archive reading support for tar, tar.gz, tgz, zip
- Added archive reading support for .tar, .tar.gz, .tgz, and .zip files with virtual subpath syntax (archive.ext:path/inside/archive).
- Added archive listing and subdirectory navigation capabilities to explore archive contents without extraction.
- Added /tools slash command to display visible agent tools and their capabilities.
- Implemented ArchiveReader module with openArchive(), parseArchivePathCandidates(), and archive content extraction methods.
- Added fflate 0.8.2 dependency for archive decompression support.
- Added comprehensive test coverage for TAR, TAR.GZ, TGZ, and ZIP archive reading with fixture generation utilities.
2026-04-01 20:45:51 +02:00
can1357 e59436ba31 feat(coding-agent): added /tools command to display available agent tools
- 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.
2026-04-01 20:32:59 +02:00
can1357 5f0944ffe2 feat: added marketplace help command and improved catalog parsing resilience
- Added `/marketplace help` subcommand to display marketplace operations usage guide.
- Enhanced marketplace catalog parsing to skip invalid entries with warnings instead of failing.
- Improved `/marketplace discover` command to suggest official marketplace when no plugins available.
- Fixed marketplace error messages to display error details instead of object stringification.
- Added comprehensive marketplace plugin system documentation covering discovery, installation, and management.
2026-04-01 19:31:48 +02:00
can1357 94edc693cb fix(marketplace): corrected plugin name validation to allow dots
- Corrected plugin name validation regex to allow dots in addition to hyphens.
2026-04-01 19:09:55 +02:00
can1357 68cf52de3c fix(session): corrected artifact storage fallback for non-persistent sessions
- Fixed artifact storage for non-persistent sessions to use in-memory fallback instead of returning undefined, enabling proper spill truncation for all session types.
- Added in-memory artifact map and counter to SessionManager for fallback storage when file-based ArtifactManager is unavailable.
- Updated saveArtifact() JSDoc to reflect new behavior of returning artifact IDs for all sessions.
2026-04-01 19:08:48 +02:00
can1357 5366888205 ux(tools): added animated spinner with status icons to gh_run_watch output
- Enhanced `gh_run_watch` tool call rendering to display animated spinner status and target description (run ID, branch, or current HEAD) with improved visual hierarchy.
- Refactored renderer to use `formatStatusIcon` helper for consistent status display across spinner frames.
2026-04-01 17:44:31 +02:00
can1357 b7c801fab2 feat(tools): added GitHub Actions workflow renderer and enhanced gh-* tool outputs
- Added gh-renderer.ts module with GitHub Actions workflow visualization for terminal output.
- Enhanced gh_pr_view tool to fetch and display inline review comments alongside pull request reviews.
- Improved gh_run_watch tool output with structured job state tracking and failed log formatting.
- Fixed gh_run_watch to resolve explicit branch watches against GitHub API branch head instead of local HEAD.
- Fixed gh_* tool outputs to spill full large results to artifacts instead of pre-truncating.
- Standardized trailing newlines across 100+ prompt template files for POSIX compliance.
2026-04-01 17:35:39 +02:00
can1357 a0f2b0ad99 feat(tools): added gh_pr_checkout and gh_pr_push tools for worktree-based PR management
- Added gh_pr_checkout tool to check out GitHub pull requests into git worktrees with branch metadata.
- Added gh_pr_push tool to push checked-out pull request branches to source fork with force-with-lease support.
- Implemented 15+ git helper functions for worktree, branch, and remote management operations.
- Extended GhPrViewData interface with headRefOid, headRepository, isCrossRepository, and maintainerCanModify fields.
- Added comprehensive integration tests for gh_pr_checkout and gh_pr_push tools with fixture setup and cleanup.
2026-04-01 17:21:27 +02:00
can1357 010a69c7d6 feat(tools): introduced GitHub CLI tools for repository and workflow operations
- Added 7 GitHub CLI tools (repo view, issue view, PR view, PR diff, PR search, issue search, run watch) for repository and workflow operations.
- Added `github.enabled` setting to gate read-only GitHub CLI tools, disabled by default.
- Added bundled `/green` command for iterative CI failure fixing with optional git tag instructions.
- Implemented gh-cli module with GitHub CLI command execution utilities and output parsing.
- Added comprehensive test coverage for GitHub tools and custom commands with mocked CLI interactions.
2026-04-01 17:15:10 +02:00
can1357 d42975618d Merge remote-tracking branch 'origin/main' into pr-594
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
2026-04-01 15:35:50 +02:00
can1357 b264ddda84 Merge remote-tracking branch 'origin/main' into pr-594
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
2026-04-01 15:34:54 +02:00
can1357 766d81e8e4 Merge remote-tracking branch 'origin/main' into pr-587
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
2026-04-01 15:34:54 +02:00
can1357 268dca8fe8 Merge remote-tracking branch 'origin/main' into pr-587
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
2026-04-01 15:33:13 +02:00
can1357 606f9ac1f5 Merge remote-tracking branch 'origin/main' into pr-586-r2
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
2026-04-01 15:33:13 +02:00
can1357 dca0fcb974 fix(coding-agent): validate plugin scope flag 2026-04-01 15:31:46 +02:00
BayLee4 2d5f802daf fix(coding-agent): do not enable web_search if explicitly disabled (#593)
Co-authored-by: le-cameleon <200889489+le-cameleon@users.noreply.github.com>
2026-04-01 15:26:08 +02:00
Vu Anh Nguyen 3860ac986c fix(coding-agent): strip stale assistant OpenAI Responses replay payload on rehydrate
sanitizeRehydratedOpenAIResponsesAssistantMessage now removes the
assistant providerPayload for Responses-family messages, not just the
stale thinkingSignature. After rehydration the native replay snapshot
belongs to a previous live provider connection and replaying it on a
warmed session causes 401 rejections from GitHub Copilot.

User/developer providerPayload is preserved by the caller since it
carries durable compaction and preserved history needed for valid cold
request reconstruction.

Fixes #592
2026-04-01 14:53:28 +07:00
can1357 906123c97d style: reformat 2026-04-01 04:52:47 +02:00
can1357 77eddf80e9 fix(patch): wrapped long diff lines with continuation gutters
- Replaced truncation with line wrapping for diff output in the edit tool renderer.
- Added `wrapEditRendererLine` to preserve gutter markers and line numbers on continuation lines.
Fixes #578
2026-04-01 04:52:03 +02:00
can1357 6645a7a059 fix(model-registry): filtered disabled providers from model listing
- Applied `disabledProviders` setting to `getAvailable()` and `getDiscoverableProviders()` so `--list-models` and `/model` hide models from disabled providers.
- Initialized settings before model refresh in the `--list-models` code path.
- Added tests verifying disabled providers are excluded from both methods.
Fixes #588
2026-04-01 04:52:03 +02:00
can1357 3b68346123 fix(render-utils): used diff-specific colors for diffstat add/remove
- Replaced success/error theme colors with toolDiffAdded/toolDiffRemoved for diff stats display.
Fixes #589
2026-04-01 04:52:02 +02:00
can1357 cbb9f21363 chore(tools): added napi-rs to auto-generated file detection patterns
- Added napi-rs to known code generator patterns for auto-generated file detection.
2026-04-01 04:52:02 +02:00
can1357 15f34723c1 feat(web): removed code_search tool and Exa API integration from web module
- Removed code_search tool and all related Exa API integration from web search module.
- Deleted code-search.ts implementation including CodeSearchResponse types and executeCodeSearch() function.
- Updated getSearchTools() to return only webSearchCustomTool, removing dual-tool support.
- Removed code_search tool documentation from README and prompt files.
2026-04-01 04:52:02 +02:00
BayLee4 74c4197855 feat(coding-agent): priority to commit model for titles with fallback to smol (#573)
Co-authored-by: le-cameleon <200889489+le-cameleon@users.noreply.github.com>
2026-04-01 04:51:53 +02:00
David Dembeck c4f9216674 fix(git): preserve empty context lines in joinPatch to prevent corrupt patch errors (#583) 2026-04-01 04:48:12 +02:00
Miroslav Drbal 5acd56a5e3 fix(coding-agent): only shadow user entry when project install is enabled
listInstalledPlugins() was marking user-scope entries as shadowedBy:
"project" based on plugin ID presence in the project registry alone.
A disabled project copy (enabled: false) is not active in discovery, so
the user copy is the effective install and must not appear shadowed.

activeProjectIds now only includes project plugins where the first entry
does not have enabled: false.
2026-03-31 22:03:03 +02:00
Miroslav Drbal b160455027 fix(coding-agent): declare --scope flag in Plugin command
omp plugin ... --scope project was rejected by the strict CLI parser
before reaching any handler, making the feature inaccessible via the
omp plugin entrypoint. Declaring scope in static flags and forwarding
it to PluginCommandArgs.flags lets the CLI framework accept and route it.
2026-03-31 22:02:12 +02:00
Miroslav Drbal c7f4f597bd fix(coding-agent): pass scope through plugin selector uninstall flow
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.
2026-03-31 21:29:24 +02:00
Sam Biggins cafcf906fd fix(tui): cap inline image height and preserve multiplexer scrollback
Inline images (screenshots from puppeteer, assistant images) rendered at
unbounded height — a 1280x800 screenshot consumed ~32 terminal rows,
causing excessive scrolling. In multiplexers (tmux, screen, zellij),
this was compounded by fullRender clearing scrollback on every resize.

Image height cap:
- New setting tui.maxInlineImageRows (default 20)
- Effective cap: min(setting, floor(viewport * 0.6))
- Shared resolveImageOptions() replaces per-site settings reads
- Existing calculateImageFit() already handles maxHeightCells

Multiplexer scrollback preservation:
- Skip CSI 3J (clear scrollback) in tmux/screen/zellij
- Skip fullRender(true) on height change in multiplexers
- Cached isMultiplexer constant (TMUX, STY, ZELLIJ env vars)
2026-03-31 09:34:11 -07:00
Miroslav Drbal 05966c8910 feat(coding-agent): marketplace plugin project scope
Plugins can now be installed at user scope (global) or project scope
(per-project, higher capability priority). Scope is encoded in registry
file location, not a metadata field:

  user:    ~/.omp/plugins/installed_plugins.json
  project: <nearest-project>/.omp/plugins/installed_plugins.json
  cache:   ~/.omp/plugins/cache/plugins/  (shared, path-referenced)

Project root discovery: resolveActiveProjectRegistryPath(cwd) walks up
from cwd looking for the nearest .omp/ directory, falling back to the
nearest .git root. This is the single resolver used by install, uninstall,
list, upgrade, discovery, and doctor.

Discovery: listClaudePluginRoots(home, cwd?) reads both registries when
cwd is provided. Project entries shadow user entries for the same plugin
ID. Cache key is canonical ("${home}:${resolvedProjectPath}") so nested
cwds within the same project share a cache entry.

Manager changes:
- installPlugin({ scope? }): routes registry reads/writes by scope;
  checks collectReferencedPaths() across both registries before deleting
  any cached plugin dir to prevent cross-scope data loss
- uninstallPlugin(id, scope?), setPluginEnabled(id, enabled, scope?),
  upgradePlugin(id, scope?): throw a disambiguation error when the plugin
  exists in both scopes and no scope is specified
- upgradePluginAcrossScopes(id): new; upgrades all scopes the plugin is
  installed in; returns InstalledPluginEntry[]
- upgradeAllPlugins(): uses upgradePluginAcrossScopes; result includes scope
- listInstalledPlugins(): returns InstalledPluginSummary[] merged from both
  registries; user entries marked shadowedBy: "project" when overridden

CLI: omp plugin install|uninstall|upgrade|enable|disable --scope user|project
Slash: /marketplace install [--scope user|project] name@marketplace
MarketplaceManager constructed with projectInstalledRegistryPath in all
CLI handlers and builtin-registry.ts via resolveActiveProjectRegistryPath.

.gitignore: .omp/plugins/ added (local runtime state, not committed).
preloadPluginRoots/clearClaudePluginRootsCache carry cwd through for LSP.
main.ts passes getProjectDir() at startup.

Tests: 226 pass across 13 files. New: project-scope.test.ts (resolver
walk-up, .git fallback, null return, canonical path, shadow precedence);
manager scope tests (registry isolation, disambiguation errors, cross-scope
cache-ref protection, upgradePluginAcrossScopes, shadowedBy marking).

fixes #581
2026-03-31 17:43:09 +02:00
can1357 d18504d632 fix(coding-agent): corrected marketplace plugin selector error handling and cleanup
- Added error handling for marketplace plugin selector failures with user-facing error messages.
- Fixed marketplace clone promotion timing by extracting logic into separate function and applying consistently across addMarketplace and refreshMarketplace methods.
- Added cleanup of temporary clone directories on source verification failures to prevent orphaned files.
- Improved plugin selector UI rendering by expanding onCancel callback to trigger requestRender after completion.
- Fixed LSP config path handling by replacing hardcoded filename array with variable reference.
- Enhanced error handling for unknown plugin source variants in marketplace validation.
2026-03-30 13:54:31 +02:00
can1357 398435596c chore(agents): clarified reviewer agent procedure by removing parallel spawning
- Simplified reviewer agent procedure by removing parallel task spawning and consolidating steps.
2026-03-30 13:46:54 +02:00
Miroslav Drbal 304158cadb fix: check duplicate marketplace before fetching, reject relative sources for URL marketplaces
- addMarketplace reads registry before fetching; if the fetched catalog
  name collides with an existing entry, cleans up the clone and throws
  before any cache corruption occurs
- installPlugin rejects relative string sources when the marketplace was
  added via URL (only marketplace.json is cached, not the plugin tree)
2026-03-30 13:44:55 +02:00
Miroslav Drbal f65df186b8 fix: refresh slash commands on /reload-plugins, validate string source paths at parse time
- /reload-plugins now calls refreshSlashCommandState() so newly
  installed/removed plugin commands take effect without restart
- parseMarketplaceCatalog rejects string sources that don't start
  with './' at parse time instead of deferring to install-time crash
2026-03-30 13:44:55 +02:00
Miroslav Drbal 9218b1450b fix: guard npm dist-tags in classifier, reject catalog name drift, validate source payloads
- classifyInstallTarget skips known npm dist-tags (latest, next, beta,
  etc.) and semver-like strings before checking marketplace names
- updateMarketplace throws if fetched catalog name differs from the
  registered name, preventing stale data on upstream renames
- parseMarketplaceCatalog validates variant-specific required fields
  (github.repo, url.url, git-subdir.url+path, npm.package) at parse
  time instead of deferring to install-time crashes
2026-03-30 13:44:55 +02:00
Miroslav Drbal 0b85d3a1ad fix: validate plugin names at parse time, atomic cache replacement
- parseMarketplaceCatalog rejects plugin names that fail isValidNameSegment
  instead of deferring the error to install time
- cachePlugin copies to staging dir first, then renames into place;
  a failed copy no longer destroys the active install
- Fix ReturnType<> usage in cloneAndReadCatalog
2026-03-30 13:44:55 +02:00
Miroslav Drbal b134c6628b fix: preserve disabled flag on force-reinstall, re-warm preloaded roots after cache clear
- Carry over enabled:false from existing entries during force reinstall
  and upgrade; disabled plugins stay disabled without user intent change
- After clearing plugin roots cache, fire-and-forget preloadPluginRoots()
  so sync LSP config reads stay valid for the rest of the session
2026-03-30 13:44:54 +02:00
Miroslav Drbal 7a8e4e021e fix: preserve --plugin-dir across cache clears, safe force-reinstall, URL classification
- Store injected --plugin-dir roots in module-level variable; survive
  cache clears by re-merging on next listClaudePluginRoots() call
- Defer old plugin deletion in force-reinstall until new cache succeeds;
  transient failures no longer leave the plugin uninstalled
- Classify HTTP URLs by pathname instead of full string; query params
  no longer cause .json URLs to be misclassified as git
2026-03-30 13:44:54 +02:00
Miroslav Drbal 87b0e8eab4 fix: uninstall routes by installed registry, not marketplace registration
Check installed_plugins.json directly instead of relying on the
marketplace being registered. Handles the case where a marketplace
entry is removed but its plugins are still installed.
2026-03-30 13:44:54 +02:00
Miroslav Drbal 256af35527 fix: wire marketplace routing for uninstall + list
- handleUninstall now classifies targets and routes marketplace
  specs to MarketplaceManager.uninstallPlugin()
- handleList shows both npm and marketplace plugins grouped by type
2026-03-30 13:44:54 +02:00
Miroslav Drbal 5bf8e4ca92 fix: wire classifyInstallTarget into handleInstall
Route marketplace install targets (name@marketplace) to
MarketplaceManager.installPlugin() instead of npm install.
classifyInstallTarget() was implemented but never called from
the install handler.
2026-03-30 13:44:53 +02:00
Miroslav Drbal 505b671c77 fix: address Codex review findings
- Honor enabled:false flag in listClaudePluginRoots (skip disabled plugins)
- Normalize local source URIs to absolute paths in addMarketplace
- Resolver returns explicit tempCloneRoot instead of path-based inference
2026-03-30 13:44:53 +02:00
Miroslav Drbal dc98266281 feat: add marketplace auto-update with background catalog refresh
- Add marketplace.autoUpdate setting (off/notify/auto, default notify)
- Background catalog refresh on startup when stale (>24h)
- /marketplace upgrade [name@marketplace] slash command
- omp plugin upgrade CLI command
- checkForUpdates, upgradePlugin, upgradeAllPlugins, refreshStaleMarketplaces
- Semver-aware version comparison with non-semver fallback
- 10 new tests for auto-update methods
2026-03-30 13:44:53 +02:00
Miroslav Drbal 4e199f93f7 feat: add marketplace plugin system
Add Claude Code-compatible marketplace plugin infrastructure:

- Registry: types, ID helpers, atomic read/write for marketplaces.json
  and installed_plugins.json (Claude Code format with version: 2)
- Fetcher: classifySource (6 ordered rules), parseMarketplaceCatalog,
  fetchMarketplace (local sources; git/http stubs for Phase 2)
- Resolver + Cache: resolvePluginSource with pathIsWithin containment,
  cachePlugin, removeCachedPlugin, cleanOrphanedCache
- MarketplaceManager: orchestrates add/remove/update marketplaces,
  install/uninstall/enable plugins, clearPluginRootsCache on mutation
- CLI: omp plugin marketplace add|remove|update|list,
  omp plugin discover, classifyInstallTarget for name@marketplace
- Discovery: listClaudePluginRoots reads OMP registry alongside
  Claude's, OMP authoritative for duplicate plugin IDs
- Args: --plugin-dir repeatable flag (parsing only, runtime wiring TBD)
- Slash command: /reload-plugins clears fs + roots cache
- Test fixtures and 130 tests across 8 test files
2026-03-30 13:44:53 +02:00
can1357 bc2b99f9b0 feat(coding-agent): removed grep.app provider, consolidated code search to Exa
- Removed grep.app code search provider support; code search now uses Exa exclusively.
- Removed `providers.codeSearch` configuration setting and related UI options from settings schema.
- Removed `setPreferredCodeSearchProvider` and `isCodeSearchProviderId` exports from public API.
- Simplified code search implementation by eliminating provider selection logic and grep-specific parsing.
2026-03-30 13:44:52 +02:00
Qiang 577ccfd724 fix(cursor): resolve shell stream hanging on turnEnded signal (#555)
- Add resolveH2 promise resolver triggered on explicit turnEnded message
- Import CursorShellStreamCallbacks, ExecClientControlMessageSchema, ExecClientStreamCloseSchema
- Refactor handleShellStreamArgs to support shellStream handler with proper logging
- Update types.ts and coding-agent cursor.ts accordingly
2026-03-30 13:44:36 +02:00
Miroslav Drbal [ApoC] 62676f4de8 fix(mcp): activate new server tools immediately after /mcp add (#557)
refreshMCPTools preserves the prior MCP tool selection by only keeping
tools that were already active. Brand-new servers added via /mcp add
had their tools registered in the registry but never activated on the
agent, making them invisible until restart.

After the connection is confirmed in #handleWizardComplete, explicitly
add the new server's tools to the active set via setActiveToolsByName.
Covers both the normal connection path and the fallback

Co-authored-by: Miroslav Drbal <miroslav.drbal@gendigital.com>
2026-03-30 13:28:42 +02:00
enieuwy 323a3bc29c feat(core): add first-class retry fallback chains for model/provider failover (#541)
* feat(rules): implemented alwaysApply auto-injection into system prompt

rules with alwaysApply: true were parsed by all providers and used to
exclude the rule from rulebookRules, but the inclusion half was never
built — rule content was silently dropped. now:

- full content is injected directly into the system prompt (before the
  rulebook rules section) in both default and custom prompt templates
- rules remain addressable via rule:// for re-reading
- ttsr rules still take priority (condition + alwaysApply goes to ttsr only)

updated rulebook-matching-pipeline.md to reflect the three-bucket split
(ttsr > always-apply > rulebook) and corrected the rule:// resolution
docs.

* feat(browser): implement screenshot path saving

- Add `browser.screenshotDir` setting (tools tab) for a persistent
  default screenshot directory, configurable via /settings
- Honour the existing `path` parameter in the screenshot action,
  which was declared in the schema but never consumed by the implementation
- Resolution order: params.path (abs) > join(screenshotDir, params.path)
  > join(screenshotDir, screenshot-<timestamp>.png) > /tmp only
- Writes full-resolution buffer to disk (not the API-compressed copy)
- Creates destination directory recursively if it doesn't exist
- details.screenshotPath reflects the actual saved location

Fixes: path param silently ignored since removal in v11.5.0

* feat(browser): expand ~ in screenshotDir and path params

Users can now configure browser.screenshotDir as ~/Downloads or
~/Pictures and use params.path as ~/screenshots/foo.png without
needing to supply fully-qualified paths.

* fix(browser): write screenshot to exactly one location

Previously wrote to /tmp unconditionally then copied to user path,
resulting in two files. Now resolves a single destination upfront:
  1. params.path (absolute, or relative to screenshotDir/cwd)
  2. screenshotDir + auto-timestamp filename
  3. /tmp fallback (original behaviour, unchanged)

Also: user-defined destinations receive the full-res buffer;
/tmp fallback retains the API-compressed copy as before.

* feat(settings): add text input support for plain string settings

Settings with type: "string" and no submenu now render as an editable
text field in the /settings TUI panel instead of being silently skipped.

- settings-defs.ts: add TextInputSettingDef interface; pathToSettingDef
  falls through to { type: "text" } for any plain string schema entry
- settings-selector.ts: add TextInputSubmenu class (mirrors
  ConfigInputSubmenu from plugin-settings.ts); add "text" case to
  #defToItem; add #createTextInput method

This makes browser.screenshotDir visible and editable in the Tools tab.
Empty field on submit clears the setting (falls back to /tmp behavior).

* fix(settings): text input — cursor at end, block tab navigation

- Cursor: call handleInput(ctrl+e) after setValue to jump to end of
  pre-filled string instead of leaving it at position 0
- Tab/arrow guard: add #textInputActive flag; suppress tab-switch and
  left/right routing to tab bar while a TextInputSubmenu is open, so
  arrow keys reach the Input component's cursor movement handlers
  instead of switching settings tabs

* fix(browser): expand ~\ (Windows backslash) in screenshot paths

expandHome now handles both Unix ~/... and Windows ~\... separators,
matching user expectation on all platforms. Addresses Codex review.

* fix(coding-agent): use expandPath for screenshots

* docs: add changelog for screenshot path option

Bug fixes:
- Add browser.screenshotDir to settings-schema.ts (lost during rebase conflict)
- Fix stale expandHome comment to expandPath in settings-selector.ts
- Final screenshotDir description: Directory to save screenshots with ~ support

* fix: biome format corrections for screenshot-path-option branch

* fix: add missing #textInputActive field and screenshotDir default

* fix(browser): align screenshot metadata with saved file contents

When screenshotDir or params.path is set, the full-resolution PNG buffer
is written to disk. Previously mimeType/bytes in details still reflected
the resized payload sent to the model, making metadata inconsistent with
the actual saved file.

Now savedBuffer/savedMimeType track what is written, and details reflects
that. Display output distinguishes 'Saved' vs 'Model' when full-res is
used, and collapses to a single Format/Dimensions line for temp-only.

* fix(browser): resolve params.path relative to cwd regardless of screenshotDir

screenshotDir is a default save location, not an anchor for explicit
paths. A relative params.path should always resolve against cwd so its
semantics are stable and predictable regardless of user settings.

* fix(tui): enforce strict line budget for collapsed tool output

The grep, ast_grep, and ast_edit renderers used group-count-based
collapse that always included the first group unconditionally,
allowing collapsed output to remain visually large when a single
group contained many lines.

Add maxCollapsedLines to renderTreeList that enforces a strict
total-line cap in collapsed mode. Items that exceed the remaining
budget are skipped entirely (no broken fragments). The isLast tree
branch is computed after the budget check to avoid double-last
branches when a summary line follows.

Remove the per-tool getCollapsedMatchLimit / getCollapsedChangeLimit
helpers that are now redundant.

Fixes #455

Made-with: Cursor

* WIP

* WIP

* cleanup

* docs(coding-agent): update changelog for custom model tags and cycle order

* Fix custom model precedence across load and refresh

* feat(ask): add multiline editor support for custom input

* feat(extension-ui): add dialog options and abort signal support to editor

* docs(ask): add multiline editor and timeout behavior guidance

* docs(ask): simplify multiline input documentation

* fix(tui): preserve terminal scrollback during full redraws

Replace destructive \x1b[3J\x1b[2J\x1b[H full-redraw sequence with
scrollback-preserving repaint helpers:

- seedTranscript: first paint with no prior frame, writes full transcript
  without clearing scrollback
- repaintViewport: trusted-frame repaints that scroll viewport-shift
  delta into scrollback before overwriting visible rows in-place
- Height-increase handler that pushes revealed scrollback back before
  reclaiming the display

Replace requestRender(true) state destruction with a one-shot
without resetting #previousLines or cursor bookkeeping.

Track #previousHeight to detect terminal height increases that pull
scrollback lines into the visible area.

fixes #507

* fix(tui): fix exit gaps, content shrink drift, and overlay cursor recovery

- Rewrite stop() to use viewport-relative cursor positioning instead of
  content-length, preventing blank gaps when content is shorter than viewport
- Replace trailing \r\n\x1b[2K clear loops in repaintViewport() and
  height-increase path with \r\n\x1b[J to avoid cursor drift past content
- Add 12 TUI regression tests for exit gaps, content shrink, and overlay
  dismiss cursor recovery
- Add 6 coding-agent controller tests for /new and /tree commands

* fix(tui): redraw sparse height increases atomically

* fix(coding-agent,tui): address review regressions

* fix(tui): reseed after terminal resume

* test(ai): avoid leaking kagi module mocks

* fix(ask): keep multiline custom input in prompt gutter

* fix(ask): preserve multiselect choices on editor dismiss

* fix(ask): honor app interrupt in prompt editor

* fix(coding-agent): preserve new-session approval state

* feat(core): add session-scoped model/provider retry fallback policy

* feat(core): validate retry fallback chains on session startup

* fix(ask): preserve prior answer when custom editor dismissed in single-select

* fix(core): harden retry fallback policy semantics

* fix(core): correct retry fallback edge cases

* test(coding-agent): removed macOS fallback test case from theme detection

- Removed test case for macOS fallback behavior inside Zellij.

* refactor: simplified null checks using optional chaining across TypeScript and Rust modules

- Simplified null/empty checks across TypeScript codebase using optional chaining operator (?.) for improved readability.
- Replaced explicit null checks in validation logic with optional chaining in oauth-discovery, gemini-cli, claude, zai, and lsp modules.
- Updated error handling in Rust command invocation to use double question mark operator (??) for cmd_result.
- Consolidated null validation patterns across tools (bash-skill-urls, browser, gemini-image, resolve) and keybindings using optional chaining.

* chore: bump version to 13.15.1

* fix(core): address PR review on fallback retry behavior

* test(ai): refactored auth storage test to use spyOn for cleaner mocks

- Refactored auth storage test to use vi.spyOn() instead of vi.mock() for cleaner mock management.
- Simplified mock type definitions by leveraging bun:test's Mock type import.

* chore: bump version to 13.15.2

* Fix stale OpenAI Responses replay across session boundaries (#534)

* Fix stale OpenAI Responses replay across session boundaries

Fixes #505

* Fix CI tests for session replay change

* Harden session reload and switch rollback

* Guard session switch snapshots

* fix(coding-agent): preserve responses replay snapshots

* Normalize pasted image formats before attach (#543)

Co-authored-by: iter <itertoolz@gmail.com>

* Allow overriding the Codex web search model (#516)

* Allow codex web search model override

* Handle blank codex web search model

* feat(ai): add gemini-3.1-pro-preview models to google-vertex provider (#521)

Add gemini-3.1-pro-preview and gemini-3.1-pro-preview-customtools to
the google-vertex provider in models.json, matching the existing
google-generative-ai entries.

Fixes #520

Co-authored-by: Muness Castle <munesscastle@artium.ai>

* Make temporary model selector keybinding configurable (#539)

Fixes #533

* chore: bump models.json

* refactor(coding-agent): migrated test mocks to vitest spyOn with Symbol.dispose cleanup

- Migrated test mocking from bun:test mock API to vitest spyOn pattern across 9 test files.
- Extracted mock setup logic into reusable helper functions with Symbol.dispose cleanup pattern.
- Replaced manual beforeEach/afterEach and try-finally blocks with TypeScript 5.2 using declarations.
- Removed 178 lines of boilerplate mock initialization and restoration code from test suite.

* chore: bump version to 13.15.3

* fix(ask): restore prompt-style enter handling

* fix(tui): avoid blank scrollback regressions

* fix(models): keep same-id replacements authoritative

* fix(tui): enforce collapsed line budgets

* fix(models): unify selector role sources

* fix(rules): dedupe always-apply prompt injection

* fix(browser): show saved screenshot path

* style: format merged PR fixes

* refactor(coding-agent): restructured screenshot and prompt utilities into focused helpers

- Extracted screenshot formatting logic into dedicated `formatScreenshot()` function with options support.
- Consolidated prompt source deduplication into `dedupePromptSource()` helper to prevent rule duplication.
- Refactored editor text sanitization to use `replaceTabs()` utility for consistent tab width handling.
- Added test coverage verifying editor respects configured tab width when loading text programmatically.

* refactor(coding-agent): restructured validation and rendering for consistency

- Refactored theme color validation to use single source of truth with THEME_COLOR_RECORD object.
- Simplified model registry to defer per-model overrides to dedicated method and use constant for role IDs.
- Refactored tree list rendering to pre-render items once for consistent line counts across phases.
- Refactored question result formatting to use early returns and consistently include question ID in output.
- Updated hook editor hint text to include ctrl+g external editor option when prompt style is enabled.
- Removed unused isLogicalLineStart property from LayoutLine interface in editor component.

* revert: 535 due to TUI regressions

* test(coding-agent): corrected hook-editor assertion for keybinding render

- Corrected assertion in hook-editor test to verify external editor keybinding is rendered.

* feat(tools): added root path alias to resolve bare / to working directory

- Added root path alias feature to resolve bare `/` to session working directory in path resolution.
- Updated browser tool to use `resolveToCwd()` for consistent workspace-relative path handling.
- Added comprehensive test suite validating root path alias resolution across grep, read, find, ast_grep, and ast_edit tools.

* feat(prompts/tools): clarified hashline block boundary handling with examples

- Improved hashline tool documentation with clearer guidance on block boundary handling and closing delimiter duplication prevention.
- Added concrete example demonstrating correct anchor placement when replacing entire blocks including closing braces.
- Reorganized boundary duplication warnings into actionable self-check guidance with visual comparison steps.

* chore: bump version to 13.16.0

* fix(coding-agent): fixed python kernel startup hangs (#548)

* fix(coding-agent): fixed python kernel startup hangs

* fix(coding-agent): fixed startup timeout regressions

* fix(coding-agent): preserved startup cancellation typing

* perf(pi-natives): optimized memory allocation with MiMalloc integration

- Integrated MiMalloc as global allocator to improve memory allocation performance.

* feat: fff

- Added SearchDb class for stateful shared search database instances enabling persistent file indexing and frecency tracking across grep, glob, and fuzzyFind operations.
- Added optional db parameter to grep(), glob(), and fuzzyFind() functions for database-backed searching with improved performance via cached file indices.
- Replaced grep-searcher with fff-grep and added fff-search dependency for enhanced file discovery and search capabilities with memory-mapped file support.
- Migrated fuzzy file discovery from fd module to fff module with SearchDb integration for stateful caching and improved search performance.
- Exported SearchDb type from @oh-my-pi/pi-natives public API for type-safe usage in grep, glob, and fuzzyFind workflows.

* feat(pi-natives): added unified picker coordination for file search operations

- Added `wait_for_picker_scan()` function to search_db module with cancellation token support for polling picker scan completion.
- Integrated picker-based file search into glob matching logic with `collect_files_from_picker()` helper to reuse shared SearchDb picker results.
- Refactored fff and grep modules to use centralized `wait_for_picker_scan()` wrapper instead of direct FilePicker calls, improving cancellation handling.
- Propagated SearchDb instance through agent session initialization and input controller to enable unified file picker coordination across search operations.

* chore: bump version to 13.16.1

* fix: install zig in CI

* feat(tui): make inline image max-width configurable via tui.maxInlineImageColumns (#551)

* feat(tui): make inline image max-width configurable via tui.maxInlineImageColumns

* fix(tui): handle 0 as unlimited in maxInlineImageColumns; drop || undefined coercion

* feat(browser): auto-detect NixOS and use system Chromium (#550)

Puppeteer's bundled Chromium is a dynamically-linked FHS binary that
cannot run on NixOS. On startup, resolveSystemChromium() checks for
/etc/NIXOS and searches for a usable binary in order:

  1. chromium on PATH
  2. chromium-browser on PATH
  3. ~/.nix-profile/bin/chromium
  4. /run/current-system/sw/bin/chromium

The resolved path is passed as executablePath to puppeteer.launch().
Result is cached per process. On non-NixOS systems the function returns
undefined immediately, leaving Puppeteer's default resolution intact.

* feat(pi-natives): added automatic parenthesis escaping in regex patterns

- Added automatic escaping of unescaped parentheses in regex patterns when group syntax errors occur, enabling literal function call patterns like `fetchAnthropicProvider(` to work as search queries.
- Extracted regex matcher builder into separate function for reusability and error recovery logic.
- Added 2 test cases validating parenthesis escaping behavior for both escaped and literal parentheses.
- Fixed documentation formatting in sanitize_braces comment.

* style: reformat

* chore: bump version to 13.16.2

* fix: only show update banner when npm version is strictly newer (#552)

* fix(ai): corrected OAuth credential updates to replace in-place instead of accumulating soft-deleted rows

- Fixed OAuth credential updates to replace matching credentials in-place rather than creating disabled rows, preventing unbounded accumulation of soft-deleted credentials.
- Modified OAuth credential saving to preserve unrelated identities instead of replacing all credentials for a provider.
- Updated credential identity resolution to use provider context for more accurate email deduplication.
- Implemented upsertAuthCredentialForProvider method to handle credential matching and in-place updates.
- Added 5 test cases covering credential preservation across reauth, multi-account scenarios, and stale cache handling.

* chore: bump version to 13.16.3

* feat: introduced unified range API for hashline edits and model catalog updates

- Simplified hashline edit location API by replacing separate `line` and `block` properties with unified `range` property accepting `{ pos, end }` anchors.
- Renamed hashline helper functions from `hlineref`/`hlinefull` to `href`/`hline` for improved brevity and consistency.
- Added detection for `kysely-codegen` generated files in auto-generated file guard with corresponding test coverage.
- Added 13 new AI model configurations and updated token limits and pricing for existing models across multiple providers.
- Enhanced file type validation in grep native to reject symlinks, FIFOs, sockets, and non-regular files with improved error handling.

* chore: bump version to 13.16.4

* fix: pin rustc-hash to 2.1.1 to avoid SIGILL on CI

rustc-hash 2.1.2 (released today) refactored hash_bytes to use
split_first_chunk, which produces illegal instructions when compiled
with nightly + -C target-cpu=x86-64-v3 on CI runners.

* fix(ci): pin nightly to 2026-03-27 to avoid codegen SIGILL regression

Today's nightly produces illegal instructions when compiled with
-C target-cpu=x86-64-v3. Reverts the unnecessary rustc-hash pin from
the previous commit since the real cause is the nightly compiler.

Also lets Cargo.lock return to rustc-hash 2.1.2 (not the culprit).

* fix(ci): add rustup target fallback for pinned nightly cross-compile

* fix(coding-agent): do not prompt to use grep and find tools if they are disabled (#566)

Co-authored-by: le-cameleon <200889489+le-cameleon@users.noreply.github.com>

* fix(natives): skipped grep special files (#565)

avoided opening fifos and other special filesystem nodes during grep and added fifo regressions in native and coding-agent tests.

* fix: skill baseDir regex fails on Windows backslash paths (#554)

The regex that strips SKILL.md from the path to compute baseDir only
matches forward slashes. On Windows where paths use backslashes, the
replace is a no-op and baseDir equals the full SKILL.md file path.

This breaks sub-path resolution for skills: the subpath gets appended
to the SKILL.md file path instead of the skill directory.

Fix: use character class matching both path separators.

---------

Co-authored-by: deadcode-walker <268043493+deadcode-walker@users.noreply.github.com>
Co-authored-by: Rens Tillmann <rens@super-forms.com>
Co-authored-by: haiyang.zhou <haiyang.zhou@seamoney.com>
Co-authored-by: Leo P <junk@slact.net>
Co-authored-by: Zakhar Kogan <36503576+zaharkogan@users.noreply.github.com>
Co-authored-by: Vu Anh Nguyen <vuanhng00@gmail.com>
Co-authored-by: can1357 <me@can.ac>
Co-authored-by: daandden <64765666+daandden@users.noreply.github.com>
Co-authored-by: iter <72358817+itertea@users.noreply.github.com>
Co-authored-by: iter <itertoolz@gmail.com>
Co-authored-by: Cheol Kang <dev@cheol.me>
Co-authored-by: Muness Castle <931+muness@users.noreply.github.com>
Co-authored-by: Muness Castle <munesscastle@artium.ai>
Co-authored-by: zamo <falby97@proton.me>
Co-authored-by: elikoga <elikowa@gmail.com>
Co-authored-by: BayLee4 <63376748+BayLee4@users.noreply.github.com>
Co-authored-by: le-cameleon <200889489+le-cameleon@users.noreply.github.com>
Co-authored-by: Wiedzmin <56316383+art-wiedzmin@users.noreply.github.com>
2026-03-29 17:50:36 +02:00