* 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>
- 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.
- Added contract system for validating benchmark commands, metrics, scope paths, constraints, and off-limits paths.
- Contract validation enforces matching initialization parameters against autoresearch.md before init_experiment.
- Segment fingerprinting detects configuration drift and warns when metrics are not directly comparable.
- Added pending run detection and recovery to resume incomplete experiments from .autoresearch/runs/.
- Run directories organize artifacts with benchmark logs and optional checks logs for traceability.
- Extended experiment state to track run number, command, scope, off-limits, constraints, and fingerprint.
- Fixed rate-limit-utils to recognize and classify 'usage limit' errors as QUOTA_EXHAUSTED instead of transient.
- Added isUsageLimitError() utility function for unified detection of persistent quota limit errors across providers.
- Fixed Codex provider to return immediately on usage-limit errors instead of retrying, preventing unnecessary 5-minute delays.
- Removed usage.?limit pattern from TRANSIENT_MESSAGE_PATTERN to prevent misclassification of persistent quota errors.
- Added ACP (Agent Client Protocol) mode for headless agent operation via --mode acp flag.
- Integrated Agent Client Protocol SDK with session management, streaming communication, and event mapping.
- Added ensureOnDisk() method to SessionManager for immediate session persistence without requiring assistant messages.
- Changed session persistence to use atomic file rewrite for unflushed sessions.
- Implemented AcpAgent class with session management, prompt handling, MCP server configuration, and event streaming.
- Simplified plan mode enforcement by removing tool retrieval and restoration logic.
- Replaced tool existence checks with registry lookup to reduce intermediate variables.
- Made sessionDir parameter optional in SessionManager.create(), forkFrom(), continueRecent(), and list() methods with automatic default computation.
- Updated SessionManager.getDefaultSessionDir() to accept optional agentDir parameter for custom sessions root configuration.
- Changed SessionManager.list() signature to require cwd parameter as first argument with sessionDir now optional.
- Implemented multi-root session migration support by replacing global migration state with per-root tracking and extracting session directory encoding logic.
- Added resolveManagedSessionRoot() function to determine if session directory is managed and extract its root.
- Added symlink and path alias resolution to session directory handling for consistent behavior across aliased home and temp directories.
- Improved status line path display to strip display roots using canonical path resolution, correctly handling symlink-equivalent directory aliases.
- Added support for quoted paths in grep, ast_grep, and find tools to properly handle directory names with spaces.
- Improved ast_grep error messaging when no matches found with parse errors to suggest narrowing path/glob or setting language.
- Extracted path utility functions (resolveEquivalentPath, normalizePathForComparison, pathIsWithin, relativePathWithinRoot) to shared utils package.
- Added comprehensive test coverage for symlink alias resolution in status line path rendering and session directory handling.
* Add MCP tool discovery search and live refresh
* Fix MCP discovery review feedback
* Address remaining MCP discovery review comments
* feat: compact MCP discovery search results
* fix: align MCP discovery search contract
* feat: add MCP server tool counts to discovery hints
* fix(agent): corrected stale toolChoice validation against active tools
- Fixed stale forced toolChoice passed to provider after mid-turn tool refresh by validating against active tools.
- Added refreshToolChoiceForActiveTools() to filter invalid tool choices when available tools change.
- Changed getToolChoice config to use computed function instead of static property for dynamic validation.
- Fixed MCP tool selection tracking in coding-agent to distinguish between discovery-enabled and non-discovery sessions.
- Updated search_tool_bm25 to filter already-selected tools before applying limit parameter.
---------
Co-authored-by: can1357 <me@can.ac>
- Added automatic migration of legacy absolute-path session directories with double-dash format to new canonical locations.
- Enhanced session directory encoding to use `-tmp-` prefix for temporary directories instead of legacy double-dash format for improved clarity.
- Extracted session directory migration logic into reusable helper functions for better maintainability.
- Updated test setup to mock home directory and verify session migration behavior with temporary paths.
- Added `attribution` option to `PromptOptions` for controlling billing and initiator attribution.
- Updated subagent prompts to explicitly set `attribution: "agent"` for accurate billing attribution.
- Refactored message attribution logic to use configurable `promptAttribution` with fallback defaults.
- Added test coverage for `attribution` option in subagent reminder prompts.
Fixes#439.
feat(coding-agent): added attribution option and explicit session directory control
- Added `attribution` option to `PromptOptions` for explicit billing and initiator attribution control.
- Updated `SessionManager.create()` to require both `cwd` and `sessionDir` parameters for explicit session directory control.
- Changed session directory naming for temporary working directories from `--` format to `-tmp-` prefix.
- Made `cwd` and `sessionDir` fields mutable in SessionManager to support session relocation.
- Fixed automatic migration of legacy session directories to new `-tmp-` prefixed naming scheme.
- Updated all test fixtures to pass both `cwd` and `sessionDir` parameters to `SessionManager.create()`.
- Schedule auto-removal of completed/abandoned tasks after ~1 minute delay
- Strip already-done tasks when restoring session from branch history
- Add todo_auto_clear event to trigger UI refresh on removal
- Add blank line before Todos header for visual spacing
- Exposed `settings` instance in `CustomToolContext` for session-specific configuration access.
- Improved artifact spill configuration to use session settings with schema defaults as fallback.
- Refactored type annotations and removed Required wrappers for better type safety in settings handling.
- Replaced AgentTool type with Tool type in tool registry for improved type consistency.
- Add compaction.thresholdTokens as fixed token limit alternative to percentage
- Token limit takes priority over percentage when set; options from 25K-500K
- Add more artifact spill threshold options (1KB-1MB) with size descriptions
- Add more artifact tail bytes/lines options with descriptions
- Clean up stale duplicate schema entries from tab reorganization
- Fix statusLine.separator UI metadata
Co-authored-by: Can Bölük <can1357@users.noreply.github.com>
Two /move bugs on Windows:
1. Quoted absolute paths (e.g. /move "C:\...") were treated as relative
because surrounding quotes weren't stripped before path.isAbsolute().
2. /move before any model response threw ENOENT because the session
.jsonl file hadn't been created on disk yet (lazy-persist).
Changes:
- Extract stripOuterDoubleQuotes() helper in path-utils.ts, use in
handleMoveCommand() with empty-after-strip guard
- Guard session file rename with existsSync in moveTo(), leaving
artifact dir rename independently guarded
- Guard #rewriteFile() with hadSessionFile || hasAssistant to preserve
lazy-persist while still updating header cwd for existing files
- Add comprehensive test suite (13 tests) covering all moveTo() edge
cases including header-only sessions, deferred persistence, and
artifact migration
* feat(utils): full XDG Base Directory support for all path helpers
Implement XDG-first resolution across all omp path helpers, extend the
migration command to cover every data/state/cache location, and fix
five data-safety issues found in review.
dirs.ts:
- Add getXdgCachePath() helper ($XDG_CACHE_HOME/omp/<subpath>)
- Add isDefaultAgentDir() helper: XDG lookup is only valid when the
resolved agentDir equals the process default (~/.omp/agent); custom
profiles set via PI_CODING_AGENT_DIR or setAgentDir() are never
silently redirected to the global XDG database
- Update 15 functions to XDG-first resolution:
data: getPluginsDir, getRemoteDir, getRemoteHostDir, getPythonEnvDir,
getWorktreeBaseDir
state: getReportsDir, getSshControlDir, getCrashLogPath, getDebugLogPath
cache: getPuppeteerDir, getGpuCachePath, getNativesDir
- Guard XDG lookup with isDefaultAgentDir(agentDir ?? getAgentDir()) in
all 9 agent-subdir helpers so that callers passing the global default
agentDir still resolve to the migrated XDG location, while callers
passing a non-default agentDir or running under a custom profile via
setAgentDir() bypass XDG entirely
- Plugin-derived helpers delegate to getPluginsDir() and follow XDG
resolution automatically
migrate-xdg.ts:
- Add getXdgCacheHome() helper
- Extend MigrationItem.category to include 'cache'
- Add 12 new migration entries: reports, plugins, remote, ssh-control,
remote-host, python-env, puppeteer, wt, gpu_cache.json, natives,
omp-crash.log, omp-debug.log
- Refuse to run when PI_CODING_AGENT_DIR points to a non-default
profile: migration only makes sense for the default ~/.omp/agent tree
- copyDirectory returns skipped source paths (target existed, non-force)
- verifyIntegrity: remove size-mismatch early-return that masked stale
targets as successful copies
- executeMigration: delete only entries that were actually copied;
use rmdir on source dir so it is removed only when empty, preserving
any skipped files for a subsequent --force run
- executeMigration: rename partial target to <target>.bak on integrity
failure instead of deleting; preserves pre-existing user data while
preventing getXdgDataPath from treating the partial tree as
authoritative; source remains intact for re-copy on next run
test isolation:
- Set XDG_DATA_HOME/XDG_STATE_HOME to non-existent paths in
memories-runtime.test.ts beforeEach/afterEach to prevent
getXdgDataPath/getXdgStatePath from resolving to real user data
* fix(utils,coding-agent): fix XDG support issues
dirs.ts:
- Refactor path resolution into DirResolver class. XDG base dirs are
resolved once at construction from env vars (Linux only, no
existsSync). setAgentDir creates a fresh instance, naturally
invalidating all cached paths and recomputing isDefaultProfile.
- getRootSubdir/agentSubdir accept optional XdgCategory parameter;
when set, the XDG base replaces the config root. Every accessor
is a one-liner delegate.
- Non-Linux platforms: XDG fields are null, zero overhead. No
filesystem probing, no string comparisons on the hot path.
- Config-only subdirs (themes, tools, commands, prompts, modules)
have no XDG category — they stay under the config root.
- Remove `import { env } from 'bun'`, use process.env consistently.
- Restore JSDoc comments to document actual defaults (~/.omp/...).
migrate-xdg.ts:
- Gate migrateToXdg on Linux — exits with clear error on other
platforms.
- Fix data loss bug: verifyIntegrity now accepts a Set of skipped
paths and skips verification for files that were intentionally not
copied (pre-existing at target in non-force mode).
- Fix nested directory source deletion: recursive removeSourceEntries
walks the tree and only deletes files not in the skipped set.
- Remove dead _sourcePath variable and unused force parameter from
verifyIntegrity.
- Remove `import { env } from 'bun'`, use process.env consistently.
logger.ts:
- Revert JSDoc to document ~/.omp/logs/ as default.
oauth.ts:
- Replace direct getAgentSubdir call with getTestAuthPath().
CHANGELOG.md:
- Merge duplicate section headers under [Unreleased].
- Add missing blank line before [13.11.1].
---------
Co-authored-by: can1357 <me@can.ac>
- Added per-rule `interruptMode` override capability to TTSR interrupt logic via optional frontmatter field.
- Changed interrupt behavior to respect per-rule `interruptMode` settings with fallback to global `ttsr.interruptMode` configuration.
- Extended `Rule` and `RuleConfig` interfaces with optional `interruptMode` property for granular control.
- Updated rule discovery to extract and validate `interruptMode` from frontmatter with proper enum type checking.
- Changed abort() method signature to return Promise<void> instead of void, making it async-compatible.
- Added bash executor fallback to one-shot shell execution when persistent sessions fail to respond to cancellation.
- Fixed bash execution timeout handling to prevent subsequent commands from hanging after hard timeouts.
- Extracted abort token management into ShellAbortState for thread-safe cancellation handling across shell sessions.
- Added SessionManager.close() method for proper cleanup of persistent writers and session resources.
- Added `close()` method to SessionManager and AuthStorage for proper resource cleanup and finalization of prepared statements.
- Added `initiatorOverride` option support in OpenAI and Anthropic providers for message attribution control.
- Fixed resource leaks in RpcClient timeout handling by centralizing timeout creation with unref() and adding explicit clearTimeout() calls.
- Fixed AgentSession disposal to call SessionManager's `close()` method for guaranteed resource cleanup instead of fallback flush.
- Updated all test suites to properly dispose AuthStorage instances in cleanup hooks to prevent resource leaks between tests.
Three early-return paths in #runAutoCompaction emitted auto_compaction_end
with result=undefined, aborted=false, and no errorMessage when compaction
was legitimately not needed (no model selected, no candidate models
available, or nothing to compact yet). The event-controller had no way to
distinguish these benign skips from a genuine failure, and fell through to
show the warning:
'Auto context-full maintenance failed; continuing without maintenance'
This was visible after a successful compaction: the next threshold check
would find nothing new to compact (prepareCompaction returns null), emit a
soft-skip event, and trigger the false warning.
Add skipped?: boolean to the auto_compaction_end event type and set it on
the three soft-skip paths. Update the event-controller to treat skipped
events as silent no-ops. Propagate the field through the extension and
hook AutoCompactionEndEvent interfaces so extensions can observe the
distinction.
- Simplified TruncationResult interface by making maxLines, maxBytes, and other derived fields optional, reducing redundancy.
- Refactored noTruncResult helper to auto-compute totalLines and totalBytes, eliminating repetitive parameter passing.
- Removed truncatedBy null checks and conditional formatting logic in truncation notice functions for cleaner output.
- Consolidated internal URL handling to use noTruncResult and removed unused displayMode variable.
- Clarified documentation in read.md to distinguish filesystem output from text output formatting.
- Changed eager todo reminder message role from 'developer' to 'custom' with customType field for better message categorization.
- Removed userRequest parameter from eager todo prelude generation to simplify prompt template rendering.
- Updated eager todo prompt to avoid redundant todo_write calls unless task state materially changed.
- Modified eager todo reminder message to use string content with display: false property instead of array format.
- Refactored eager todo injection from recursive prompt call to prepended message pattern.
- Removed state fields for todo injection tracking and consolidated logic into message composition.
- Added prependMessages option to promptWithMessage for composing messages before main prompt.
- Updated system prompt to require todo creation before substantive work on user requests.
- Fixed race condition where outer prompt would continue after user abort during eager todo's inner prompt by checking generation counter before proceeding.