- Added `recoverOrphanedBackups` to promote `.jsonl..bak` files back to their primary path when the primary is missing, preventing data loss after a mid-rename crash.
- Changed backup filename from dot-prefixed to plain `..bak` so the shared `*.bak` glob can find it on both real and in-memory storage backends.
- Surfaced the original EPERM as the error `cause` and included both original and retry messages when rollback also fails.
Replaced overwrite-style session rewrites with an EPERM fallback that moves the old session file aside before retrying and restores it if the retry fails.
Added regression coverage for active-session rewrite recovery so the session remains writable after the fallback.
Fixes#1337
- Added sync truncation helpers to recursively prepare session entries and externalize image data.
- Reworked session persistence to use synchronous preparation plus `writeSync` with close-state checks.
- Added synchronous session-storage APIs and rerouted write paths to `writeLineSync`/`readTextSync`.
- Added `BlobStore.putSync`, migrated hashing to `Bun.SHA256`, and updated hash tests accordingly.
- Removed export leakage by demoting many helper and const symbols to module-local scope.
- Renamed underscore-prefixed internals and cache fields, then updated related references and `satisfies never` checks.
- Deleted obsolete logic branches and helpers, including harmony-stream interruption flow and unused benchmark runtime helpers.
- Updated Biome config and manifests by broadening lint coverage and removing an unused `@napi-rs/cli` dev dependency.
- Adjusted tests and utilities to use renamed test helpers and remove redundant private test-only helpers/locals.
- Added session-draft persistence methods in SessionManager to write unsent editor text to an artifacts-sidecar draft file and delete it after single-shot consumption.
- Persisted editor text during interactive shutdown and restored that draft on resume when the editor was empty, enabling Ctrl+D draft recovery.
- Updated Ctrl+D handling in the editor/controller path and added tests covering draft round-trip, artifact cleanup, stale-draft eviction, and in-memory no-op behavior.
buildSessionContext walked the entry path and unconditionally overwrote
models.default from every assistant message's reported model. Temporary
fallbacks (retry fallback, context promotion) and codex-side model
downgrades both produce assistant messages tagged with a different model
id, which clobbered the user's explicit /model pick on resume and made
the session silently revert to the older model.
Treat assistant-message inference as a legacy fallback that only fills
in models.default when no explicit `model_change` with role="default"
has been seen on the path.
Fixes#849
- Standardized missing-file read errors and now return `File not found: <path>` for absent edit targets.
- Centralized AI provider, usage, and OAuth helpers into shared modules to remove duplicated logic.
- Migrated OAuth/API-key login flows to shared factory helpers and removed inline prompt/token-exchange code.
- Reused shared tools and formatter utilities for discovery, stream tails, LSP batching, and source formatting.
- Consolidated repeated test helpers and fixtures into shared modules, replacing inline helper duplicates.
- Replaced Snowflake session IDs with UUIDv7 for created, forked, branched, and resumed sessions.
- Derived cache session IDs from OpenAI request options and passed them into Responses client creation.
- Used derived session IDs for OpenAI `session_id`/`x-client-request-id` headers and `prompt_cache_key`; omitted headers when retention was none.
- Added tests for UUIDv7 session creation/branching and OpenAI cache-affinity default, override, and disabled-header modes.
- Documented UUIDv7 session handling and OpenAI cache-routing fixes in package Unreleased changelogs.
- Fixed memory leak by cancelling idle compaction timer on event controller disposal.
- Fixed session resumption to preserve last non-empty session when starting fresh.
- Fixed stash detection to use git ref resolution instead of output parsing for reliability.
- Fixed secret obfuscation to deobfuscate restored session messages locally while keeping LLM messages obfuscated.
- Fixed stash pop operation to preserve staged changes with --index flag after task branch merges.
- Changed idle compaction settings from enum to numeric type for flexible configuration.
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
- 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.
- 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()`.
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
- Resolved symlinked paths before passing to brush shell to keep `pwd` output aligned with canonical Git worktree paths.
- Added `resolveShellCwd` helper that safely resolves symlinks and falls back to original path on error.
- Added test case verifying symlinked directories are canonicalized before execution.
- Added serviceTier option to OpenAI providers for controlling processing priority and cost across agent, completions, responses, and codex APIs.
- Added providerPayload field to messages for transport-native history reconstruction in OpenAI Responses and Codex APIs.
- Added /fast slash command and serviceTier setting to coding-agent for toggling OpenAI priority mode with fast mode indicator.
- Added remote compaction support with encrypted reasoning preservation for OpenAI models in coding-agent.
- Removed usage caching layer across all providers and refactored UsageFetchContext to eliminate cache and now dependencies.
- Fixed OpenAI Codex streaming service_tier inclusion, provider retry logic with exponential backoff, and email-based credential deduplication.
- Removed normativeRewrite setting and buildNormativeUpdateInput() function from public API.
- Removed $normative property and TNormative generic parameter from ToolResultMessage and AgentToolResult interfaces.
- Deleted normative.ts patch normalization module and related helper functions for diff anchor processing.
- Removed rewriteAssistantToolCallArgs() and #rewriteToolCallArgs() methods that modified tool call arguments.
- 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.
- Extracted tool choice mapping logic into dedicated utility module for provider-specific format conversions.
- Refactored task summary generation to use template-based rendering instead of string concatenation.
- Migrated system prompt generation to use Handlebars templates with structured data instead of hardcoded strings.
- Extracted JTD to TypeScript conversion logic into dedicated utility module for schema documentation.
- Consolidated prompt template rendering across multiple modules using unified renderPromptTemplate function.
- Simplified type assertions in stream module to use generic OptionsForApi type instead of provider-specific types.
- Removed Prettier configuration files (.prettierignore and .prettierrc) and migrated formatting to Biome.
- Updated Biome configuration from version 2.3.11 to 2.3.12 and changed arrowParentheses rule from 'always' to 'asNeeded'.
- Pinned @biomejs/biome dependency to exact version 2.3.12 in package.json and bun.lock.
- Applied consistent arrow function formatting across 489 files by removing unnecessary parentheses around single parameters.
- Removed blank lines after comment blocks and reorganized imports for consistency across the codebase.
- Converted named imports from node modules (fs, path, os) to namespace imports across all packages.
- Extended extension loader error handling with isEacces and hasFsCode type guards.
- Converted readdirSync, readFileSync, and statSync to async readdir, readFile, stat across skills and agent discovery.
- Made scanDirectoryForSkills async and refactored custom directory scanning to use Promise.all for concurrent processing.
- Updated agent discovery to use fs/promises for async file reading and refactored helper patterns.
- Added AgentParsingError exception class for better error handling during agent parsing.
- Added filesystem error type guards (isEnoent, isEacces, isPerm, etc.) to pi-utils for safe error checking.
- Added color manipulation utilities to pi-utils for accessibility features.
- Added color-blind mode setting to settings manager.
- Migrated plugins, settings, and config modules from sync to async file operations.
- Updated error handling to use new pi-utils type guards for type-safe checking.
- Added tsconfig.publish.json files to all packages with optimized publish-time configuration.
- Updated all package.json scripts with prepublishOnly hooks for correct type checking during publish.
- Added @oh-my-pi/omp-stats path mappings to root tsconfig.json for consistent imports.
- Added WASM generation script for photon module and integrated into install:dev script.
- converted relative imports to path aliases ($c/*, $ai/*, $tui/*, etc.) across all packages
- added per-package tsconfig.json with complete path mappings for runtime resolution
- set importModuleSpecifier to non-relative for IDE auto-import preferences
- updated dev script to run from monorepo root for consistent path resolution
- Added normative patch generation for canonicalizing edit tool output.
- Implemented tool call argument rewriting for session history persistence.
- Enhanced patch applicator to support normalized patch input processing.
- Updated agent and AI types to include normative input parameters.
- Removed tar-stream dependency and replaced with Bun.Archive for benchmark package.
- Added in-memory session storage abstraction with SessionStorage interface and MemorySessionStorage implementation.
- Added configurable bash interceptor rules with pattern-based command interception settings.
- Added AbortSignal support to 80+ web scrapers for request cancellation.
- Changed task tool to require explicit task `id` field and single `agent` parameter at top level.
- Removed `submit_review` tool - reviewers now use `complete` tool with structured output.
- Replaced Date.now() and crypto.randomUUID() with nanoid() for unique ID generation throughout codebase.
- Settings now use modelRoles map (e.g., { default: 'anthropic/claude-sonnet-4-5', small: 'anthropic/claude-haiku-4-5' })
- Session persistence uses 'provider/modelId' string format with optional role field
- Model selector: Enter sets default, S sets small, Escape closes
- Added role markers in selector: checkmark for default, lightning bolt for small
- Task tool supports pi/<role> aliases (e.g., model: pi/small, haiku, flash, mini)
- Title generation uses configured small model with auto-discovery fallback
- Explore agent now uses pi/small as primary model preference
- CustomAgentTool renamed to CustomTool
- ToolAPI renamed to CustomToolAPI
- ToolContext renamed to CustomToolContext
- ToolSessionEvent renamed to CustomToolSessionEvent
- Added CustomToolContext parameter to execute() and onSession()
- CustomToolFactory now returns CustomTool<any, any> for type compatibility
- dispose() replaced with onSession({ reason: 'shutdown' })
- Added wrapCustomTool() to convert CustomTool to AgentTool
- Session exposes setToolUIContext() instead of leaking internals
- Fix ToolExecutionComponent to sync with toolOutputExpanded state
- Update all custom tool examples for new API
- Add test/utilities.ts with shared helpers (API_KEY, userMsg, assistantMsg, createTestSession)
- Add agent-session-tree-navigation.test.ts with e2e tests for tree navigation
- Add getChildren() method to SessionManager
- Add summaryEntry to navigateTree return type
- Update existing tests to use shared utilities
- Check response.stopReason instead of catching errors for abort detection
- Return result object from _generateBranchSummary instead of throwing
- Fix summary attachment: attach to navigation target position, not old branch
- Support root-level summaries (parentId=null) in branchWithSummary
- Remove setTimeout hack for re-showing tree selector on abort
Major changes:
- Replace monolithic SessionEvent with reason discriminator with individual
event types: session_start, session_before_switch, session_switch,
session_before_new, session_new, session_before_branch, session_branch,
session_before_compact, session_compact, session_shutdown
- Each event has dedicated result type (SessionBeforeSwitchResult, etc.)
- HookHandler type now allows bare return statements (void in return type)
- HookAPI.on() has proper overloads for each event with correct typing
Additional fixes:
- AgentSession now always subscribes to agent in constructor (was only
subscribing when external subscribe() called, breaking internal handlers)
- Standardize on undefined over null throughout codebase
- HookUIContext methods return undefined instead of null
- SessionManager methods return undefined instead of null
- Simplify hook exports to 'export type * from types.js'
- Add detailed JSDoc for skipConversationRestore vs cancel
- Fix createBranchedSession to rebuild index in persist mode
- newSession() now returns the session file path
Updated all example hooks, tests, and emission sites to use new event types.