renderUsageReports (command-controller) carried the #3268 dedup contract
with no regression test; the PR's added CLI test asserts the opposite
(per-limit CLI rendering shows the note twice). Export renderUsageReports
and add a real regression through it: two accounts sharing one window group
render a provider-wide UsageReport.note once and an identical per-limit note
once. Verified failing on the pre-fix flatMap form (0 and 2 occurrences) and
passing on head (1 and 1).
Converted bracketed non-image filesystem path pastes into session-local attachment references while preserving the existing image path flow.
Added regression coverage for editor routing and controller local file attachment behavior.
Fixes#3360
- Added an extractText override to pi-mnemopi remember paths so stored content and mined facts can use different text.
- Routed coding-agent mnemopi retention to store the full transcript while extracting only user-authored turns.
- Tightened deterministic Instruction extraction to require an explicit I/you subject.
Fixes#3372
Stream fetched tool assets to disk under the existing download abort signal instead of passing the Response object to Bun.write. Remove partial files when a stalled body is aborted and cover completed plus stalled downloads with regression tests.
Fixes#3369
Address P2 review: sanitizeText preserves \t which can create visual
holes in rendered output. Add .replace(/\t/g, ' ') to provider-wide
and per-limit notes in usage-report.ts and usage-cli.ts, matching the
TUI path which already uses replaceTabs().
Apply sanitizeText to provider notes in the shared usage-report
renderer and the CLI usage output, matching the sanitization added
to command-controller.ts. Prevents tabs/newlines/control characters
in provider notes from breaking terminal rendering.
Address review feedback: provider notes could contain tabs, embedded
newlines, or control characters that break TUI rendering. Both note
rendering sites (provider-wide and per-group) now wrap the joined text
through sanitizeText → truncateToWidth → replaceTabs per AGENTS.md
TUI Sanitization rules.
Provider-wide disclaimers (e.g. OpenCode Go's "OMP-observed spend
only") were duplicated onto every UsageLimit, then repeated N times
in the TUI aggregate renderer (once per account × window). With
2 accounts × 3 windows, the same disclaimer appeared 6 times
bullet-joined.
Structural fix:
- Add notes?: string[] to UsageReport (interface + both schema
copies: usage.ts and auth-broker/wire-schemas.ts) so the field
survives the broker client's "+": "reject" deserialization gate.
- Move opencode-go's disclaimer from per-limit notes to
provider-level notes.
Defensive fix:
- Dedup identical per-limit notes in the TUI aggregate renderer
(command-controller.ts) via [...new Set(...)].
- Render provider-level notes once above per-account sections in
all three rendering paths: TUI (command-controller), CLI
(usage-cli), and ACP (usage-report helper).
Regression tests:
- usage-cli.test.ts: provider-level notes render once, not
duplicated per account or limit; positioned above per-account rows.
- usage-report-notes-schema.test.ts: wire-schema round-trip proving
notes survives usageResponseSchema validation.
Fixes#3268
Address codex P2 review: Windows UNC paths like \\server\share\me
become //server/share/me after toPosix, but path.posix.join collapses
leading // to /, producing /server/share/me/.bashrc — a local Unix path
instead of the UNC location.
Add posixJoinUnc() that restores leading // after path.posix.join when
any input segment starts with //. Add regression test for UNC homeDir.
Address codex review feedback on PR #3346:
- path.posix.join only adds / separators but preserves existing backslashes
in input segments (homeDir, ZDOTDIR, XDG_CONFIG_HOME), producing mixed
paths like C:\Users\me/.bashrc on Windows.
- Add toPosix() helper to normalize backslashes to forward slashes before
path.posix.join, applied to all POSIX-shell path components.
- PowerShell paths remain platform-native (path.join) as before.
- Add 3 regression tests: bash homeDir, zsh ZDOTDIR, fish XDG_CONFIG_HOME
all with Windows backslash paths.
The profile-alias installer used path.join unconditionally, which produces
backslash-separated paths on Windows. For bash/zsh/fish config files, this
is wrong — POSIX shells can't resolve backslash paths, even on Windows
(Git Bash, WSL).
Fix:
- resolveShellConfigPath: use path.posix.join for non-Windows platforms,
path.join for Windows (PowerShell profiles need native Windows paths)
- resolveProfileAliasCommandFromProcess: normalize script path to forward
slashes for the display/posix/fish fields (POSIX shells), keep native
path for the powerShell field
Updated 12 test assertions to compute expected paths dynamically using
path.join/path.resolve, so they match the platform's path separator.
All 17 profile-alias tests now pass on Windows (was 5 pass / 12 fail).
`__computeBunfsPackageRoot` now returns `//root/packages` for the Bun 1.3.14
`//root/<binary>` import.meta.dir shape, but production immediately joined that
root with shim and package segments through `path.join`, which collapses the
POSIX double-slash bunfs mount back to `/root`. That still made override
validation miss the embedded shim files.
Added a bunfs join helper that preserves the `//root` mount prefix after joining
production descendants, wired `bunfsPath` through it, and extended the #3329
regression test to assert the full typebox shim path stays under
`//root/packages/...`.
Fixes#3329
The reporter clarified that the failing binary is the pre-built
`omp-darwin-arm64` release asset from GitHub Releases; Homebrew is only a
local-tap wrapper that downloads that asset. The fix already covers every
cross-compiled `<bunfs-root>/<binary>` shape, but the source/test docstrings
and changelog blurb framed it as a Homebrew-build-specific bug. Updated those
three call sites to name the release asset and note the Homebrew tap as a
downstream consumer of the same binary; no code change.
Bun 1.3.14 reports `import.meta.dir` as `<bunfs-mount>/<binary-basename>` for
the compiled entry on some hosts — e.g. the Homebrew darwin-arm64 build sees
`//root/omp-darwin-arm64` instead of the bunfs root alone. The pre-fix path
joined `metaDir` with `"packages"` and baked the binary basename into every
bunfs path, so the typebox / legacy-pi shim overrides failed `existsSync`
validation, `resolveCanonicalPiSpecifier` fell through to a bunfs
`Bun.resolveSync` that also could not find the module, and every third-party
`@oh-my-pi/pi-*` extension was silently dropped.
`__computeBunfsPackageRoot` now detects the trailing binary-basename segment
(`path.basename(path.dirname(metaDir)) === "root"`) and strips it off the
original `metaDir` via string slicing rather than `path.join`, so Bun's
bunfs-native `//root` and `B:\~BUN\root` prefixes survive verbatim
(`path.posix.join` would collapse `//root` to `/root`). The single-segment
`<bunfs-root>` and deep `<bunfs>/packages/coding-agent/src/extensibility/plugins`
paths keep their existing branches.
Regression test added in `legacy-pi-bunfs-root.test.ts` for the POSIX
`//root/<bin>`, POSIX `/$bunfs/root/<bin>`, and Win32 `<drive>:\~BUN\root\<bin>.exe`
shapes.
Fixes#3329
Use a non-resolving discovery context for selected-model llama.cpp metadata refresh so command-backed and OAuth credentials stay lazy during model switches.\n\nFixes #3310
Read per-model llama.cpp meta.n_ctx values during discovery, refresh selected models after lazy load, and bypass fresh cache reuse for llama.cpp refreshes so server restarts update context windows.\n\nFixes #3310
Normalize the configured semaphore max before deciding whether the spawn
limit is bounded. Fractional values between 0 and 1 now truncate to 0 and
fall through to the unbounded path instead of storing 0 and deadlocking
the first acquire.
Fixes#3305
The session-scoped spawn Semaphore clamped its max via Math.max(1, max), so
task.maxConcurrency: 0 — labeled 'Unlimited' in the settings UI — serialized
subagent spawns one at a time instead of releasing every eligible seat.
The constructor now treats max <= 0 (and any non-finite input) as unbounded
via Number.POSITIVE_INFINITY, so the existing 'current < max' check naturally
permits every acquire. Mirrors the eval parallel()/pipeline() worker-pool
semantics (runEvalConcurrency in eval/concurrency-bridge.ts), which already
treats 0 as 'run every item at once'.
Fixes#3305
Pruned empty optional MCP argument placeholders before tools/call while preserving required fields and meaningful falsy values.
Added regression coverage for active and deferred MCP tools.
Fixes#3302
`nohup cmd &` is now a transparent background wrapper that double-forks the
operand so it reparents to init (commit 00dcd54597). The shell only tracks
the short-lived intermediate fork, so `$!` is no longer the surviving
process — the prior test read `$!`, then `process.kill(pid, 0)` checked an
already-reaped pid and failed on Linux (the failing CI job).
Split into two contracts:
- plain `&` retention: stays a child of the shell, counted by
`liveBackgroundJobCount`, kept alive by the retain map; `$!` is the real
child pid we assert on.
- nohup reparenting: the operand writes its own pid before `exec`ing the
long sleep, and that (post-exec-stable) pid is asserted to survive across
turns — independent of `$!`.
- Added `sanitizeOpenAIResponsesReasoningItemForReplay` to process reasoning-type items by stripping unique identifiers and filtering properties.
- Updated the main sanitization utility to route reasoning items through the new logic.