diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 29b9bd498..d51d90a59 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,13 +2,6 @@ ## [Unreleased] -### Fixed - -- Fixed aborted usage-limit recovery waiting on a local usage fetch or marking the resolved credential blocked after the caller had already moved to another session ([#6883](https://github.com/can1357/oh-my-pi/pull/6883) by [@paolomazzitti](https://github.com/paolomazzitti)). -- OpenAI Responses requests for Harmony-dialect models (gpt-5.x / openai-codex) now escape reserved Harmony control-token spellings (e.g. `<|channel|>analysis`) in untrusted user and tool-result text before serialization, so ordinary data — documentation, code, logs, or `omp://` grep results — can no longer trip the provider's `invalid_prompt` / "Request blocked" validator and permanently poison the session. Only the transport copy is escaped; the persisted transcript is byte-for-byte unchanged, and non-Harmony models are untouched. Extends the existing compaction-payload escaping to the live agent-loop request boundary ([#6913](https://github.com/can1357/oh-my-pi/issues/6913)). -- Fixed named forced `tool_choice` no longer being enforced on string-only OpenAI-compatible hosts (llama.cpp, LM Studio): the named object degrades to `"required"`, which alone lets the host call any advertised tool, so the request now narrows the advertised tools to the forced one (mirroring the Ollama chat transport). When the forced tool is absent the full tool list is kept and the choice is dropped for an unforced turn ([#6925](https://github.com/can1357/oh-my-pi/issues/6925)). -- Fixed direct Anthropic Claude Opus 5 requests failing with HTTP 400 when the endpoint rejected `strict` tool fields; the existing non-strict retry now recognizes `tools.N.custom.strict: Extra inputs are not permitted` responses ([#6976](https://github.com/can1357/oh-my-pi/issues/6976)). -- Fixed usage-based credential ranking treating a missing long-window metric as the short-window metric. Anthropic accounts whose 7-day bucket is not yet reported now keep the missing window neutral instead of letting 5-hour reset urgency shadow a sibling with reported weekly headroom ([#6980](https://github.com/can1357/oh-my-pi/pull/6980) by [@joswha](https://github.com/joswha)). ### Changed - Codex SSE requests to the official endpoint now use zstd-compressed bodies (level 3, `content-encoding: zstd`), matching the official Codex client; disable with `PI_CODEX_ZSTD=0`. Compression failures and HTTP 400/415 responses fall back to plain JSON, while custom Codex-compatible endpoints remain uncompressed. @@ -18,6 +11,16 @@ - Fixed bare `resource_exhausted` (the gRPC/Connect status name emitted by Cursor end-streams) classifying as `QUOTA_EXHAUSTED` in `parseRateLimitReason`, which pinned a 30-minute credential block and tripped the `retry.maxDelayMs` fail-fast at the session layer. Bare/opaque underscore status now matches the same `MODEL_CAPACITY_EXHAUSTED` branch as the space form (45–75s backoff), explicit quota details remain `QUOTA_EXHAUSTED`, and `USAGE_LIMIT_PATTERN` stays intact so stream-layer credential rotation is preserved. ([#7032](https://github.com/can1357/oh-my-pi/issues/7032)) - Fixed the Amazon Bedrock and Devin providers crashing when `Context.systemPrompt` is a bare string (as legacy `@earendil-works/pi-ai` extensions pass it), which surfaced as `stopReason: "error"` with `systemPrompt?.map is not a function`. Both providers now route through the existing `normalizeSystemPrompts()` helper like the other providers ([#7037](https://github.com/can1357/oh-my-pi/issues/7037)). +### Fixed + +- Fixed aborted usage-limit recovery waiting on a local usage fetch or marking the resolved credential blocked after the caller had already moved to another session ([#6883](https://github.com/can1357/oh-my-pi/pull/6883) by [@paolomazzitti](https://github.com/paolomazzitti)). +- OpenAI Responses requests for Harmony-dialect models (gpt-5.x / openai-codex) now escape reserved Harmony control-token spellings (e.g. `<|channel|>analysis`) in untrusted user and tool-result text before serialization, so ordinary data — documentation, code, logs, or `omp://` grep results — can no longer trip the provider's `invalid_prompt` / "Request blocked" validator and permanently poison the session. Only the transport copy is escaped; the persisted transcript is byte-for-byte unchanged, and non-Harmony models are untouched. Extends the existing compaction-payload escaping to the live agent-loop request boundary ([#6913](https://github.com/can1357/oh-my-pi/issues/6913)). +- Fixed named forced `tool_choice` no longer being enforced on string-only OpenAI-compatible hosts (llama.cpp, LM Studio): the named object degrades to `"required"`, which alone lets the host call any advertised tool, so the request now narrows the advertised tools to the forced one (mirroring the Ollama chat transport). When the forced tool is absent the full tool list is kept and the choice is dropped for an unforced turn ([#6925](https://github.com/can1357/oh-my-pi/issues/6925)). +- Fixed direct Anthropic Claude Opus 5 requests failing with HTTP 400 when the endpoint rejected `strict` tool fields; the existing non-strict retry now recognizes `tools.N.custom.strict: Extra inputs are not permitted` responses ([#6976](https://github.com/can1357/oh-my-pi/issues/6976)). +- Fixed usage-based credential ranking treating a missing long-window metric as the short-window metric. Anthropic accounts whose 7-day bucket is not yet reported now keep the missing window neutral instead of letting 5-hour reset urgency shadow a sibling with reported weekly headroom ([#6980](https://github.com/can1357/oh-my-pi/pull/6980) by [@joswha](https://github.com/joswha)). +- Fixed legacy Codex usage blocks continuing to gate every model after per-meter backoff shipped. SQLite schema 7 now splits the old `shared` scope into independent `chat` and `spark` blocks while preserving their expiry and age, then keeps a trigger-maintained physical `shared` mirror so pre-meter binaries that read the same database remain conservative after a rollback. Current store APIs expose only the meter scopes, while legacy direct `shared` writes fan back out to both meters. Broker clients negotiate meter-scoped snapshots with `OMP-Auth-Broker-Capabilities: codex-meter-block-scopes`; older clients receive a legacy `shared` wire projection, with `Vary` and a new encrypted-cache version keeping the representations separate. Active brokers now detect commits from legacy processes through SQLite's data version and advance snapshot generations, so long-poll and streaming clients receive those compatibility writes without reconnecting. +- Fixed legacy Codex usage blocks continuing to gate every model after per-meter backoff shipped. SQLite now splits the old `shared` scope into independent `chat` and `spark` blocks while preserving their expiry and age, and block reads keep a read-only fast path when no legacy row exists. Broker clients negotiate meter-scoped snapshots with `OMP-Auth-Broker-Capabilities: codex-meter-block-scopes`; older clients receive a legacy `shared` wire projection, with `Vary` and a new encrypted-cache version keeping the representations separate. + ## [17.1.8] - 2026-07-28 ### Fixed @@ -25,9 +28,6 @@ - Fixed an HTTP 400 error when resuming or replaying OpenAI history after an interrupted native Computer Use turn. - Fixed connection 404 errors when using Google Vertex AI in multi-region locations (eu and us) by correctly resolving regional endpoint (REP) hosts. - Fixed a resource leak in SqliteAuthCredentialStore.close() where unclosed prepared statements kept the SQLite connection alive, preventing database file cleanup (especially on Windows where files remained locked). -### Fixed - -- Fixed legacy Codex usage blocks continuing to gate every model after per-meter backoff shipped. SQLite schema 7 now splits the old `shared` scope into independent `chat` and `spark` blocks while preserving their expiry and age, then keeps a trigger-maintained physical `shared` mirror so pre-meter binaries that read the same database remain conservative after a rollback. Current store APIs expose only the meter scopes, while legacy direct `shared` writes fan back out to both meters. Broker clients negotiate meter-scoped snapshots with `OMP-Auth-Broker-Capabilities: codex-meter-block-scopes`; older clients receive a legacy `shared` wire projection, with `Vary` and a new encrypted-cache version keeping the representations separate. Active brokers now detect commits from legacy processes through SQLite's data version and advance snapshot generations, so long-poll and streaming clients receive those compatibility writes without reconnecting. ## [17.1.7] - 2026-07-27 @@ -53,9 +53,6 @@ - Kimi Code now sends its session-stable prompt cache key on both supported transports: `prompt_cache_key` for OpenAI-compatible requests and `metadata.user_id` for Anthropic-compatible requests. Explicit keys survive side-channel session IDs, while `cacheRetention: "none"` still disables automatic affinity ([#6049](https://github.com/can1357/oh-my-pi/issues/6049)). - Fresh encrypted auth-broker snapshot caches are revalidated within a short startup budget, so one-shot clients see newly imported or revoked credentials immediately when the broker is reachable while retaining cache fallback for transport and server failures. - Fixed custom `anthropic-messages` endpoints dropping native web-search call/result blocks in the leaked-thinking wrapper, preserving signed continuation history in source order without carrying a preceding text signature onto later unsigned blocks ([#6703](https://github.com/can1357/oh-my-pi/issues/6703)). -### Fixed - -- Fixed legacy Codex usage blocks continuing to gate every model after per-meter backoff shipped. SQLite now splits the old `shared` scope into independent `chat` and `spark` blocks while preserving their expiry and age, and block reads keep a read-only fast path when no legacy row exists. Broker clients negotiate meter-scoped snapshots with `OMP-Auth-Broker-Capabilities: codex-meter-block-scopes`; older clients receive a legacy `shared` wire projection, with `Vary` and a new encrypted-cache version keeping the representations separate. ## [17.1.4] - 2026-07-26 diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 5b360903b..e6c7b7556 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,25 @@ ## [Unreleased] +### Added + +- Added server-name autocomplete for `/mcp enable`, `disable`, `test`, `remove`, `reconnect`, `reauth`, and `unauth`, sourced from configured and runtime-discovered MCP servers ([#5654](https://github.com/can1357/oh-my-pi/issues/5654)). + +### Changed + +- Improved grouped read-call layout by nesting each request's usage metrics beneath its final path ([#6946](https://github.com/can1357/oh-my-pi/pull/6946) by [@joshrzemien](https://github.com/joshrzemien)). +- Fixed `/tan` agents being unable to read parent-session `local://` attachments (pasted files, generated references). `TanCommandController` now threads the parent session's `localProtocolOptions` into the tan clone, so `local://` resolves against `/local` instead of the clone-nested `/Tan-/local` root. Subagent local mappings now remain session-bound rather than replacing the process-global override used by active-session suggestions and links ([#6971](https://github.com/can1357/oh-my-pi/issues/6971)). +- Turn recovery now classifies a failed turn that already streamed visible (non-whitespace) assistant text as replay-unsafe, so credential rotation and model fallback no longer re-stream duplicated output. Thinking-only and whitespace-only partial turns remain retriable. +- Fixed Codex web search silently returning a plain model completion when a GPT-5.6 Responses-Lite model skipped the hosted `web_search` tool; the provider now requires a `web_search_call` event and advances to a searching model or fails clearly instead of accepting a non-search answer ([#6988](https://github.com/can1357/oh-my-pi/issues/6988)). +- Fixed the TUI collab guest never starting its loader when it joins or reconnects mid-turn: every host `state` frame now reconciles liveness in both directions ([#6996](https://github.com/can1357/oh-my-pi/pull/6996) by [@metaphorics](https://github.com/metaphorics)). +- Fixed random multi-second TUI freezes in reftable-format repos: status-line branch resolution moved off the render path onto the async-with-cache shape its siblings use, and synchronous git spawns gained a 5 s deadline ([#6997](https://github.com/can1357/oh-my-pi/pull/6997) by [@metaphorics](https://github.com/metaphorics)). +- Fixed xd:// device summaries reaching the system prompt with control characters intact and bounded only by character count, which let a multi-byte summary carry several times its intended budget; summaries are now stripped, bounded in UTF-8 bytes on a code point boundary, and the prompt states that dynamic device summaries are untrusted metadata. +- Fixed lowering task.softRequestBudget having no effect on bundled scout and sonic subagents, whose built-in budget previously replaced the configured value instead of acting as a ceiling. +- Reduced bash, grep, and glob tool guidance while preserving supported internal-URL routes and making shell/eval boundaries and broad-search timeout avoidance explicit. +- Fixed the spawn-based models config validator laziness test flaking under CPU contention by giving its two sequential probe processes an explicit 60s per-test timeout instead of sharing bun's 5s default ([#7018](https://github.com/can1357/oh-my-pi/issues/7018)). +- Coalesced the models configuration resource probe into one child process to avoid startup contention while preserving retained-resource coverage. +- Fixed quick LSP server exits being misreported as reader failures and explicit reloads being blocked by the initialization backoff ([#7041](https://github.com/can1357/oh-my-pi/issues/7041)). + ### Fixed - Force Git subprocesses to use the stable `C` message locale for predictable non-interactive command output. @@ -13,22 +32,8 @@ - Fixed `xd://` mount notices re-announcing already-known devices on session resume / host reconnect: the notice was diff-gated only against the in-memory mount set, which reset each resume, so reconnecting MCP/RPC-host devices re-spliced a redundant developer message into history and busted the provider prompt-cache prefix (re-billing the whole suffix at full price on metered providers). Notices now carry a structured `{ added, removed }` payload and are gated against the devices persisted history already announced—including legacy rendered notices from before the structured payload—so a resume that re-establishes the same inventory emits nothing. The announced baseline is reset when the transcript is replaced (`/new`, `switchSession`, `branch`), so a device reconnecting into the fresh history announces again ([#6921](https://github.com/can1357/oh-my-pi/issues/6921)). - Fixed the model picker showing an extension provider's placeholder model list instead of the credential-aware catalog it resolves at registration, so models the account actually has could be missing while unavailable ones stayed listed. - Fixed `edit`/`write` writes routed through the ACP client bridge (`fs/write_text_file`) trusting the requested content as "what's on disk" even when the client transforms it on save (e.g. Zed with `format_on_save: on` reformatting indentation the tool never touched). `routeWriteThroughBridge` now reads the file back after the bridge write and returns the verified content; `HashlineFilesystem.writeText` propagates it so the hashline snapshot tag matches the real file instead of the pre-write intent. Closes the reported "single-hunk `edit` call reformats the whole file" corruption, whose actual cause was every later edit resolving hunks against a stale snapshot the file had already drifted away from. -### Changed - -- Improved grouped read-call layout by nesting each request's usage metrics beneath its final path ([#6946](https://github.com/can1357/oh-my-pi/pull/6946) by [@joshrzemien](https://github.com/joshrzemien)). -- Fixed `/tan` agents being unable to read parent-session `local://` attachments (pasted files, generated references). `TanCommandController` now threads the parent session's `localProtocolOptions` into the tan clone, so `local://` resolves against `/local` instead of the clone-nested `/Tan-/local` root. Subagent local mappings now remain session-bound rather than replacing the process-global override used by active-session suggestions and links ([#6971](https://github.com/can1357/oh-my-pi/issues/6971)). -- Turn recovery now classifies a failed turn that already streamed visible (non-whitespace) assistant text as replay-unsafe, so credential rotation and model fallback no longer re-stream duplicated output. Thinking-only and whitespace-only partial turns remain retriable. -- Fixed Codex web search silently returning a plain model completion when a GPT-5.6 Responses-Lite model skipped the hosted `web_search` tool; the provider now requires a `web_search_call` event and advances to a searching model or fails clearly instead of accepting a non-search answer ([#6988](https://github.com/can1357/oh-my-pi/issues/6988)). -- Fixed the TUI collab guest never starting its loader when it joins or reconnects mid-turn: every host `state` frame now reconciles liveness in both directions ([#6996](https://github.com/can1357/oh-my-pi/pull/6996) by [@metaphorics](https://github.com/metaphorics)). -- Fixed random multi-second TUI freezes in reftable-format repos: status-line branch resolution moved off the render path onto the async-with-cache shape its siblings use, and synchronous git spawns gained a 5 s deadline ([#6997](https://github.com/can1357/oh-my-pi/pull/6997) by [@metaphorics](https://github.com/metaphorics)). -- Fixed xd:// device summaries reaching the system prompt with control characters intact and bounded only by character count, which let a multi-byte summary carry several times its intended budget; summaries are now stripped, bounded in UTF-8 bytes on a code point boundary, and the prompt states that dynamic device summaries are untrusted metadata. -- Fixed lowering task.softRequestBudget having no effect on bundled scout and sonic subagents, whose built-in budget previously replaced the configured value instead of acting as a ceiling. -### Changed - -- Reduced bash, grep, and glob tool guidance while preserving supported internal-URL routes and making shell/eval boundaries and broad-search timeout avoidance explicit. -- Fixed the spawn-based models config validator laziness test flaking under CPU contention by giving its two sequential probe processes an explicit 60s per-test timeout instead of sharing bun's 5s default ([#7018](https://github.com/can1357/oh-my-pi/issues/7018)). -- Coalesced the models configuration resource probe into one child process to avoid startup contention while preserving retained-resource coverage. -- Fixed quick LSP server exits being misreported as reader failures and explicit reloads being blocked by the initialization backoff ([#7041](https://github.com/can1357/oh-my-pi/issues/7041)). +- Fixed `omp ttsr test ` silently evaluating a supplied source file against the text (prose) context when its extension was absent from the hardcoded `SOURCE_FILE_EXT` allowlist, producing a false negative indistinguishable from a non-matching regex. It now emits an explanatory note (in text and `--json` output) when a resolvable file path infers `text`, pointing at `--source tool --tool edit`, and the allowlist gained the .NET family and other common source languages (`cs`, `razor`, `cshtml`, `fs`, `fsx`, `vb`, `sh`, `bash`, `sql`, `zig`, `dart`, `scala`, `ex`, `exs`, `proto`, `tf`) ([#6887](https://github.com/can1357/oh-my-pi/issues/6887)). +- Fixed automatic light/dark theme switching in direct WezTerm sessions on macOS when DEC Mode 2031 is unsupported. Native appearance notifications now repaint the auto theme immediately, while a bounded, front-loaded OSC 11 validation burst keeps the terminal background authoritative and reconciles fixed terminal themes only after an actual response. Persistent update notifications now resolve their warning, muted, and accent colors at render time so they also recolor when the active theme changes ([#6923](https://github.com/can1357/oh-my-pi/pull/6923) by [@Sairen777](https://github.com/Sairen777)). ## [17.1.8] - 2026-07-28 @@ -64,7 +69,6 @@ - Fixed omp worktree clear prematurely deleting active task-isolation sandboxes owned by running subagents. - Fixed /vibe mode preventing the director from completing parent tasks after verifying worker results by keeping the built-in todo tool active. - Fixed numeric GitHub issue and pull request autocomplete being suppressed inside skill slash-command arguments. -- Fixed `omp ttsr test ` silently evaluating a supplied source file against the text (prose) context when its extension was absent from the hardcoded `SOURCE_FILE_EXT` allowlist, producing a false negative indistinguishable from a non-matching regex. It now emits an explanatory note (in text and `--json` output) when a resolvable file path infers `text`, pointing at `--source tool --tool edit`, and the allowlist gained the .NET family and other common source languages (`cs`, `razor`, `cshtml`, `fs`, `fsx`, `vb`, `sh`, `bash`, `sql`, `zig`, `dart`, `scala`, `ex`, `exs`, `proto`, `tf`) ([#6887](https://github.com/can1357/oh-my-pi/issues/6887)). ## [17.1.7] - 2026-07-27 @@ -88,9 +92,6 @@ - `xd://` device docs now render the parameter schema as a comment-annotated TypeScript type (via `jsonSchemaToTypeScript`, the same renderer the in-band tool inventory uses) instead of a raw JSON Schema dump, shrinking system-prompt device sections while keeping descriptions inline. - Added a `/vision [on|off|auto|status]` slash command for session-scoped control of the `inspect_image` vision-delegation tool, modeled on `/computer`: `on`/`off` force the tool for the current session only, `auto` returns to the persisted setting, and `status` reports the effective mode, session override, tool state, and active-model image capability. - Replaced the `inspect_image.enabled` boolean with the tri-state `inspect_image.mode` (`auto`|`on`|`off`, default `auto`). In `auto` the tool is registered only when the active model lacks native image input, so vision-capable models (e.g. `kimi-code/k3`) read images inline with their own capabilities instead of delegating to a separate vision model; the tool set is re-evaluated on every model switch with a status notice when it flips. The `read` tool now follows the effective state dynamically rather than the raw setting, so it returns decoded image blocks again whenever `inspect_image` is hidden. Existing `inspect_image.enabled: true/false` configs migrate to `inspect_image.mode: on/off`. -### Fixed - -- Fixed automatic light/dark theme switching in direct WezTerm sessions on macOS when DEC Mode 2031 is unsupported. Native appearance notifications now repaint the auto theme immediately, while a bounded, front-loaded OSC 11 validation burst keeps the terminal background authoritative and reconciles fixed terminal themes only after an actual response. Persistent update notifications now resolve their warning, muted, and accent colors at render time so they also recolor when the active theme changes ([#6923](https://github.com/can1357/oh-my-pi/pull/6923) by [@Sairen777](https://github.com/Sairen777)). ## [17.1.6] - 2026-07-27 @@ -270,9 +271,6 @@ - Fixed spilled tool-output artifact descriptors leaking on error/abort paths. `OutputSink.dump()` was the only path that closed the spill `Bun.FileSink`, but the bash and Python executors re-throw on failure and their `finally` blocks never closed the sink, so a large-output command that errored leaked the artifact descriptor until an unrelated read (e.g. a `SKILL.md` load) hit `EMFILE`. `OutputSink` now exposes an idempotent `dispose()` that closes the sink exactly once, wired into every executor's `finally` ([#6463](https://github.com/can1357/oh-my-pi/issues/6463)). - Fixed the first submitted prompt stalling while the local tiny-title worker started: the interactive submit handler now paints the pending user row before starting title generation, and startup prewarms an idle, unref'd worker so the first submit reuses a live subprocess instead of paying spawn latency ahead of the first frame ([#6462](https://github.com/can1357/oh-my-pi/issues/6462)). - Fixed legacy Pi extensions failing validation when importing the upstream `keyText` keybinding helper ([#6470](https://github.com/can1357/oh-my-pi/issues/6470)). -### Added - -- Added server-name autocomplete for `/mcp enable`, `disable`, `test`, `remove`, `reconnect`, `reauth`, and `unauth`, sourced from configured and runtime-discovered MCP servers ([#5654](https://github.com/can1357/oh-my-pi/issues/5654)). ## [17.1.0] - 2026-07-24 diff --git a/packages/coding-agent/test/edit-acp-bridge.test.ts b/packages/coding-agent/test/edit-acp-bridge.test.ts index b5cc5cc22..83308426f 100644 --- a/packages/coding-agent/test/edit-acp-bridge.test.ts +++ b/packages/coding-agent/test/edit-acp-bridge.test.ts @@ -11,7 +11,7 @@ import { executeHashlineSingle, executePatchSingle, executeReplaceSingle, - hashlineEditParamsSchema, + type hashlineEditParamsSchema, } from "@oh-my-pi/pi-coding-agent/edit"; import { HashlineFilesystem } from "@oh-my-pi/pi-coding-agent/edit/hashline/filesystem"; import { resolveLocalUrlToPath } from "@oh-my-pi/pi-coding-agent/internal-urls"; @@ -76,7 +76,7 @@ function makeDriftingBridge() { const bridge: ClientBridge = { capabilities: { writeTextFile: true }, writeTextFile: async ({ path: p, content: c }) => { - await Bun.write(p, c.replace(/^ /gm, "\t")); + await Bun.write(p, c.replace(/^ {4}/gm, "\t")); }, }; const spy = spyOn(bridge, "writeTextFile"); @@ -316,9 +316,7 @@ describe("executeHashlineSingle model-visible payload under write-time drift", ( const relPath = "nb.ipynb"; const absPath = path.join(tmpDir, relPath); const notebook = { - cells: [ - { cell_type: "code", source: ["print('old')\n"], metadata: {}, outputs: [], execution_count: null }, - ], + cells: [{ cell_type: "code", source: ["print('old')\n"], metadata: {}, outputs: [], execution_count: null }], metadata: {}, nbformat: 4, nbformat_minor: 5, diff --git a/packages/coding-agent/test/extensibility/legacy-pi-cli-exports.test.ts b/packages/coding-agent/test/extensibility/legacy-pi-cli-exports.test.ts index 1969aecc5..50e32f803 100644 --- a/packages/coding-agent/test/extensibility/legacy-pi-cli-exports.test.ts +++ b/packages/coding-agent/test/extensibility/legacy-pi-cli-exports.test.ts @@ -1,8 +1,5 @@ import { describe, expect, it } from "bun:test"; -import { - CONFIG_DIR_NAME, - parseArgs, -} from "@oh-my-pi/pi-coding-agent/extensibility/legacy-pi-coding-agent-shim"; +import { CONFIG_DIR_NAME, parseArgs } from "@oh-my-pi/pi-coding-agent/extensibility/legacy-pi-coding-agent-shim"; describe("legacy shim CLI exports", () => { it("re-exports parseArgs and CONFIG_DIR_NAME from the legacy package root", () => { diff --git a/packages/coding-agent/test/tools/lsp-regressions.test.ts b/packages/coding-agent/test/tools/lsp-regressions.test.ts index 96b8d3924..e1db33d5b 100644 --- a/packages/coding-agent/test/tools/lsp-regressions.test.ts +++ b/packages/coding-agent/test/tools/lsp-regressions.test.ts @@ -16,7 +16,6 @@ import { sortAndValidateTextEdits, } from "@oh-my-pi/pi-coding-agent/lsp/edits"; import { renderCall, renderResult } from "@oh-my-pi/pi-coding-agent/lsp/render"; -import { renderResult as renderLocalResult } from "../../src/lsp/render"; import { type CodeAction, type CreateFile, @@ -51,6 +50,7 @@ import * as piUtils from "@oh-my-pi/pi-utils"; import { sanitizeText, TempDir } from "@oh-my-pi/pi-utils"; import type { Subprocess } from "bun"; import DEFAULTS from "../../src/lsp/defaults.json" with { type: "json" }; +import { renderResult as renderLocalResult } from "../../src/lsp/render"; import { getLanguageFromPath } from "../../src/utils/lang-from-path"; /** Minimal LSP tool session: production always supplies `settings`; these tests only need cwd + a default settings stub. */ diff --git a/packages/coding-agent/test/turn-recovery-replay-unsafe.test.ts b/packages/coding-agent/test/turn-recovery-replay-unsafe.test.ts index dd9c8bcd7..212a90aeb 100644 --- a/packages/coding-agent/test/turn-recovery-replay-unsafe.test.ts +++ b/packages/coding-agent/test/turn-recovery-replay-unsafe.test.ts @@ -1,7 +1,6 @@ import { afterAll, beforeAll, describe, expect, it } from "bun:test"; import type { AssistantMessage } from "@oh-my-pi/pi-ai"; import * as AIError from "@oh-my-pi/pi-ai/error"; -import { createProviderErrorMessage } from "../../ai/src/providers/error-message"; import { getBundledModel } from "@oh-my-pi/pi-catalog/models"; import type { Model, Usage } from "@oh-my-pi/pi-catalog/types"; import { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry"; @@ -13,6 +12,7 @@ import { type TurnRecoveryHost, } from "@oh-my-pi/pi-coding-agent/session/turn-recovery"; import { TempDir } from "@oh-my-pi/pi-utils"; +import { createProviderErrorMessage } from "../../ai/src/providers/error-message"; const USAGE: Usage = { input: 0, @@ -244,5 +244,4 @@ describe("TurnRecovery replay-unsafe output classification", () => { const message = createProviderErrorMessage(model, new Error("fetch failed")); expect(recovery.isRetryableError(message)).toBe(true); }); - }); diff --git a/packages/coding-agent/test/write-acp-fs.test.ts b/packages/coding-agent/test/write-acp-fs.test.ts index af4082688..fea4a3e3b 100644 --- a/packages/coding-agent/test/write-acp-fs.test.ts +++ b/packages/coding-agent/test/write-acp-fs.test.ts @@ -91,7 +91,7 @@ describe("write tool ACP fs routing", () => { const bridge: ClientBridge = { capabilities: { writeTextFile: true }, writeTextFile: async ({ path: target, content }) => { - await Bun.write(target, content.replace(/^ /gm, "\t")); + await Bun.write(target, content.replace(/^ {4}/gm, "\t")); }, }; const session = createSession(tmpDir, { bridge }); diff --git a/packages/coding-agent/test/write-xdev-dispatch.test.ts b/packages/coding-agent/test/write-xdev-dispatch.test.ts index fc1198597..a55192c2c 100644 --- a/packages/coding-agent/test/write-xdev-dispatch.test.ts +++ b/packages/coding-agent/test/write-xdev-dispatch.test.ts @@ -335,9 +335,7 @@ describe("read and write route xd:// device URLs", () => { expect(summaryBytes).toBeLessThanOrEqual(XDEV_EXTERNAL_DESCRIPTION_CAP); // The ellipsis is inside the byte budget, and the cut backs off at most // one code point rather than splitting the character at the boundary. - expect(bodyBytes).toBeLessThanOrEqual( - XDEV_EXTERNAL_DESCRIPTION_CAP - Buffer.byteLength("…", "utf-8"), - ); + expect(bodyBytes).toBeLessThanOrEqual(XDEV_EXTERNAL_DESCRIPTION_CAP - Buffer.byteLength("…", "utf-8")); expect(bodyBytes).toBeGreaterThan(XDEV_EXTERNAL_DESCRIPTION_CAP - 6); expect(body.endsWith("あ")).toBe(true); // A split code point would decode to U+FFFD and fail the round trip. diff --git a/packages/hashline/test/patcher.test.ts b/packages/hashline/test/patcher.test.ts index 0ab353290..10436845b 100644 --- a/packages/hashline/test/patcher.test.ts +++ b/packages/hashline/test/patcher.test.ts @@ -159,7 +159,7 @@ describe("Patcher snapshot tag integrity", () => { // turned into tabs, exactly the corruption reported against the ACP bridge. class DriftingFilesystem extends InMemoryFilesystem { async writeText(path: string, content: string): Promise { - const drifted = content.replace(/^ /gm, "\t"); + const drifted = content.replace(/^ {4}/gm, "\t"); await super.writeText(path, drifted); return { text: drifted }; } @@ -194,7 +194,7 @@ describe("Patcher snapshot tag stays honest across a write-time content transfor // A follow-up edit anchored on the returned tag must succeed against // the real (drifted) file instead of failing a stale-tag mismatch. - const followUp = await patcher.apply(Patch.parse(`[${PATH}#${section.fileHash}]\nSWAP 1.=1:\n+function g() {`)); + await patcher.apply(Patch.parse(`[${PATH}#${section.fileHash}]\nSWAP 1.=1:\n+function g() {`)); expect(fs.get(PATH)).toBe("function g() {\n\treturn 2;\n}\n"); }); }); diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 07d564081..91604e494 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,11 +2,16 @@ ## [Unreleased] +### Added + +- Added response-level OSC 11 appearance subscriptions so terminal consumers can distinguish confirmed unchanged background classifications from missing replies ([#6923](https://github.com/can1357/oh-my-pi/pull/6923) by [@Sairen777](https://github.com/Sairen777)). + ### Fixed - Fixed native Windows terminal panes freezing their host during forced closure by skipping the impossible stdout-drain wait after ConPTY disconnects ([#6917](https://github.com/can1357/oh-my-pi/issues/6917)). - Fixed the `Loader` spinner pegging a CPU core during idle waits: advancing the braille glyph baked it into the underlying `Text` via `setText`, invalidating the wrap cache every 80 ms tick so `wrapTextWithAnsi` and per-line width measurement re-ran over the whole message. The wrapped text now carries a stable representative for each frame display width and only the visible glyph is swapped at render time, so same-width frames reuse the wrap/width pipeline while custom themes with mixed-width frames remain correctly wrapped ([#6940](https://github.com/can1357/oh-my-pi/issues/6940)). - Fixed hash-prefixed UUIDs in prose being misclassified as 8-digit CSS colors and receiving spurious swatches ([#7002](https://github.com/can1357/oh-my-pi/issues/7002)). +- Fixed unbounded memory growth when a PTY consumer stalls without dying: `ProcessTerminal.#safeWrite` handed every frame to `process.stdout.write()` and ignored its backpressure return, so a stalled-but-alive reader (never throws, unlike the terminal-death path in [#5837](https://github.com/can1357/oh-my-pi/pull/5837)) let the writable buffer grow without bound as cosmetic `hub wait` spinner/progress frames piled up — one incident reached ~48 GiB RSS and wedged the host. The write path now caps the pending stdout backlog and treats a consumer that will not drain past the cap as a disconnect, taking the same clean, supervisor-resumable exit as a dead terminal ([#6854](https://github.com/can1357/oh-my-pi/issues/6854)). ## [17.1.8] - 2026-07-28 @@ -14,9 +19,6 @@ - Fixed wrapped Markdown list continuations losing their hanging indentation in narrow terminal layouts. - Fixed an issue where emergency exits from fullscreen overlays could leave the Kitty keyboard protocol active, corrupting Arrow Up input in the terminal after exiting. -### Fixed - -- Fixed unbounded memory growth when a PTY consumer stalls without dying: `ProcessTerminal.#safeWrite` handed every frame to `process.stdout.write()` and ignored its backpressure return, so a stalled-but-alive reader (never throws, unlike the terminal-death path in [#5837](https://github.com/can1357/oh-my-pi/pull/5837)) let the writable buffer grow without bound as cosmetic `hub wait` spinner/progress frames piled up — one incident reached ~48 GiB RSS and wedged the host. The write path now caps the pending stdout backlog and treats a consumer that will not drain past the cap as a disconnect, taking the same clean, supervisor-resumable exit as a dead terminal ([#6854](https://github.com/can1357/oh-my-pi/issues/6854)). ## [17.1.7] - 2026-07-27 @@ -31,9 +33,6 @@ - Streaming markdown now freezes the stable prefix through provably closed lists instead of re-lexing everything after the last non-list block on every delta - Raised the markdown render cache entry budget (32 KiB → 256 KiB) so large messages — exactly the expensive renders — are cacheable - Deduplicated terminal cursor-visibility writes to skip redundant escape sequences -### Added - -- Added response-level OSC 11 appearance subscriptions so terminal consumers can distinguish confirmed unchanged background classifications from missing replies ([#6923](https://github.com/can1357/oh-my-pi/pull/6923) by [@Sairen777](https://github.com/Sairen777)). ## [17.1.6] - 2026-07-27 diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 52aa7cfa0..a792fbc01 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -2,13 +2,14 @@ ## [Unreleased] -### Changed - -- Replaced the central logger's Winston dispatch with a byte-compatible local dispatcher while retaining the existing `winston-daily-rotate-file` rotation and retention behavior. ### Added - Added a `postmortem.quit` option for shutdown paths where terminal output has already disconnected and cannot drain. +### Changed + +- Replaced the central logger's Winston dispatch with a byte-compatible local dispatcher while retaining the existing `winston-daily-rotate-file` rotation and retention behavior. + ## [17.1.8] - 2026-07-28 ### Added