- 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.
- Removed getTestAuthPath function and updated oauth test to construct path directly using getAgentDir and path.join.
- Refactored XDG directory resolution to validate paths exist before returning them, preventing invalid directory references.
- Extracted XDG resolution logic into a reusable resolveIf helper function for cleaner code.
* 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>
* fix(path): PI_CONFIG_DIR discovery
* refactor: centralize agent dir name into getConfigAgentDirName()
- Add getConfigAgentDirName() to utils/dirs.ts as single source of truth
- Replace duplicated "/agent" suffix construction in helpers.ts and config.ts
- Let biome format mcp/manager.ts canonically
---------
Co-authored-by: can1357 <me@can.ac>
- Extracted fetch mocking logic into reusable `hookFetch()` utility function with middleware-style handler pattern.
- Replaced manual `globalThis.fetch` assignment and restoration across 10 test files with `hookFetch()` calls using `using` statement for automatic cleanup.
- Implemented Disposable pattern with Symbol.dispose for fetch hook resource management, eliminating try-finally blocks.
- Exported `hookFetch` from utils public API to enable consistent fetch mocking across packages.
- Added Bun version validation at startup to enforce minimum version 1.3.7 for JSONL session parsing.
- Fixed `/resume` and `--resume` flags silently failing on older Bun runtimes by adding version check.
Fixes#277
- Added render_mermaid tool to convert Mermaid diagrams to ASCII output with configurable rendering options.
- Added renderMermaid.enabled setting to control availability of the render_mermaid tool.
- Changed Mermaid rendering from PNG terminal graphics to ASCII text format across theme and TUI components.
- Migrated mermaid utilities from pi-tui to pi-utils package with new ASCII rendering functions.
- Removed PNG-based mermaid rendering APIs (getMermaidImage, renderMermaidToPng) in favor of ASCII alternatives.
- Consolidated @oh-my-pi/pi-utils subpath imports into single package root import across 100+ files.
- Moved tryParseJson utility from local web scrapers module to @oh-my-pi/pi-utils package for centralized JSON parsing.
- Renamed loadSkillsFromDir to scanSkillsFromDir and refactored skill discovery to use fs.promises.readdir instead of glob-based approach.
- Replaced custom parseJSON with tryParseJson across discovery modules for consistent error handling.
- Removed emitCustomToolSessionEvent method and cleanupSshResources function, consolidating shutdown logic into dispose method.
- Updated glob pattern construction to use GlobBuilder with literal_separator(true) for improved path handling.
- Added fallback empty string for undefined tool descriptions across all AI providers to prevent runtime errors.
- Made `description` field required in CustomTool interface and normalized tool descriptions in agent-loop.
- Refactored tool normalization in agent-loop by renaming `injectIntentIntoTools()` to `normalizeTools()` with conditional intent injection.
- Added comprehensive description metadata to todo-write tool schema fields for improved clarity.
- Added a `display.tabWidth` setting to control default tab rendering.
- Integrated `.editorconfig` resolution for c ontext-aware tab indentation.
- Updated native text processing to use the resolved tab width for calculations.
- Improved tab visualization in diffs and other UI elements for consistency.
- Migrated timing instrumentation from custom utils/timings module to centralized logger.time() and logger.timeAsync() methods across coding-agent and natives packages.
- Removed PI_DEBUG_STARTUP environment variable and debugStartup() function, consolidating debug output to logger.debug() for conditional logging.
- Replaced custom TextDecoder buffer decoding with native toString('utf-8') method in natives package for simplified string conversion.
- Added RingBuffer<T> circular buffer implementation to pi-utils with comprehensive test coverage for efficient queue operations.
- Enhanced logger interface with time() and timeAsync() methods providing unified operation timing and performance tracking across packages.
- Added SSH host management feature with `ssh` CLI command and `/ssh` slash command for add, list, and remove operations.
- Added SSH configuration support at project (.omp/ssh.json) and user (~/.omp/agent/ssh.json) scopes with host discovery from project files.
- Added SSH host configuration flags: --host, --user, --port, --key, --desc, --compat, and --scope for flexible host setup.
- Removed automatic line relocation on stale hash references; now fails with error instead.
Puppeteer uses cosmiconfig to search for its configuration at import time. cosmiconfig walks up from CWD parsing every package.json it finds. If any package.json in the search path has invalid JSON, the strict parse-json parser throws synchronously
during module evaluation, surfacing as an uncaught exception that crashes the entire process.
- Added support for 11 new AI providers (Hugging Face, NVIDIA, Together, Ollama, LiteLLM, Xiaomi, Moonshot, Venice, Qwen Portal, vLLM, Cloudflare AI Gateway) with API key authentication and login flows.
- Implemented $pickenv() utility for environment variable fallback chains, enabling multi-key resolution for providers with alternative credential names.
- Extended KnownProvider and OAuthProvider types to include all 11 new providers with corresponding model manager functions and OAuth handlers.
- Expanded models.json with thousands of new model entries across all new providers and replaced deprecated opencode provider with cloudflare-ai-gateway.
- Refactored model generation script to use unified fetchProviderModelsFromCatalog() and centralized API key resolution for all providers.
- Exported `getTerminalId()` and `getTtyPath()` functions from tui package for obtaining stable terminal identifiers with support for TTY device paths and terminal multiplexers.
- Improved path display in status line to strip both `/work/` and `~/Projects/` prefixes when abbreviating paths.
- Refactored session directory naming to use single-dash format for home-relative paths and double-dash format for absolute paths, with automatic migration of legacy session directories on first access.
- Implemented TTY ID utilities in tui package with platform-specific TTY path resolution using /proc/self/fd/0 on Linux, dlopen on macOS/BSD, and libc on other Unix systems.
- Added macOS path standardization to strip `/private` prefix from paths when both original and stripped paths resolve to the same location.
- Added `sanitizeText` function to pi-natives that strips ANSI escape sequences, removes control characters and lone surrogates, and normalizes line endings.
- Moved `sanitizeText` function from `@oh-my-pi/pi-utils` to `@oh-my-pi/pi-natives` for better code organization and native performance.
- Added line length clamping (4000 characters) to bash and Python execution output to prevent excessively long lines.
- Replaced internal `#normalizeOutput` methods with `sanitizeText` utility function in bash and Python execution components.
- Fixed bash interactive tool to gracefully handle malformed output chunks by normalizing them with `sanitizeText`.
- Simplified documentation by removing WASM terminology from package descriptions and comments.
- Replaced all direct `process.cwd()` calls with `getProjectDir()` utility function across 40+ files to centralize project directory resolution logic.
- Added `getProjectDir()` and `setProjectDir()` functions to `@oh-my-pi/pi-utils/dirs` module to provide abstracted project directory management.
- Made `SessionManager.list()` method asynchronous to support asynchronous session discovery operations.
- Updated default working directory resolution throughout codebase to use `getProjectDir()` instead of `process.cwd()` for improved project directory detection.
- Refactored environment variable access to use dedicated getter/setter functions in test suite.
- Simplified configuration constants by removing ompConfig dependency and using hardcoded values.
- Introduced module-level caching for agent directory and subdirectory paths to improve performance.
- Added setAgentDir() function to manage agent directory updates and cache invalidation.
- Reorganized dirs.ts with logical section headers and consolidated subdirectory functions using helper utilities.
- Updated directory accessor functions to accept optional agentDir parameter for flexibility.
- Extracted directory path utilities from multiple packages into a centralized '@oh-my-pi/pi-utils/dirs' module.
- Moved 30+ path helper functions (getAgentDir, getConfigRootDir, getPluginsDir, getMCPConfigPath, etc.) from scattered locations into a single shared utility module.
- Consolidated APP_NAME, CONFIG_DIR_NAME, and VERSION constants into the centralized dirs module for reuse across packages.
- Updated 70+ import statements across packages/ai, packages/coding-agent, packages/stats, and packages/tui to use the new centralized module.
- Removed local path construction logic and replaced with utility function calls for improved maintainability and consistency.
- Deleted packages/coding-agent/src/extensibility/plugins/paths.ts as its functions were moved to the centralized dirs module.
- Added streaming functions `streamHashLinesFromUtf8` and `streamHashLinesFromLines` for processing large files with configurable chunking.
- Added `HashlineStreamOptions` interface to control streaming behavior with `startLine`, `maxChunkLines`, and `maxChunkBytes` options.
- Changed hashline format from 4-character to 2-character hex hashes for more compact output.
- Updated `computeLineHash` function to normalize whitespace and removed line number from hash seed for consistency.
- Improved CLI argument parsing with explicit handling of `--help`, `--version`, and subcommand detection.
- Removed `@types/diff` dev dependency as it is no longer needed.
- Created lightweight CLI framework in @oh-my-pi/pi-utils/cli as drop-in replacement for oclif with zero dependencies.
- Migrated coding-agent CLI from oclif framework to @oh-my-pi/pi-utils/cli with lazy command loading and simplified architecture.
- Changed default root command from 'index' to 'launch' for improved UX.
- Removed @oclif/core and @oclif/plugin-autocomplete dependencies from coding-agent package.
- Deleted custom oclif help renderer (oclif-help.ts) as help rendering is now integrated into the new CLI framework.
- Moved launch command from nested index/index.ts to top-level launch.ts for clearer command structure.
* + /mcp
- Reloads MCP manager in runtime state (no restart needed) and syncs with mcp.json.
- Handles OAuth discovery/auth flow automatically for auth-required servers.
- Validates server names and config shape before saving.
- Persists OAuth credentials in auth storage and links them to MCP config.
- Provides immediate connection checks and clear status messages.
- Supports enable/disable, reauth, and unauth flows that are easy to get wrong by hand.
* active agent tool registry runtime reload + token support for bearer auth http based transport
* +session rebind on succesful connection
* fix(coding-agent): address /mcp check failures
---------
Co-authored-by: can1357 <me@can.ac>
using declaration disposes synchronously after return evaluates the
promise expression but before it settles, killing the child process
and producing empty stdout. Adding await ensures the process completes
before Symbol.dispose fires.
- Removed createAbortablePromise function and inlined Promise.withResolvers usage in untilAborted for simpler abort handling.
- Replaced Bitmap class with simpler Uint8Array lookup table for whitespace detection in SSE parsing.
- Fixed subarray calculation in ConcatSink.pullJSONL to use correct read offset instead of computed remainder.
- Simplified copyWithin call in ConcatSink.pullJSONL to use read offset directly.
- Changed String.replace with regex to replaceAll for carriage return removal in sanitizeText.
- Removed unused test utilities and test cases for TextDecoderStream.
- Extracted stream abort handling into dedicated `createAbortableStream` utility function for reuse across stream operations.
- Refactored `sanitizeBinaryOutput` to handle surrogate pairs correctly and filter additional control characters (DEL and C1 control block) with lazy array allocation.
- Simplified JSONL parsing by replacing manual buffer management with new `pullJSONL` generator method in ConcatSink class.
- Removed unused `createSanitizerStream` and `createTextDecoderStream` helper functions that are no longer needed.
- Refactored `readSseJson` to use generator-based line processing with fast-path optimization for OpenAI-style done markers.
- Updated stdio transport to use new `readJsonl` utility instead of manual JSON parsing with TextDecoder.
- Extracted stream parsing utilities into reusable functions in pi-utils package (readLines, readJsonl, parseJsonlLenient, readSseJson).
- Replaced manual buffer management with ConcatSink class for efficient stream handling across multiple modules.
- Simplified SSE stream parsing in google-gemini-cli provider by using readSseJson utility instead of manual reader setup.
- Refactored MCP stdio transport to use readLines utility for cleaner line-based stream processing.
- Updated RPC client and mode to use readJsonl utility, removing duplicate JSONL parsing logic.
- Optimized buffer allocations by using allocUnsafe where data is immediately populated and reusing empty buffer instances.
- Refactored readSseJson abort handling to use pipeThrough with signal instead of manual event listeners, improving stream cancellation semantics.
- Replaced finally block with catch block to handle abort errors explicitly, preventing unnecessary cleanup operations.
- Reformatted test strings to use single quotes for consistency with project style guidelines.
- Removed unused isEnoent import and consolidated error code checking in dump-edit-history script.
- Fixed handling of aborted requests to properly throw abort errors when stream terminates without a terminal event.
- Fixed exit error handling in ChildProcess.wait() to properly capture exit reasons and non-zero exit codes.
- Fixed stdout text conversion in ChildProcess.wait() to use Response API for proper text decoding.
- Changed stderr handling API from `exposeStderr` boolean option to `stderr: "full" | null` enum-like option for clearer intent.
- Refactored ChildProcess constructor to accept stderr parameter directly instead of options object for simpler API.
- Refactored SSE stream parsing to use generic `readSseJson` utility instead of domain-specific handlers across multiple packages.
- Migrated from Node.js Buffer API to Web standard APIs (Uint8Array, TextDecoder, DataView) for cross-platform compatibility.
- Simplified stream transformation pipeline by consolidating multiple stream operations into unified `createTextLineSplitter` utility.
- Refactored `ptree.ts` to remove complex stream pumping infrastructure and simplify stderr handling with direct async iteration.
- Rewrote stream utilities to operate at binary level with byte-level parsing for improved efficiency and reduced string allocations.
- Updated TypeScript configuration to include DOM.AsyncIterable type definitions for async iterable DOM API support.
- Migrated all environment variable access from Node.js `process.env` to Bun runtime `Bun.env` API across the entire codebase.
- Updated 71 files including source code, tests, documentation, and configuration to use Bun's native environment variable API.
- Added comprehensive environment variables documentation in `packages/coding-agent/docs/environment-variables.md` covering 100+ environment variables organized by category.
- Updated CHANGELOG entries to reflect migration from `process.env` to `Bun.env` and environment variable prefix changes (PI_* vs OMP_*).
- Maintained identical behavior and logic across all changes - only the environment variable access method was updated.
- Added import of expandRoleAlias function from model-resolver module.
- Added role alias expansion step before parsing model strings in model resolution logic.
- Fixed u32 overflow in snowflake ID generation by keeping values in Number space instead of relying on bitwise operations that cause integer truncation.
- Simplified snowflake generation by replacing bigint arithmetic with 32-bit number operations and hex lookup table.
- Removed configurable epoch from Source constructor, using fixed EPOCH constant instead.
- Renamed Source.next() method to generate() and removed source parameter from module-level functions.
- Removed getMachineId() function which was unused in non-distributed snowflake implementation.
- Simplified getSequence() and getTimestamp() implementations to use direct hex parsing instead of bigint operations.
- Replaced nanoid and randomUUID with Snowflake ID generator across codebase for consistent distributed ID generation.
- Created new Snowflake utility module in packages/utils with support for 64-bit distributed ID generation with configurable epoch, machine ID, and sequence numbers.
- Updated session ID format documentation from nanoid to snowflake hex string format (16 hex characters).
- Removed nanoid dependency from package.json as it is now replaced by internal Snowflake implementation.
- Migrated environment variable access from function-based `getEnv()` API to object property-based `$env` API across 43 files in the monorepo.
- Simplified `packages/utils/src/env.ts` by removing scoped environment variable logic (EnvScope, getEnvMap, getEnv functions) and replacing with direct `process.env` reference exported as `$env`.
- Updated `packages/ai/src/stream.ts` to remove environment parameter from KeyResolver functions and use global `$env` object instead of passed-in env parameter.
- Migrated environment variable access from direct process.env to centralized getEnv() utility function across all packages.
- Renamed environment variable prefix from OMP_ to PI_ throughout codebase (e.g., OMP_CODING_AGENT_DIR -> PI_CODING_AGENT_DIR).
- Removed automatic environment variable migration from PI_ to OMP_ prefixes via migrate-env.ts module.
- Removed env setting from configuration schema and applyEnvironmentVariables() method from settings.
- Updated CI/CD build configuration to use PI_COMPILED flag instead of OMP_COMPILED.
- Changed venvPath property in PythonRuntime from nullable (string | null) to optional (string | undefined).
- Extracted environment variable parsing logic from multiple packages into centralized @oh-my-pi/pi-utils package.
- Moved getEnv, getEnvMap, and parseEnvFile functions from local implementations to shared pi-utils/src/env.ts module.
- Updated all imports across ai, coding-agent packages to use getEnv from @oh-my-pi/pi-utils instead of local definitions.
- Replaced direct process.env accesses in azure-openai-responses.ts and openai-responses.ts with centralized getEnv utility calls.
- Implemented EnvScope type and proxy-based environment variable merging to support multiple scopes (global, project, process) with dynamic process.env integration.
- Consolidated environment variable parsing and caching logic into single reusable module with improved testability and abstraction.
- Migrated from Node.js to Bun runtime by replacing @types/node with @types/bun and bun-types dependencies.
- Downgraded @types/diff from ^8.0.0 to ^7.0.2 in coding-agent package.
- Updated tsconfig.base.json to include DOM.AsyncIterable in lib configuration for async iterable DOM API support.
- Simplified stream handling in update-cli.ts by removing Readable.fromWeb() conversions and using response.body directly with pipeline().
- Simplified TextDecoderStream instantiation in stream.ts to use default parameters instead of explicit UTF-8 encoding configuration.
- Added defensive null/undefined handling in agent-loop.ts result assignment using nullish coalescing operator.
- Added session-based shell execution with persistent shell instances and session management via sessionKey parameter.
- Added support for shell snapshots to initialize bash sessions with saved state via snapshotPath parameter.
- Added sessionEnv option to set environment variables once per session, separate from command-specific env variables.
- Added process group management functions (process_group_id and kill_process_group) for better process lifecycle control on Linux, macOS, and Windows.
- Changed env option to apply variables for the current command only, with session-level variables now managed via sessionEnv.
- Refactored shell execution to use async output queuing with enqueueChunk for proper chunk sequencing and improved timeout handling with process group termination.