From 6cf5b2539911c9d03d19ae8b608a84d1b3793327 Mon Sep 17 00:00:00 2001 From: can1357 Date: Fri, 24 Jul 2026 02:38:32 +0200 Subject: [PATCH] chore: update changelogs --- packages/agent/CHANGELOG.md | 10 +- packages/ai/CHANGELOG.md | 35 ++--- packages/catalog/CHANGELOG.md | 11 +- packages/coding-agent/CHANGELOG.md | 142 +++++------------- .../src/prompts/bench/cache-prefix-chunk.md | 2 +- packages/collab-web/CHANGELOG.md | 3 +- packages/snapcompact/CHANGELOG.md | 2 +- packages/stats/CHANGELOG.md | 2 +- packages/tui/CHANGELOG.md | 4 +- 9 files changed, 72 insertions(+), 139 deletions(-) diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index b331cac72..3504625ea 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -4,23 +4,23 @@ ### Added -- Classified Cloudflare AI Gateway `cf-aig-cache-status` into bounded `pi.gen_ai.gateway.response_cache.status` values (`hit` | `miss` | `bypass` | `unknown`) on chat spans, without mapping response replay to prompt-cache token attributes or recording arbitrary Cloudflare headers +- Added support for tracking Cloudflare AI Gateway cache status (hit, miss, bypass, unknown) on chat spans. ### Changed -- Queued steering no longer hard-aborts non-interruptible tools (e.g. `bash`): it aborts interruptible waits only and raises a cooperative steering signal (`ToolCallContext.steeringSignal`) that long-running tools may observe to finish early or background themselves. The mid-batch steering/IRC watch now runs for every tool batch instead of only batches containing an interruptible tool. +- Improved tool execution steering behavior: queued steering now cooperatively signals long-running, non-interruptible tools (via ToolCallContext.steeringSignal) to allow graceful early termination or backgrounding, rather than hard-aborting them. ### Fixed -- Fixed an unbounded allocation loop when a steer (or follow-up) was queued on a session with an empty transcript: `Agent.continue()` now delivers the queued message as the opening turn instead of throwing, so idle-drain callers no longer respin `continue()` on every microtask until OOM ([#6344](https://github.com/can1357/oh-my-pi/issues/6344)). -- Fixed provider-switched sessions being stranded without their remotely-compacted history: compaction now judges whether a prior OpenAI remote-compaction replay payload can be reused against the active model rather than the whole candidate set, so switching to a model that cannot replay the payload re-expands the originals into a portable local summary instead of leaving the model with only a placeholder ([#6343](https://github.com/can1357/oh-my-pi/issues/6343)). +- Fixed an out-of-memory (OOM) crash caused by an infinite loop when a steer or follow-up message was queued on an agent session with an empty transcript. +- Fixed an issue where switching providers or models on a session could lose compacted history; the agent now correctly falls back to a portable local summary if the new model cannot replay the prior provider's remote-compaction payload. +- Fixed a compaction failure with Anthropic models where serializing prior assistant reasoning inside tags triggered reasoning_extraction refusals. ## [17.0.8] - 2026-07-22 ### Fixed - Improved resilience against transient stream JSON parse failures by recovering completed tool calls while safely preventing incomplete, unknown, refused, or sensitive calls from executing. -- Fixed compaction/summarization serializing prior assistant reasoning back to Claude as text (rendered verbatim inside `` tags for the `anthropic` dialect), which tripped Anthropic's `reasoning_extraction` refusal and blocked compaction on Fable 5 sessions; `serializeConversation` now drops `thinking` blocks for Anthropic-dialect summary targets while other dialects (e.g. Harmony) keep their native reasoning ([#6093](https://github.com/can1357/oh-my-pi/issues/6093)). ## [17.0.5] - 2026-07-18 diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index e1a4134cf..fe8defe4b 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -4,28 +4,25 @@ ### Added -- Added caller-owned `cachedContent` on `google-generative-ai` and `google-vertex` GenerateContent options: pass an opaque cache resource name through the shared builder (blank values rejected); no create/refresh/delete lifecycle and no guessed model/project/location validation; existing `cachedContentTokenCount` → `Usage.cacheRead` normalization is unchanged. -- Added Anthropic extra-usage reporting across `omp usage`, interactive `/usage`, and ACP `/usage`: the OAuth usage endpoint's authoritative `spend` payload (or legacy `extra_usage` fallback when absent) is normalized into a `Claude Extra Usage` USD row; capped accounts show limit/remaining/fractions and status, while uncapped spend exposes only its absolute used amount—rendered as `$… used` in CLI/TUI and `123.45 usd used` in ACP—without a fabricated cap, percentage, or status. ([#5575](https://github.com/can1357/oh-my-pi/issues/5575)) -- Added process-scoped OAuth account pools for trusted auth-broker clients via `OMP_AUTH_BROKER_ACCOUNT_POOL_FILE`, consistently filtering snapshots, streaming updates, refreshes, and usage reports to selected OAuth identities while leaving API-key credentials and the shared encrypted snapshot cache unrestricted. -- Added opt-in Vercel AI Gateway automatic prompt caching for OpenAI Chat Completions while preserving `only` and `order` routing preferences. -- Added Vercel AI Gateway Responses cache anchors and cache lifetimes, emitted only with automatic caching. -- Added opt-in OpenAI GPT-5.6 explicit prompt-cache controls for Responses and Chat Completions. Existing requests remain implicit; the policy marks at most one existing stable-history block and is rejected locally on unsupported explicit routes. -- Forwarded `statefulResponses` through `streamSimple`, so diagnostic callers can explicitly disable OpenAI Responses `previous_response_id` chaining. -- Added native QwenCloud Token Plan API-key login, model discovery, and an optional interactive console-Cookie prompt for 5-hour and 7-day quota reporting ([#6151](https://github.com/can1357/oh-my-pi/issues/6151)). -- Added model-scoped usage health and same-provider reselection for native coding-plan credential pools, preserving OAuth/login-pool precedence, scoped broker blocks, sibling rotation state, and conservative unknown-account handling while excluding ordinary configured API keys ([#5018](https://github.com/can1357/oh-my-pi/issues/5018)). +- Added support for caller-owned `cachedContent` on Google Generative AI and Google Vertex AI `GenerateContent` options, allowing passing of opaque cache resource names. +- Added Anthropic extra-usage reporting across CLI, interactive, and ACP usage endpoints, normalizing the authoritative `spend` payload into a 'Claude Extra Usage' USD row with accurate limit, remaining, and status details. +- Added process-scoped OAuth account pools for trusted auth-broker clients via `OMP_AUTH_BROKER_ACCOUNT_POOL_FILE` to filter snapshots, updates, refreshes, and usage reports to selected OAuth identities. +- Added opt-in Vercel AI Gateway automatic prompt caching for OpenAI Chat Completions, including support for cache anchors and cache lifetimes. +- Added opt-in explicit prompt-cache controls for OpenAI GPT-5.6+ Responses and Chat Completions, supporting stable boundary selection, stateful Responses markers, and future GPT-5.x/6.x models. +- Added support for forwarding `statefulResponses` through `streamSimple` to allow diagnostic callers to explicitly disable OpenAI Responses `previous_response_id` chaining. +- Added native QwenCloud Token Plan support, including API-key login, model discovery, and an optional interactive console-Cookie prompt for quota reporting. +- Added interactive Meta Model API key login and support for `MODEL_API_KEY` and `META_API_KEY` environment variables. +- Added model-scoped usage health tracking and same-provider reselection for native coding-plan credential pools. ### Fixed -- Fixed Bedrock cache checkpoints to use resolved model compatibility: unsupported 1-hour retention now falls back to the provider-default 5-minute cache, bundled Nova Lite, Micro, Pro, and Premier requests—and Nova Premier's documented in-region model ID—emit AWS-recommended explicit checkpoints for cache savings, and forced opaque profiles remain conservative. -- Fixed OpenAI GPT-5.6+ explicit prompt-cache controls to select the latest stable boundary, preserve established stateful Responses markers (including no-system histories), and support later official GPT-5.x and GPT-6.x models. -- Fixed Bedrock cache checkpoints to use resolved model compatibility: unsupported 1-hour retention now falls back to the provider-default 5-minute cache, bundled Nova Lite, Micro, Pro, Premier, and Nova 2 Lite requests—including their documented in-region, regional, and global IDs—emit AWS-recommended explicit checkpoints for cache savings, configured checkpoint maxima are honored exactly (zero disables emission, one keeps the final-user boundary), and forced opaque profiles remain conservative. -- Fixed Pi-native and compatibility-wrapper requests dropping cache controls required by `omp bench --cache`, so benchmark pairs can disable OpenAI Responses chaining and preserve explicit prompt-cache affinity. -- Fixed outbound credential-pattern redaction (`[github_token_redacted]` & co.) running unconditionally: it is now opt-in via `configureCredentialRedaction` and disabled by default, so credential-shaped strings the user deliberately pastes reach the provider unmodified unless the host enables redaction. -- Added interactive Meta Model API key login and `MODEL_API_KEY` / `META_API_KEY` environment authentication ([#4941](https://github.com/can1357/oh-my-pi/issues/4941)). -- Fixed SuperGrok (`xai-oauth`) `/usage` showing "no usage data" for unified-billing accounts: when `?format=credits` lacks `creditUsagePercent` (or marks `isUnifiedBillingUser`), fall back to / merge the default monthly `monthlyLimit`/`used` payload. -- Fixed sessions wedging onto their fallback model with `400 Invalid \`signature\` in \`thinking\` block` after switching to an Anthropic signing endpoint while the latest assistant turn came from a different Anthropic-compatible provider (e.g. Kimi k3). The cross-model thinking-signature strip skipped the latest surviving assistant turn entirely, replaying the foreign signature verbatim on every attempt; the latest turn now strips signatures whose issuing provider differs from the target (same-provider switches keep their byte-for-byte latest turn), and foreign `redacted_thinking` siblings are dropped alongside instead of riding the wire unverifiable. -- Fixed OAuth callback servers aborting login when an invalid callback arrives before the legitimate browser redirect, and restricted `localhost` callback listeners to the IPv4 loopback interface ([#4106](https://github.com/can1357/oh-my-pi/issues/4106)). -- Fixed the Google Gemini CLI / Antigravity OAuth login hanging indefinitely (or ignoring ESC/cancel) during Cloud Code Assist project provisioning: `pollOperation` was an unbounded `while (true)` loop with bare `fetch` calls that never checked `OAuthController.signal`, passed no signal to `fetch`, and imposed no per-request timeout or attempt cap, so a stalled `done: false` operation or a hung fetch left login unrecoverable short of SIGKILL. The post-callback provisioning phase (token exchange, user-info, project discovery/onboarding, LRO polling) now threads the controller signal, applies a 30s per-request timeout via the new `oauthFetch` helper, checks cancellation before each poll, and bounds polling to 24 attempts — surfacing a `LoginCancelledError` on cancel and an `OAuthError` (`kind: "timeout"`) on a stall instead of spinning forever ([#4085](https://github.com/can1357/oh-my-pi/issues/4085)). +- Fixed AWS Bedrock cache checkpoints to use resolved model compatibility, falling back to the provider-default 5-minute cache for unsupported 1-hour retentions, emitting AWS-recommended explicit checkpoints for Nova models (Lite, Micro, Pro, Premier, Nova 2 Lite), and honoring configured checkpoint maxima. +- Fixed Pi-native and compatibility-wrapper requests dropping cache controls required by `omp bench --cache` to preserve explicit prompt-cache affinity and allow disabling OpenAI Responses chaining. +- Fixed outbound credential-pattern redaction running unconditionally; it is now opt-in via `configureCredentialRedaction` and disabled by default. +- Fixed SuperGrok (`xai-oauth`) `/usage` reporting for unified-billing accounts by falling back to the default monthly limit and usage payload when credit usage percentages are absent. +- Fixed sessions wedging with a `400 Invalid signature in thinking block` error when switching Anthropic-compatible providers by stripping signatures whose issuing provider differs from the target. +- Fixed OAuth callback servers aborting login on premature invalid callbacks, and restricted `localhost` callback listeners to the IPv4 loopback interface. +- Fixed Google Gemini CLI and Antigravity OAuth login hanging indefinitely during Cloud Code Assist project provisioning by introducing request timeouts, cancellation checks, and bounded polling. ## [17.0.9] - 2026-07-23 diff --git a/packages/catalog/CHANGELOG.md b/packages/catalog/CHANGELOG.md index 561230709..aefad0538 100644 --- a/packages/catalog/CHANGELOG.md +++ b/packages/catalog/CHANGELOG.md @@ -4,12 +4,11 @@ ### Added -- Added resolved Bedrock Converse prompt-cache compatibility limits, including explicit 5-minute checkpoint support for bundled Nova Lite, Micro, Pro, Premier, and Nova 2 Lite models plus their documented in-region, regional, and global IDs, and model-specific 1-hour Claude retention. -- Added the native Meta Model API provider and Muse Spark 1.1 with Responses API reasoning replay, image input, and the full supported reasoning-effort ladder ([#4941](https://github.com/can1357/oh-my-pi/issues/4941)). -- Added an opt-in Vercel AI Gateway automatic prompt-cache compatibility option alongside provider routing preferences. -- Added Vercel AI Gateway Responses cache-anchor and cache-lifetime compatibility controls. -- Added resolved OpenAI GPT-5.6 prompt-cache breakpoint capability metadata, keeping older models and compatible endpoints opt-in only. -- Added the native `alibaba-token-plan` provider with QwenCloud Token Plan Individual discovery and a curated chat-model fallback catalog ([#6151](https://github.com/can1357/oh-my-pi/issues/6151)). +- Added Bedrock Converse prompt-cache compatibility limits, including 5-minute checkpoint support for Nova models (Lite, Micro, Pro, Premier, Nova 2 Lite) and 1-hour Claude retention. +- Added native Meta Model API provider and Muse Spark 1.1 support, featuring Responses API reasoning replay, image input, and reasoning-effort controls. +- Added Vercel AI Gateway integration features, including opt-in automatic prompt-cache compatibility, provider routing preferences, and Responses cache-anchor and cache-lifetime controls. +- Added prompt-cache breakpoint capability metadata for OpenAI GPT-5.6, with opt-in support for older models and compatible endpoints. +- Added native alibaba-token-plan provider with QwenCloud Token Plan Individual discovery and a curated chat-model fallback catalog. ## [17.0.9] - 2026-07-23 diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 0797d927d..8fd616b79 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -4,116 +4,55 @@ ### Breaking Changes -- Replaced the `providers.webSearch` and `providers.image` single-preference enums with the `providers.webSearchOrder` and `providers.imageOrder` priority lists. Existing config values migrate automatically: a concrete legacy choice becomes the head of the new list with the remaining providers appended in their built-in order, and `auto` simply resets to the default chain. +- Replaced the `providers.webSearch` and `providers.image` single-preference configuration options with `providers.webSearchOrder` and `providers.imageOrder` priority lists. Existing configurations migrate automatically on startup. ### Added -- Added `error.notify` so failed model turns can emit distinct terminal/desktop notifications without changing completion notifications ([#2691](https://github.com/can1357/oh-my-pi/issues/2691)). -- Added `/live`, a Codex-authenticated realtime voice surface that streams microphone audio over WebRTC, routes coding work through the active agent session, and returns progress and final results to the voice model over the call's sideband channel. -- Added auto-following light and dark themes to HTML session exports, with a `/export --themes` option to bundle the user's selected TUI themes. -- Added owner-routed async job delivery: every session (including subagents) registers its own delivery sink, so background bash/task results are injected into the owning agent's run instead of the first top-level session; deliveries whose owner is gone are dead-lettered with the result retained on the job row. -- Added `AsyncJobManager.registerDeliverySink` and `AsyncJobManager.waitForOwnerJobs` (with an `excludeSuppressed` filter for quiescence checks). -- Added background-on-steer for auto-backgrounded bash: an incoming user/peer message backgrounds the running command (instead of waiting it out or killing it) so the message is handled promptly. -- Added `friendlyName` support for hidden secrets so model-visible placeholders can carry sanitized semantic labels, content-derived hashes, and case hints while preserving exact deobfuscation ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Made the statusline `git` segment jj-aware: in a Jujutsu repo it shows the nearest bookmark (falling back to the short change-id) instead of git's `detached` label or nothing, and working-copy change counts come from jj where there is no `.git` to read ([#3582](https://github.com/can1357/oh-my-pi/issues/3582)) -- Added `block`/`unblock` todo operations and a `blocked` status for tasks waiting on external input; blocked tasks stay visible in the todo HUD and summary but are excluded from the incomplete-todo stop reminder, and an optional blocker note records what the task is waiting for. -- Added a toggle-list editor in `/settings` for array-of-enum settings: `providers.webSearchOrder` and `providers.imageOrder` (ordered — Enter/Space toggles, ←/→ nudges, 1-9 splices the hovered provider into that position) and `providers.webSearchExclude` now appear under Providers → Services instead of being config-file only. +- Added dynamic multi-root workspace context support, allowing users to manage multiple workspace directories mid-session via `/add-dir`, `/remove-dir`, and `/dirs` slash commands, or seed them at launch using the `--add-dir` CLI flag. +- Added `/live`, a Codex-authenticated real-time voice interface that streams microphone audio over WebRTC and routes coding tasks through the active agent session. +- Added opt-in usage-aware model fallback for rationed coding plans, including a `/usage` command to view live quantitative usage data and automatic fallback chain traversal. +- Added `error.notify` configuration to allow failed model turns to trigger distinct terminal or desktop notifications. +- Added auto-following light and dark themes to HTML session exports, with a `/export --themes` option to bundle selected TUI themes. +- Added owner-routed asynchronous job delivery, ensuring background bash and task results are injected directly into the owning subagent or agent session rather than the top-level session. +- Added background-on-steer capability for auto-backgrounded bash commands, allowing incoming user or peer messages to immediately background running commands. +- Added `friendlyName` support for hidden secrets, allowing model-visible placeholders to carry sanitized semantic labels, hashes, and case hints. +- Added support for Jujutsu (`jj`) repositories in the statusline `git` segment, displaying the nearest bookmark or change ID and retrieving working-copy change counts. +- Added `block` and `unblock` operations for tasks, introducing a `blocked` status for tasks waiting on external input to exclude them from incomplete-todo reminders. +- Added a toggle-list editor in `/settings` for managing array-of-enum settings like search and image provider orders. - Added `models.yml` Bedrock Converse prompt-cache capability overrides for bundled and opaque inference profiles. -- Documented Vibe mode (`/vibe`) in `docs/vibe-mode.md` and the `/fresh` provider-stream reset in the session-operations doc, and linked both from the README's new "Session controls" section ([#6440](https://github.com/can1357/oh-my-pi/issues/6440)). -- Added `getServiceTiers()` and `setServiceTier()` extension APIs for reading and changing the live per-family service tier used by subsequent session requests ([#5860](https://github.com/can1357/oh-my-pi/issues/5860)). -- Added opt-in `omp bench --cache` independent cold/warm prompt-cache pairs with stable-prefix controls, sequential-by-default execution, mechanism-specific provider proof, and privacy-safe JSON output; it rejects `openai-codex-responses`, whose WebSocket transport chains turns. -- Added `tools.xdevDocs` prompt-doc modes (`inline`, `builtins`, `catalog`) and the `tools.xdevInlineDevices` glob allowlist controlling which mounted `xd://` device docs are inlined into the system prompt; dynamic-device catalog summaries and mid-session mount notices are capped to one line, and changing the mode in `/settings` refreshes the active prompt ([#6063](https://github.com/can1357/oh-my-pi/issues/6063)). -- Added opt-in usage-aware model fallback for rationed coding plans: `/usage` lists every available model mapped to live quantitative usage data, same-provider account pools are reselected before model changes, interactive reserve crossings require confirmation, and noninteractive role/subagent selection walks existing fallback chains ([#5018](https://github.com/can1357/oh-my-pi/issues/5018)). +- Added `getServiceTiers()` and `setServiceTier()` extension APIs to read and modify the live per-family service tier for session requests. +- Added opt-in `omp bench --cache` for independent cold/warm prompt-cache benchmarking with stable-prefix controls. +- Added `tools.xdevDocs` prompt-doc modes and the `tools.xdevInlineDevices` glob allowlist to control which mounted device documentation is inlined into the system prompt. +- Added the opt-in `read.renderMarkdown` setting for formatted Markdown read previews. ### Changed -- Split the `AgentSession` implementation into focused session-domain controllers while preserving its public API and runtime behavior. -- Subagents now inherit `async.enabled` and `bash.autoBackground.enabled` from the parent instead of having both force-disabled. Subagent runs complete only after their own background jobs settle and the agent submits a `yield` that postdates every delivered result: a terminal yield with jobs still pending parks the run (recoverable turn stop) instead of completing it, async results are folded in as follow-up turns (with a one-time notice offering `hub` wait/cancel), a result delivered after a yield supersedes that yield and re-runs the yield reminder ladder, and a run that never refreshes a superseded yield fails with the stale payload preserved as salvage. Teardown cancels and awaits surviving jobs before isolation worktree capture and cleanup. -- Added ordered `bash.patterns` command approval rules so selected bash commands can be allowed, prompted, or denied by command pattern. -- Cache full-session retention transcript incrementally instead of re-formatting the entire message history on every retain cycle ([#4246](https://github.com/can1357/oh-my-pi/issues/4246)) -- Bound interactive bash live display write queue to prevent unbounded PTY chunk backlog ([#4240](https://github.com/can1357/oh-my-pi/issues/4240)) -- All Markdown flavors (`.markdown`, `.mdx`, `.mdc`, `.mkd`, `.mdown`) now follow the `read.summarize.prose` setting like `.md`, so they read verbatim instead of being code-block summarized when prose summaries are off. -- xAI web search now uses `grok-4.5` (at low reasoning effort) instead of `grok-4.3`. -- Unified startup and runtime retry-fallback selector resolution, so deferred model roles honor the same exact-model, longest-wildcard, role, and default-chain precedence before session creation ([#5018](https://github.com/can1357/oh-my-pi/issues/5018)). +- Updated subagent behavior to inherit `async.enabled` and `bash.autoBackground.enabled` from parent sessions, and refined subagent run completion to wait for background jobs to settle. +- Added ordered `bash.patterns` command approval rules to allow, prompt, or deny bash commands by pattern. +- Updated Markdown file handling so all Markdown flavors (`.markdown`, `.mdx`, `.mdc`, etc.) respect the `read.summarize.prose` setting. +- Upgraded xAI web search to use `grok-4.5` at low reasoning effort instead of `grok-4.3`. +- Improved search provider resilience by cascading and falling back through other configured search providers when the preferred provider fails. +- Extended the bash tool's `direnv` and `devenv` auto-loading to all backends (including the ACP client terminal and interactive PTY) while honoring `direnv`'s local allow list. ### Fixed -- Fixed `models.yml` compatibility validation accepting invalid OpenAI-specific values through the Bedrock schema branch. -- Pinned displaceable transcript snapshots (`hub` waiting polls and live `todo` lists) to the viewport like the `vibe_wait` wall: when the transcript outgrows the terminal, their still-mutating rows are no longer committed to native scrollback on every spinner tick, which previously spammed hundreds of duplicated "waiting on N jobs" rows and force-sealed the poll so follow-up polls stacked instead of replacing it. -- Fixed legacy pi extensions failing to load on npm/source-link installs when their module graph contained a transitive CommonJS dependency (`Missing graph-owned CommonJS definition`). The `@(scope)/pi-coding-agent` root shim is served from `src/` on source-link installs, so an extension's import evaluated a second instance of `legacy-pi-compat.ts` whose top-level global registration clobbered the host bundle's populated CommonJS graph bridge with empty state; the registration is now first-wins so the host bridge survives ([#6449](https://github.com/can1357/oh-my-pi/issues/6449)). -- Fixed `omp auth-gateway serve` and `omp auth-gateway check` bypassing the process-scoped OAuth account pool configured by `OMP_AUTH_BROKER_ACCOUNT_POOL_FILE`. -- Fixed a first-use race in `ArtifactManager` where two concurrent `allocatePath`/`save` callers on a fresh instance both re-seeded `#nextId` across the directory-scan yield and allocated the same artifact id, silently overwriting the first artifact (same tool type) or making `artifact://` resolution ambiguous (different tool types). The initial scan is now memoized as a single in-flight promise so all concurrent callers share one initialization and receive distinct ids ([#4091](https://github.com/can1357/oh-my-pi/issues/4091)). -- Fixed blob reference resolution passing unvalidated `blob:sha256:` suffixes into `path.join`, allowing a crafted ref (e.g. `blob:sha256:../../../etc/passwd`) in a persisted/shared session to escape the blob directory and read arbitrary files into resolved image history; `parseBlobRef` now rejects any suffix that is not a canonical 64-char lowercase hex hash, gating every resolution path ([#4088](https://github.com/can1357/oh-my-pi/issues/4088)). -- Fixed pressing Esc in the `/omfg` amendment input discarding the whole generated-rule flow; it now returns to the save destination selector with the candidate preserved. -- Preserved superseded compaction summaries, snapcompact archives, and OpenAI replacement history so branching or rewinding before a newer compaction rebuilds the original model context ([#4090](https://github.com/can1357/oh-my-pi/issues/4090)). -- Fixed the Linux socket-mode DAP launch (e.g. `dlv`) hanging forever when the unix socket connect failed: `connectSocket` now rejects on a `Bun.connect` error (ECONNREFUSED/ENOENT/EACCES) or when the connect stalls past the launch deadline, instead of leaving the awaiter pending and leaking the detached adapter ([#4087](https://github.com/can1357/oh-my-pi/issues/4087)). -- Fixed discarded `Settings` instances keeping debounced save timers and chained background saves armed; discarding an instance now cancels its pending writes so they cannot race a successor's file locks. -- Fixed startup status messages (warnings, errors, extension/tool errors, status lines) keeping the dark-mode color after auto-theme detection later switched the active theme to light — e.g. `dark-catppuccin`/`light-catppuccin` warnings rendered in Mocha yellow on the Latte background. Transient status presenters now resolve their color lazily at render time so a theme swap re-shapes them ([#6337](https://github.com/can1357/oh-my-pi/issues/6337)). -- Fixed MCP OAuth endpoint discovery and Smithery browser-login polling hanging indefinitely against an endpoint that accepts the TCP connection but never responds. `discoverOAuthEndpoints`/`fetchResourceMetadataScopes` now bound every metadata/well-known/authorization-server fetch with a per-request `AbortSignal.timeout`, and `pollSmitheryCliAuthSession` bounds each poll so the loop reaches its 5-minute deadline instead of stalling ([#4103](https://github.com/can1357/oh-my-pi/issues/4103)). -- Fixed bash internal-URL expansion skipping unquoted `skill://` (and other supported schemes) inside a legacy backtick command substitution nested directly in double quotes (e.g. ``echo "`cat skill://valid-skill/SKILL.md`"``); `isInsideShellQuote` now treats `` ` `` as an expansion-context boundary like `$()`, including `$()`/backtick nesting in either order, while single-quoted and escaped-backtick text stay literal ([#5645](https://github.com/can1357/oh-my-pi/issues/5645)). -- Fixed `omp say` playing no audio for a short single-segment clip on hosts where the first streaming backend (the bundled ffmpeg built without pulse/alsa output) spawns then exits nonzero: the pipe write succeeds before that death and `player.end()` has already closed the input, so neither the broken-pipe replay nor the early-exit handler advanced to `paplay`/`aplay`. `StreamingAudioPlayer` now retains the utterance PCM and, when the streaming backend exits nonzero, replays it through per-file playback so short clips still reach the speakers ([#5875](https://github.com/can1357/oh-my-pi/issues/5875)). -- Fixed mid-session `memory.backend` changes leaving runtime state, tools, listeners, and prompt context on different backends; Mnemopi clear/enqueue now rehydrate listeners, and legacy `memories.enabled` no longer activates the local pipeline after migration ([#5638](https://github.com/can1357/oh-my-pi/issues/5638)). -- Fixed Plan Review annotations being discarded on dismissal and limited to headings; review notes now persist per plan, feed Refine, and can target the top visible plan line. -- Fixed the approved plan reference being permanently suppressed when the first post-approval prompt bailed during setup: `#planReferenceSent` was set at message-construction time (before delivery), so a generation-bail, an `@`-mention read error, or a `before_agent_start` hook throw between build and `agent.prompt` left the flag set with nothing delivered and the retry skipped re-injection. The flag is now committed only when the plan-reference message is handed to `agent.prompt` ([#4094](https://github.com/can1357/oh-my-pi/issues/4094)). -- Fixed `/new`, handoffs, branching (`/branch`, `/btw`), and cross-session switches retaining staged preview resolve callbacks and per-session ACP `allow_always`/`reject_always` decisions from the previous session ([#4093](https://github.com/can1357/oh-my-pi/issues/4093)). -- Fixed ACP sessions silently dropping tools from MCP servers that finished connecting after `MCPManager`'s 250ms startup race window; the initial post-connect refresh and every later `onToolsChanged` follow-up now run through a single ordered queue, so late-arriving tools are still applied to the session. -- Fixed mixed-agent `task` batches launching valid siblings when any item failed agent preflight: all effective item policies now validate before job registration or synchronous execution, approval details show effective-agent counts, and the batch setting copy reflects the current per-item agent shape. -- Fixed `error.notify` raising a "Stopped with error" toast for provider failures while an auto-retry or async-delivery continuation was pending; the toast now waits for the true terminal settle. -- Fixed concurrent MCP config mutations losing updates and racing on a shared temp path: every `mcp.json` read-modify-write (add/update/remove server, disabled/force-enabled lists) is now serialized under a per-file lock, and each atomic write uses a unique temp file so overlapping writers no longer rename each other's `.tmp` out from under them (ENOENT or clobbered config) — reachable in-process via the fire-and-forget extensions-dashboard toggle and across processes on a shared `~/.omp/mcp.json` ([#4104](https://github.com/can1357/oh-my-pi/issues/4104)). -- Fixed transient provider stream stalls after tool calls failing to auto-retry even when every call already had a tool result, including synthetic `executed:false` results from OpenAI-completions stalls ([#6414](https://github.com/can1357/oh-my-pi/issues/6414)). -- Fixed terminal `yield` results racing post-turn maintenance, which could trigger an unnecessary automatic handoff or compaction. -- Fixed PDF image reads returning stale extractions after same-path content replacement and racing concurrent cold reads by binding each cache generation to immutable source bytes and coalescing extraction with independent caller cancellation. ([#6368](https://github.com/can1357/oh-my-pi/issues/6368)) -- Fixed direct edit calls failing with `File not found` for relative paths that `read` resolved to a unique nested workspace file. ([#6359](https://github.com/can1357/oh-my-pi/issues/6359)) -- Fixed concurrent dead-kernel replacement in persistent Python sessions starting multiple generations and orphaning the losing process; callers now share one generation-scoped replacement, while resets and disposal invalidate and drain stale replacements ([#6367](https://github.com/can1357/oh-my-pi/issues/6367)). -- Fixed Assistant-mode TTS playback aborting when an agent continued after a tool call or automatic follow-up in the same run; internal continuation boundaries now preserve queued speech, while a new user message still interrupts prior playback. ([#6375](https://github.com/can1357/oh-my-pi/issues/6375)) -- Fixed credential-shaped tokens (GitHub/GitLab/OpenAI/Anthropic key patterns) being redacted from outbound provider requests even with `secrets.enabled` off; the pattern redaction now follows the `secrets.enabled` ("Hide Secrets") setting like the secret obfuscator. -- Fixed a cancelled `lsp reload` reporting `Restarted ` while killing the server with no replacement: `reloadServer` swallowed `ToolAbortError`/tool timeout in both fallback `catch` blocks and fell through to `proc.kill()`. Cancellation and timeout now propagate; the rust-analyzer fallback only triggers on genuine method-not-found; and a wedged-connection teardown removes the client by identity and awaits confirmed process exit before claiming a restart (surfacing a truthful teardown error if the process outlives the kill). ([#6369](https://github.com/can1357/oh-my-pi/issues/6369)) -- Fixed Ctrl-clicking a wrapped OAuth authorization URL opening only the clicked row's truncated fragment by preserving the complete hyperlink target on every rendered row. -- Fixed used-only absolute usage amounts across output surfaces: CLI now renders `$123.45 used`; the TUI shows a neutral, width-bounded amount instead of a pending/dotted/account-count placeholder; and ACP preserves `123.45 usd used` while suppressing duplicate window suffixes such as `— extra`. ([#5575](https://github.com/can1357/oh-my-pi/issues/5575)) -- Fixed auto-compaction re-triggering the "Compaction freed too little context" warning on every resume when the branch's last entry was an over-threshold snapcompact archive: the dead-end rescue now rebuilds the trailing archive locally at a threshold-derived frame budget (superseding the stale frame payload) instead of pausing, since the elide/image tiers can never touch a compaction entry (#4786). -- Terminal title now reflects the agent run state in the separator between the `π` brand and the session name: animated spinner frames while the agent is working, `>` when the turn is over and it's your move, `!` while the agent is blocked on you (ask/approval prompt). Gated by the new `tui.titleState` setting (default on). ([#3587](https://github.com/can1357/oh-my-pi/issues/3587), [#4451](https://github.com/can1357/oh-my-pi/pull/4451) by [@mattwilkinsonn](https://github.com/mattwilkinsonn)) -- Fixed reversible secret placeholders sharing a case-folded hash base across ASCII case variants, which let a prompt-injected model synthesize a never-provider-visible sibling secret's keyed token by swapping the case hint (`#…:L#` → `#…:U#`) in a tool-call argument. Placeholder bases are now keyed on the exact secret value, so each casing variant gets an independent base and a synthesized sibling token deobfuscates to nothing on live provider/tool-call paths ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed an auto-collected environment secret that is also declared as a plain `mode: "replace"` entry with the same content still forcing creation of the persisted `secret-placeholder.key`. Replace mappings run before obfuscate mappings, so the value is one-way replaced and the obfuscate entry never emits a reversible placeholder; the key-need check now ignores such replace-shadowed obfuscate entries, so an effectively replace-only secret set no longer requires (or writes) the key file and no longer fails startup when the agent config dir is unwritable ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed a default `mode: "replace"` regex that matches every non-whitespace candidate (e.g. `\S{n}`) shipping the raw secret unchanged when its deterministic replacement collided with the secret value, since every alphanumeric/punctuation candidate still matched. The redaction search now falls back to same-length whitespace markers — a full space/tab run, then a single whitespace byte among non-whitespace filler (` AAAA`) — so `\S`-class patterns and ones that also match all-space/all-tab runs (e.g. `(?:\S{n}| {n}|\t{n})`) are redacted to a stable nonmatching value instead of leaking to the provider; a regex that matches every non-line-terminator stays in the existing `.`/`[\s\S]` sentinel-keeping case ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed the placeholder key-need check over-requiring the persisted `secret-placeholder.key` for an effectively non-placeholding `mode: "replace"` config when a later (shorter-content) replacement erases the placeholder content before the plain-obfuscate pass. Each replacement output is now tested in the form it survives the rest of the replace phase, and the obfuscate `content` it tiles into must also survive those later replacements — covering both a fragment a later replacement rewrites (`AA -> SEC` then `S -> X` turning every `SEC` into `XEC`) and surrounding passthrough bytes a later replacement rewrites (`AA -> SEC` forming `SEC`+`RET12`, then `R -> X` turning the freshly formed `SECRET12` into `SECXET12`). Such configs no longer create the key or fail startup in an unwritable agent config dir, while a fragment whose formed content genuinely survives still requires the key ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed an obfuscate-mode secret regex whose sub-threshold match straddles a previously generated `#…#` placeholder re-obfuscating across the token — corrupting reversible deobfuscation (e.g. a plain `SECRETUV` secret plus `[A-Z]{6}` turning `XXSECRETUVYY` into a single placeholder that restored as `XXSECRETUV`) and, on a re-obfuscation pass, rewriting the surrounding context into fresh placeholders so the `obfuscate()` fixed point and provider-visible history/prompt-cache prefixes drifted. The short-match guard now measures the regex's own match length in the placeholder-expanded scan view (not the rewritten source span) and runs before the placeholder-preservation branch, so a match shorter than `MIN_OBFUSCATE_SECRET_LEN` is skipped, surrounding literals round-trip intact, and re-obfuscation stays a fixed point ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed a secret regex whose match boundary falls inside a previously generated `#…#` placeholder's expanded value mishandling the cut. In obfuscate mode the boundary was snapped out to the whole token, so two such matches around one placeholder mapped to overlapping source ranges that clobbered on apply and dropped bytes from reversible deobfuscation (e.g. a plain `ABCDEFGH` secret plus `[A-Z]{8}` turned `YYBBABCDEFGHSECRETUV` into a placeholder that restored as `YYBBABCDEFGHETUV`, dropping `SECR`); in replace mode the same cut redacted only the bytes outside the snapped token with a deterministic scramble that drifted across re-obfuscation passes (`ZZgK#…#` → `ZZgZ#…#`). The regex scan now resumes just past the cut placeholder rather than consuming the straddled span, so the cut secret stays hidden as its existing placeholder, no bytes are lost, any trailing wholly-outside content (e.g. an adjacent 8-char run) is still obfuscated or redacted on its own, and re-obfuscation is a fixed point ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed a `mode: "replace"` regex that depends on surrounding context (lookbehind/lookahead/`\b`) leaking the raw matched value on alternating turns. The deterministic-replacement collision search tested candidate redactions in isolation, so for a pattern like `(?<=api=)[AZ]` it accepted `api=A` for `api=Z` (a bare `A` does not match the lookbehind) — but the next obfuscate pass re-matched `A` in context and redacted it back to `api=Z`, shipping the secret every other turn. Candidate redactions are now evaluated in their surrounding text, and the deterministic replacement itself is verified to be a fixed point in context (not just against the `Z`/`ZZ` sentinel), so context-sensitive replace regexes resolve to a value the pattern never re-matches in place ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed a multi-character `mode: "replace"` regex remainder (the bytes of a match outside a preserved `#…#` placeholder) drifting across an obfuscator restart, which invalidated provider prompt-cache prefixes even with a stable key. The remainder was redacted to a content-derived `ZZ`+hash marker that was only recognized as already-redacted within the generating session (via an in-memory set), so a fresh obfuscator reprocessing persisted text re-redacted it to a different value (`ZZPL#…#` → `ZZ7f#…#`). The remainder marker now derives from a keyed run of the per-install key and the remainder length, so any instance sharing the key reproduces it byte-identically (idempotent across restart) while staying unpredictable enough that raw sentinel-shaped bytes (`ZZZZ`) still differ from it and are redacted rather than passed through ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed a secret regex match that starts in outside text and ends inside a previously generated `#…#` placeholder's expanded value leaving an independently-matching outside prefix provider-visible. Resuming the scan past the cut placeholder skipped the whole straddling span, so a pattern like `[A-Z0-9]{8,12}` greedily spanning `SECRETUV` into an `ABCDEFGH` placeholder returned `SECRETUV#…#` even though `SECRETUV` satisfies the regex on its own. The cut handling now re-runs the regex bounded to just before the placeholder (full left context kept, so lookbehind still evaluates) and redacts the standalone prefix match — to its own reversible placeholder in obfuscate mode, or a one-way redaction in replace mode — while the cut secret stays as its existing placeholder. The replace-mode redaction's fixed point is verified against the placeholder-expanded view re-obfuscation actually scans, so it does not drift when the adjacent placeholder expands ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed a secret regex whose match straddles a previously generated `#…#` placeholder still rewriting short surrounding raw bytes the regex never needed, drifting the `obfuscate()` fixed point and provider-visible history/prompt-cache prefixes across re-obfuscation passes. When a greedy match (e.g. `[A-Z0-9]{8,12}`) reaches across a prior-call placeholder whose own value already satisfies the pattern, a trailing/leading raw chunk that does not independently match is now left verbatim instead of being rewritten on the next pass — in obfuscate mode the chunk was minted into a fresh placeholder (`…SECRETUV→#…#A`), and in default replace mode its deterministic scramble drifted (`…#…#ZZJ5sotJ` → `…#…#ZZpvsotJ`). Surrounding bytes are still redacted when the placeholder value alone cannot satisfy the regex (e.g. a required `api_key=` prefix) or when they independently match it ([#2465](https://github.com/can1357/oh-my-pi/issues/2465)). -- Fixed a secret regex match straddling a prior-call placeholder with independently-matching raw bytes on one or both sides leaking those bytes unredacted, in two ways. First, the spillover check concatenated the outside-placeholder chunks before testing whether they independently satisfy the regex, which erased the placeholder-token boundary between them — e.g. with `\b[A-Z]{8}\b|[A-Z]{17}` and a placeholder for `SECRETUV` flanked by prefix `ABCDEFGH` (matches on its own) and suffix `I` (does not), the concatenated `ABCDEFGHI` matched neither alternative, so `ABCDEFGH` was treated as spillover and left verbatim. Second, testing each chunk in isolation (an out-of-context substring) broke context-sensitive patterns — lookbehind, lookahead, and `\b` — that depend on bytes actually adjacent to the chunk in the source text but outside its own range: `(?<=api=)[0-9]{8}` over `api=12345678` plus a trailing placeholder failed when `12345678` was tested standalone, since the isolated slice has no `api=` immediately before it. Each outside chunk is now tested at its real position in the source text, so lookbehind/lookahead see the actual surrounding bytes while a match spanning into the placeholder itself still doesn't count as independent. -- Fixed a default (no custom `replacement`) `mode: "replace"` regex whose deterministic redaction has no same-length candidate able to escape the regex (a pathological match-everything config such as `[\s\S]{8}`) churning its marker across every re-obfuscation pass and across obfuscator restarts, drifting provider prompt-cache prefixes. The fallback kept the content-hash-derived replacement, which the regex itself re-matches on the next pass; since that replacement is hashed from its own bytes (not the original secret), each pass rehashed it into a different value. The fallback now reuses the same key+length-only marker already used for per-chunk remainder redactions, which depends on nothing but the per-install key and the value's length, so re-matching and re-redacting it always reproduces the identical marker. A config with only this kind of regex (no other entry needing a persisted key) now also gets a persisted placeholder key created/read for it, so the marker's key input itself stays stable across a process restart instead of falling back to a process-random key. -- Fixed `findNonMatchingReplacement` exhaustively enumerating every `90^length` candidate (up to 729,000 for a 3-character match) before falling back, when a default `mode: "replace"` regex of length <= 3 matches every candidate (e.g. `[\s\S]{3}`). Each such match could burn tens of milliseconds; a modest tool output could stall provider requests. All lengths now use the same bounded single-position-substitution search already used for longer values (O(length * 90) instead of O(90^length)). -- Fixed a bounded default-mode regex (e.g. `[A-Z]{9}`) whose greedy reach spans a placeholdered secret plus a short trailing raw chunk (or a second adjacent secret) leaving that chunk unredacted on the first `obfuscate()` call but sweeping it into a new placeholder starting from the second call, churning provider-visible history and prompt-cache prefixes. A cut-resolution resume point that landed exactly on the start of another already-generated placeholder handed it straight to a fresh regex attempt instead of skipping past it, so a leading run of secrets resolved differently depending on whether its first member was still raw text (this call is about to placeholder it) or was already a placeholder from a prior call. Resume points are now chained past every immediately-adjacent placeholder before a new match attempt, so both calls land on the same next scan position and agree on the same (conservative) redaction from the first pass onward. -- Fixed friendly-name secret placeholders (`#PREFIX_HASH:HINT#`) being forgeable: untrusted text could wrap a real secret's plaintext in a fabricated friendly-name prefix around a hash suffix borrowed from any OTHER already-obfuscated secret, and `obfuscate()` would treat the whole token — including the exposed secret literal standing in for the prefix — as already redacted, letting it reach the provider untouched. `obfuscate()` now refuses that friendly-name-independent alias fallback whenever the dropped prefix contains a configured secret's literal value, while still accepting a stale prefix left over from a friendly-name rename. -- Fixed the friendly-name placeholder forgery check above missing regex-discovered secrets (only statically configured plain secrets were checked), and a regex match's short-match guard undercounting its length when clamped to a wholly-outside prefix before an already-generated placeholder — a full-size match whose kept prefix was under the 8-byte floor was wrongly skipped as noise, leaving that prefix provider-visible. -- Fixed a configured secret's `friendlyName` being able to bake another live secret's literal value straight into every placeholder minted for it (e.g. `{ content: "ABCDEFGH", friendlyName: "LEAKTOKEN" }` alongside a secret covering `LEAKTOKEN`), which then read as an already-generated placeholder on an exact match and was never scanned. `obfuscate()` now drops the friendly-name prefix for a given secret whenever the sanitized name contains a configured plain secret's literal or is matched by a configured regex, independent of `entries[]` order (regex patterns are now compiled before any placeholder is minted). -- Fixed a default (no custom `replacement`) `mode: "replace"` regex with no same-length candidate able to escape it (a pathological match-everything config such as `.`/`[\s\S]`) emitting a 1–2 byte matched value unchanged when it was exactly `Z` or `ZZ`: the fallback reused `#generateReplacement`'s shared `Z`/`ZZ` sentinel for such short values, and a raw match of exactly that sentinel round-tripped to the same bytes, reaching the provider unredacted (plain `mode: "replace"` secrets already avoided this via `ensureDistinctReplacement`, but the regex fallback did not). The fallback now uses a same-length, key-derived run instead of the sentinel for <=2 char values — still a fixed point under re-obfuscation (depends only on the per-install key and the value's length, never its content, so re-matching and re-redacting it reproduces the identical marker), but no longer a public, install-independent constant a regex config could be tuned to bypass. -- Fixed `getSecretPlaceholderKey()`/`getExistingSecretPlaceholderKey()` defaulting their `keyDir` parameter to `getConfigRootDir()` (`~/.omp`) while `createAgentSession()` always passes the profile-scoped `agentDir` (`~/.omp/agent`, per `docs/secrets.md`) explicitly. A caller relying on the default read or minted a key file at a different path than live sessions use, so placeholders it created were never stable against SDK sessions. Both helpers now default to `getAgentDir()`. -- Fixed a default (no custom `replacement`) `mode: "replace"` regex that cannot escape a 1–2 byte match (e.g. `.`, `[\s\S]`, `[\s\S]{2}`) still risking an unredacted round-trip: the previous key-derived same-length fallback marker was returned without checking it against the matched value, and since that marker is drawn from an alphabet the regex has already proven to match exhaustively, a real 1–2 byte secret that happened to equal it would ship to the provider unchanged. Such regex entries are now rejected outright — dropped with a warning when loaded from `secrets.yml`, dropped silently as a construction-time backstop otherwise — since no same-length marker can be guaranteed distinct from every possible match once the regex is proven to match every candidate in that alphabet. -- Fixed a plain secret's `friendlyName` being accepted as a placeholder prefix when it was a lowercase or punctuated variant of the secret's own value (e.g. `friendlyName: "github_pat_abc123"` for a secret of the same content): the collision check compared the already-sanitized (uppercased, alphanumeric-only) friendly name against the secret's raw, case-sensitive value, so a case/punctuation variant slipped through and stamped most of the secret into every placeholder (`#GITHUBPATABC123_…#`). The secret value is now sanitized the same way before the comparison. -- Fixed a regex-discovered secret's `friendlyName` collision check testing the already-sanitized (uppercased, separator-stripped) label against the configured regex instead of the label as written, so a case-sensitive or punctuated pattern (e.g. `tok_[a-z0-9]+`) missed a `friendlyName` that was itself a live match for that regex (e.g. `"tok_abc123"`), stamping the matched token — minus separators — into every placeholder (`#TOKABC123_…#`). The regex check now runs against the raw, pre-sanitization label, matching how the regex would actually encounter that text verbatim. -- Fixed the forged friendly-name-alias placeholder guard missing a case- or flag-variant occurrence of a regex-discovered secret: it only checked the dropped alias prefix against exact previously-discovered secret strings, so a differently-cased match of a case-insensitive pattern (e.g. `content: "tok[a-z0-9]+", flags: "i"` discovering lowercase `tokabc123`) never landed in the exact-match set under its uppercase form, letting a forged `#TOKABC123_#` be waved through as already-redacted and leave `TOKABC123` provider-visible. The guard now also tests the dropped prefix directly against every configured regex pattern. -- Fixed `secrets.yml`-loaded regex `friendlyName` entries pre-sanitizing the label before it reached `#friendlyNameCollidesWithSecret`'s raw-label regex check (the fix above), silently defeating it for every config-file-loaded entry — only entries constructed programmatically with a raw string were actually protected. The loader now preserves the original, unsanitized `friendlyName` string (still validating that it sanitizes to something non-empty), deferring sanitization to the obfuscator as before. -- Fixed the forged friendly-name-alias guard comparing a normalized (alnum-only, uppercased) dropped prefix against RAW plain-secret values, so a lowercase or punctuated configured secret's normalized rendering (e.g. `GITHUBPATABC123` for `github_pat_abc123`) slipped past both the obfuscate-direction guard and, more severely, an equivalent unguarded fallback in `deobfuscate()` — restoring a forged `#GITHUBPATABC123_#` straight to that OTHER secret's raw value on live provider-output/tool-call-argument paths, with no check at all. Both guards now normalize the compared secret values the same way before accepting the alias fallback, and `deobfuscate()` gained the same secret-shaped-prefix check `obfuscate()` already had. -- Fixed the friendly-name self-collision check comparing an already 32-char-capped, sanitized label against a configured secret's full sanitized value: a secret longer than the cap (or a label set to a long secret's value) could never have its full sanitized form contained in the truncated label, so the collision went undetected and the secret's first 32 sanitized characters were accepted and stamped into the placeholder. The check now runs against the full, uncapped sanitized label; the 32-char cap is applied only afterward, for display. -- Fixed a regex entry's `friendlyName` collision check testing the sanitized label only against the RAW spelling of what the regex would match, so a label set to the NORMALIZED (already uppercased, separator-stripped) rendering of a value the regex redacts — e.g. `friendlyName: "TOKABC123"` for `content: "tok_[a-z0-9]+"`, which discovers `tok_abc123` — slipped past a case-sensitive/punctuated pattern that can never match its own normalized form. The check now also compares the sanitized label directly against the sanitized value of the secret actually being minted (reusing `#prefixIsSecretShaped`), catching this on the secret's very first mint, before it's recorded as a previously-discovered value. -- Extended the bash tool's direnv/devenv auto-loading to every backend: the ACP client terminal and the interactive PTY now receive the repo's direnv environment (variables set, and `unset -v` for variables the `.envrc` removes) — previously only the one-shot `executeBash` path did — via a shared preflight so all backends behave identically, with the caller's explicit env still winning. direnv loading also always re-runs `direnv export json` instead of serving a content-hashed cache, so a change to a `watch_file` target re-exports even when the `.envrc` text is unchanged (direnv's own watch invalidation is authoritative). ([#4455](https://github.com/can1357/oh-my-pi/issues/4455)) -- The bash tool's direnv auto-load now honors direnv's own allow list: an `.envrc` the user has not `direnv allow`ed is skipped silently and never executed or auto-allowed, keeping OMP's trust boundary identical to the user's shell. ([#4455](https://github.com/can1357/oh-my-pi/issues/4455)) -- Fix ACP terminal hang/leak by bounding createTerminal and RPC awaits with abort/timeout and cleaning up late-resolving terminals ([#4241](https://github.com/can1357/oh-my-pi/issues/4241)) -- Added the opt-in `read.renderMarkdown` setting for formatted Markdown read previews, disabled by default. -- Fixed Markdown file read metadata so the opt-in Markdown preview renderer can recognize local and URI-backed Markdown files consistently. -- Fixed persisted vibe workers disappearing or being replaced across graceful restarts, session switches, failed mode exits, and late cancelled initialization: resumable conversations now restore safely, mode exit atomically commits worker tombstones with the mode change and rolls back cleanly on storage failure, explicit kills tear workers down monotonically while repairing uncertain append tails, killed transcripts remain readable but non-revivable, and stale initializers cannot overwrite newer same-ID workers ([#5303](https://github.com/can1357/oh-my-pi/issues/5303) by [@mastertyko](https://github.com/mastertyko)). -- Bounded vibe teardown so `vibe_kill` and Vibe-mode exit / session-switch suspension no longer hang when a cancelled turn's provider or tool ignores the abort signal: cancelled jobs get a short unref'd settlement grace, then detach while staying marked cancelled ([#5303](https://github.com/can1357/oh-my-pi/issues/5303) by [@RensTillmann](https://github.com/RensTillmann)). -- Fixed switching out of a Vibe-mode session clobbering the target session's active tools: mode reconciliation now strips only the transient vibe tools and preserves the freshly loaded target's tool set, instead of re-applying the source session's stale pre-vibe snapshot ([#5303](https://github.com/can1357/oh-my-pi/issues/5303)). -- Fixed restored Vibe workers resolving against the settings default model instead of the reopened session's active model: `#reconcileModeFromSession` now passes the session's active model string into rehydration so the `good` (`pi/task`) worker's inherited model tracks the resumed or switched-to session ([#5303](https://github.com/can1357/oh-my-pi/issues/5303)). - -### Removed - -- Added dynamic multi-root workspace context (issue [#2569](https://github.com/can1357/oh-my-pi/issues/2569)): a session now carries an ordered list of workspace directories beyond `cwd`, managed live from the terminal. New `/add-dir `, `/remove-dir `, and `/dirs` slash commands let you add and remove folders mid-session; the repeatable `--add-dir ` CLI flag seeds them at launch, and the `workspace.additionalDirectories` setting persists defaults per project. Additional roots are persisted in the session header, survive reopen/fork/move, and are surfaced to the agent in the system prompt so it knows they exist and can `read`/`grep`/`glob` them by absolute path. Design aligns with the endorsed community implementation on `feature/session-workspace`. -- Fixed the `browser` tool's `open` action ignoring the requested `timeout` during browser acquisition (CDP discovery/connect ran to its own fixed wait), and orphaning a freshly-created browser on abort/timeout before tab publication. The requested timeout now bounds the whole open lifecycle, and one explicit registry lease is held across tab acquisition so rollback disposes exactly the failed open — a concurrent open of a different tab name on the same browser can no longer dispose the browser out from under it. ([#6365](https://github.com/can1357/oh-my-pi/issues/6365)) -- Fixed `write` silently creating a stray zero-byte file or archive member when a read was mis-dispatched as a write: a local target that ends in a read-tool selector (e.g. `src/foo.tsx:1-260:raw`), does not exist, and carries empty content is now rejected with a message pointing at the equivalent `read(...)`. Non-empty content still deliberately creates selector-shaped names, and existing literal colon filenames or archive members stay writable. ([#6387](https://github.com/can1357/oh-my-pi/issues/6387)) +- Fixed a path traversal vulnerability in blob reference resolution by rejecting non-canonical hashes in `parseBlobRef`. +- Fixed multiple edge cases in the secret obfuscation and redaction engine, including handling of context-sensitive regexes, placeholder key requirements in unwritable directories, friendly-name forgery vulnerabilities, and regex match boundaries straddling existing placeholders. +- Fixed a first-use race condition in `ArtifactManager` where concurrent callers could allocate duplicate artifact IDs. +- Fixed Vibe-mode session stability, resolving issues with workers disappearing across restarts, hanging during teardown, clobbering target tools during session switches, and resolving against incorrect models. +- Fixed concurrent MCP configuration mutations losing updates by serializing read-modify-write operations under a per-file lock with atomic writes. +- Fixed legacy extensions failing to load on npm/source-link installs due to transitive CommonJS dependency graph clobbering. +- Fixed `omp auth-gateway` commands bypassing the process-scoped OAuth account pool configured via environment variables. +- Fixed terminal transcript rendering issues where displaceable snapshots (like waiting polls and todo lists) spammed native scrollback. +- Fixed the terminal title to reflect the active agent run state (working, waiting, or blocked) when `tui.titleState` is enabled. +- Fixed the `browser` tool's `open` action ignoring timeouts during browser acquisition and leaking orphaned browser instances. +- Fixed the `write` tool silently creating empty files when a read-tool selector was mis-dispatched as a write. +- Fixed snapcompact archiving reproducing assistant reasoning (`¶think:` sections) into replayed frames for Anthropic-dialect models. +- Fixed Linux socket-mode DAP launches hanging indefinitely on connection failures. +- Fixed Plan Review annotations being discarded on dismissal and limited to headings. +- Fixed Assistant-mode TTS playback aborting prematurely when an agent continued after a tool call. +- Fixed absolute usage amounts rendering inconsistently across CLI, TUI, and ACP output surfaces. +- Fixed MCP sessions dropping tools from servers that finished connecting after the initial startup window. ## [17.0.9] - 2026-07-23 @@ -238,7 +177,6 @@ - Changed every bundled TTSR rule to warn without interrupting generation. - Renamed the system prompt's project-context section wrapper from `` to `` to stop it colliding with the `task` tool's `context` parameter under in-band XML tool dialects: models were closing `` with a stray `` (primed by the ambient section tag) and emitting sibling params as bare `` elements, so `tasks` arrived missing. - Rendered `read xd://` calls in the compact grouped read view instead of a full tool-execution card; other internal URLs (`skill://`, `agent://`, …) still render full so their resolved content stays visible. -- Changed `providers.webSearch` preferred provider failure handling to fall back and cascade through other configured/default search providers rather than stopping immediately. ### Fixed @@ -327,14 +265,12 @@ - Fixed `autoResume` crossing an explicit `/new` boundary: after `/new` a new session's JSONL is created lazily (only once assistant output exists), so exiting before any assistant message left the per-terminal breadcrumb pointing at a not-yet-materialized file. `readTerminalBreadcrumbEntry` rejected the missing target and `continueRecent()` fell back to the most-recent session — the pre-`/new` transcript — processing the next prompt with stale context. `/new` now records a durable `fresh` breadcrumb boundary that `continueRecent()` honors (starting fresh) even when the target is absent, while a genuinely stale/deleted breadcrumb still falls back to the most-recent session ([#5730](https://github.com/can1357/oh-my-pi/issues/5730)). - Fixed subagents that repeatedly submit malformed `yield` results from leaving the parent waiting forever; malformed submissions now repeat the required response format, and repeated invalid submissions fail the child with a clear error. ([#4957](https://github.com/can1357/oh-my-pi/issues/4957)) - Fixed configured or `-e` extensions in compiled binaries failing to resolve bundled `@oh-my-pi/*` value imports through the `omp-legacy-pi-bundled:` registry, and surfaced extension load failures during interactive and `-p` session startup. ([#4954](https://github.com/can1357/oh-my-pi/issues/4954)) -- Fixed snapcompact archiving reproduced assistant reasoning (`¶think:` sections) into frames replayed to the model on every subsequent request, wedging Fable 5 sessions on `reasoning_extraction` refusals; snapcompact serialization now excludes reasoning when the session model uses the Anthropic dialect ([#6093](https://github.com/can1357/oh-my-pi/issues/6093)). ### Removed - Fixed the Cursor-backed advisor losing entire turns when it selected server-native tools (`bash`, `grep`, etc.) outside its grant: exec-resolved native blocks are already rejected in-band by the advisor-scoped bridge, so they no longer trip the unavailable-tool quarantine and discard the `advise` emitted in the same turn ([#5900](https://github.com/can1357/oh-my-pi/issues/5900)). - Fixed custom `anthropic-messages` OAuth providers being unable to opt into configured Claude Code fingerprint header overrides. ([#5888](https://github.com/can1357/oh-my-pi/issues/5888)) - Fixed authoritative providers (e.g. `openai-codex`) keeping unsupported bundled models selectable when a fresh model cache and an expired OAuth token coincided: built-in discovery now forces the OAuth refresh so the provider's model manager is constructed and prunes stale bundled entries (e.g. `gpt-5.4-nano`) instead of waiting out the cache TTL. ([#5364](https://github.com/can1357/oh-my-pi/issues/5364)) -- Added `providers.webSearchOrder` to prioritize web-search fallbacks while preserving the built-in order for unlisted providers; a failing preferred provider now continues through that fallback chain. ## [17.0.5] - 2026-07-18 diff --git a/packages/coding-agent/src/prompts/bench/cache-prefix-chunk.md b/packages/coding-agent/src/prompts/bench/cache-prefix-chunk.md index 9f53f8277..b29ec845d 100644 --- a/packages/coding-agent/src/prompts/bench/cache-prefix-chunk.md +++ b/packages/coding-agent/src/prompts/bench/cache-prefix-chunk.md @@ -1 +1 @@ -Prompt-cache benchmark stable prefix. \ No newline at end of file +Prompt-cache benchmark stable prefix. diff --git a/packages/collab-web/CHANGELOG.md b/packages/collab-web/CHANGELOG.md index cc030e546..b6193a3d9 100644 --- a/packages/collab-web/CHANGELOG.md +++ b/packages/collab-web/CHANGELOG.md @@ -4,7 +4,8 @@ ### Fixed -- Fixed `xd://resolve`/`xd://reject`/`xd://propose` cards losing action metadata after the xdev unwrap (badge rendered `?`/warn instead of apply/discard/propose semantics), and registered the missing `reject`/`propose` renderers plus the hub-family aliases (`irc`, `job`, `await`, `poll`, `cancel_job`) so those transcript names no longer fall back to generic JSON. ([#5640](https://github.com/can1357/oh-my-pi/issues/5640)) +- Fixed action metadata loss on xd://resolve, xd://reject, and xd://propose cards to ensure correct action badges are rendered. +- Added proper rendering support for reject, propose, and hub-family aliases (irc, job, await, poll, cancel_job) to prevent them from falling back to generic JSON. ## [17.0.8] - 2026-07-22 diff --git a/packages/snapcompact/CHANGELOG.md b/packages/snapcompact/CHANGELOG.md index 6777da3ef..94d5b0a8e 100644 --- a/packages/snapcompact/CHANGELOG.md +++ b/packages/snapcompact/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added -- Added an `includeThinking` serialize option (default `true`) so callers can exclude assistant reasoning (`¶think:` sections) from archived transcripts; used to keep reproduced reasoning out of frames replayed to Anthropic-dialect models ([#6093](https://github.com/can1357/oh-my-pi/issues/6093)). +- Added an `includeThinking` serialization option (defaulting to `true`) to allow excluding assistant reasoning (`¶think:` sections) from archived transcripts. ## [16.5.0] - 2026-07-13 diff --git a/packages/stats/CHANGELOG.md b/packages/stats/CHANGELOG.md index b5f132ea6..58ea16a69 100644 --- a/packages/stats/CHANGELOG.md +++ b/packages/stats/CHANGELOG.md @@ -4,7 +4,7 @@ ### Fixed -- Fixed malformed persisted content blocks aborting stats ingestion before later projects and settled pending full-session migrations after successful backfills ([#6373](https://github.com/can1357/oh-my-pi/issues/6373)). +- Fixed an issue where malformed persisted content blocks could abort stats ingestion for subsequent projects, and ensured pending full-session migrations are properly settled after successful backfills. ## [17.0.6] - 2026-07-20 diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 7aebf4c8a..1f16b2d79 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -4,11 +4,11 @@ ### Added -- `Text.setStyleFn()` applies a foreground styler at render time, so a component re-resolves its color after `invalidate()` instead of baking the palette that was active when it was constructed. +- Added Text.setStyleFn() to apply foreground stylers at render time, allowing components to dynamically re-resolve colors after invalidation instead of baking in the palette active at construction. ### Fixed -- Fixed teardown leaving the terminal in cursor-key/keypad application mode (DECCKM), which broke arrow keys in the parent shell after exit; `stop()` and `emergencyTerminalRestore()` now emit the standard `rmkx` resets ([#6374](https://github.com/can1357/oh-my-pi/issues/6374)). +- Fixed an issue where exiting or tearing down the TUI left the terminal in cursor-key/keypad application mode (DECCKM), which broke arrow keys in the parent shell. Both stop() and emergencyTerminalRestore() now correctly emit standard rmkx resets. ## [17.0.9] - 2026-07-23