- Native (non-mcp://) resource URIs now pass through byte-for-byte via
rawHref; slash elision applies only to the legacy mcp:// wrapper, so
catalog://root/ style URIs match exact-equality server lookups.
- resources/templates/list failure no longer discards a successful
resources/list (Promise.allSettled; templates retried later).
- Opaque RFC 3986 URIs (urn:doc, custom:item) are recognized by both
the router and read-cli discovery gates, with drive-path and
read-selector false positives guarded.
- Review follow-up for PR #6790.
- task.maxEffort only clamped the initial thinking level; a retry
fallback candidate could clamp back up to its model floor and run a
low-capped spawn at high.
- The ceiling now rides the session as thinkingLevelCeiling: clamped in
ModelControls (constructor, setThinkingLevel, auto classifier,
restore) and in applyRetryFallbackCandidate; fallback candidates whose
floor exceeds the ceiling are skipped.
- Effort value import moved to @oh-my-pi/pi-catalog/effort; changelog
attribution added.
- Review follow-up for PR #6794.
- Added a suppress load option so disabled servers still claim their
capability key: a project foo with enabled:false shadows a same-named
enabled user foo again, while scope-removed entries drop fully.
- Tool-name collisions now resolve by stable server+tool origin key
instead of manager array order, so reconnect re-appends cannot flip
the routed implementation.
- Review follow-up for PR #6787.
- Dropped the terminal split artifact so repeated saves no longer grow a
blank line per write.
- Replaced the partition-and-concat merge with an ordered line list:
headings, prose, and footers keep their positions; new lessons insert
at the head of the first bullet run and the cap trims oldest bullets.
- Strengthened tests to byte-exact idempotence and mixed-Markdown order.
- Review follow-up for PR #6774.
- WT_SESSION leaks into tmux/screen/Zellij panes, so the automatic raw
0x08 -> ctrl+backspace override deleted a word on plain Backspace.
- The heuristic now requires isWindowsTerminalSession() and not
isInsideTerminalMultiplexer(); PI_TUI_RAW_BACKSPACE_IS_CTRL=1 stays an
unconditional opt-in.
- Review follow-up for PR #6784.
- Retargeted the dynamic-only regression test at source-owned
CATALOG_PROVIDERS instead of the generated models.json type.
- Reused withCatalogDiscoveryTimeout for the models.dev lookup so the
timer clears on success.
- Deferred bundled-model reference index construction into the dynamic
fetch, keeping the ModelManager cache fast path free of a 12K-model
walk.
- Review follow-up for PR #6765.
- Handler wrappers spread ctx, snapshotting the model accessor; a handler
calling pi.setModel() then reading ctx.model saw the stale model.
- Scoped contexts now delegate via Object.create(ctx) with an own ui
property, so all accessors stay live.
- Review follow-up for PR #6806.
Moved RPC dialog request lifecycle into a reusable helper that emits a cancel frame targeting the original request before settling an aborted local promise.
Added coverage for remote confirmation cancellation and pending-request cleanup.
Render the Advisor spend next to the primary-model cost as `$2.67 (sub) + $0.41 (adv)`, leaving the status line unchanged until an Advisor cost exists.
Record the cost from finalized advisor `message_end` events in a per-session ledger instead of deriving it from the live advisor transcript, so an in-session compaction or any other history rewrite no longer resets the reported spend. The ledger is cleared for a new session and once a different-session switch commits, and survives a switch that rolls back.
Replaced the scoped UI object spread with a delegating proxy that binds inherited methods to the original context while overriding only abort-capable dialogs.
Extended watchdog coverage with a prototype-backed notification method matching RPC UI contexts.
Attached the session-stop abort listener and rechecked cancellation before invoking extension work, preventing synchronous ctx.abort() calls from being missed.
Added deterministic coverage for a handler that aborts and then waits on non-UI work.
Forwarded confirmation dialog options in the interactive TUI and scoped extension UI dialogs to each handler watchdog signal.
Added regressions for direct confirmation cancellation and fail-closed tool-call timeout cleanup.
Fixes#6805
- Keep terminal working titles static with a colon separator on Windows instead of scheduling animated spinner updates.
- Update terminal title builder and state machine to check the platform and bypass timer intervals on win32.
- Deduplicate terminal title writes globally across all platforms.
- Adopt `SetConsoleTitleW` via `bun:ffi` for Windows terminal updates instead of OSC writes.
- Cleared the retained soft-requirement lifecycle alongside the deferred
hard choice: clearDeferredToolDirectives() owns both, is called from
clearAllQueues/reset and session-scoped tool-state cleanup, with a
regression covering reminder re-injection after a queue clear.
- Allowed void-returning pre-model gates via the named AgentBeforeModelCall
type and normalized gate results in the loop and Agent dispatcher.
- Documented that the first gate installed mid-run applies from the next
run; corrected the onToolChoiceRejected contract docs; documented the
cross-run lifetime of ToolChoiceQueue's in-flight claim.
- Removed the unused addBeforeModelContextBuild hook.
- Relocated both packages' changelog entries out of the released 17.1.4
sections into Unreleased with PR attribution, folding the never-shipped
Fixed bullet into Added and noting the input-event timing change.
Added an optional per-server languageId override and used it for both disk-backed and in-memory didOpen notifications.
Covered config loading and both document-open paths with a fake custom GDScript server.
Fixes#6800
build-bindings.ts built the failure error from captured stderr only, but
napi-rs/cargo route much of the failure detail to stdout (e.g. `cargo
metadata exited with code 101 ...`). When stderr was empty the thrown
error collapsed to a bare "napi build failed", hiding the real cause.
Attach the exit code plus tail-capped stdout and stderr sections to the
thrown error so the actionable output survives on the error object.
Fixes#6796
Gates guard 1's suppression on #dead: the disconnected path stays
best-effort, but a failed restore during a normal stop() throws as it
did before the guard, instead of silently leaving stdin in raw mode.
Claude-Session: https://claude.ai/code/session_01LTC1HNAntXEMnTYmuUpGHz
Moved first-wins MCP tool-name deduplication and origin-aware warnings into one shared helper used by startup extension registration, SDK custom-tool assembly, and deferred refreshes.
Added an SDK startup regression proving colliding MCP proxy tools keep the first origin instead of silently overwriting it.
Fixes#6786
Applied the denylist and per-server enabled:false exclusions before connection-equivalence deduplication, alongside project scope, so a disabled higher-priority server can no longer shadow a differently-named equivalent enabled server and leave no connection. Parameterized LoadOptions<T> so the pre-dedup filter sees the typed item.
Fixes#6786
Applied the project-scope filter before connection-equivalence deduplication so a project server can no longer shadow a differently-named but equivalent user server and then be dropped, leaving none.
Fixes#6786
Windows Terminal identity is commonly lost across SSH and container hops,
leaving only the ambiguous raw 0x08 byte. Added the conservative
PI_TUI_RAW_BACKSPACE_IS_CTRL=1 opt-in so those sessions can map it to
ctrl+backspace without changing the default for terminals where 0x08 means
plain Backspace.
Restored the public isWindowsTerminalSession and matchesRawBackspace exports
and route the parser wrappers through matchesRawBackspace. Documented the
runtime flag and covered local WT, remote opt-in, SSH, and 0x7f behavior.
Fixes#6782
Deduplicated semantically identical MCP endpoints across provider-specific names while preserving provider priority and canonical direct names.
Kept the first registration on sanitized tool-name collisions and logged both origins.
Fixes#6786
- Replaced the napi-cli/cargo-zigbuild/cargo-xwin/sccache build path with
Bazel: rules_rust + crate_universe over Cargo.lock, hermetic zig cc
toolchains (linux-gnu pinned to glibc 2.17, linux-musl), host Xcode for
darwin, and a repo-local hermetic clang-cl + llvm-ml + xwin toolchain for
windows-msvc (bazel/toolchains/msvc).
- All eight shipped addons build as //:natives-<target> via the release
transition in bazel/defs.bzl (opt, thin LTO, cgu=16, stripped, canonical
.node naming); scripts/bazel-natives.ts is the single driver for local
dev and CI.
- Rust validation moved to bazel test + clippy aspects (strict workspace
policy for opted-in crates, default lints elsewhere, mirroring cargo
semantics) and the rustfmt aspect; cargo stays as the dev-iteration
surface, with brush-core/brush-builtins promoted to workspace members
and excluded from cargo dev tasks to keep their historical scope.
- CI caches through an in-cluster bazel-remote action cache (TLS + basic
auth, cluster-internal only); GitHub-hosted runners never touch the
infrastructure and use an actions/cache-backed disk cache instead.
- Deleted the hand-rolled caching machinery: ci-target-cache,
ci-native-artifact-cache, ci-build-native, native-source-hash,
find-native-artifacts, restore-linux-native, native-prewarm workflow,
ensure-* toolchain actions, and all sccache/Swatinem wiring.
- Warm native rebuilds drop from ~20 minutes to seconds; a cold client
with a warm remote cache rebuilds the linux x64 pair in ~2.5 minutes.
- Skipped extension-source reconciliation when restricted sessions intentionally load no extensions.
- Added a shared-registry regression covering the provider model, credential, and custom API.
Fixes#6783
The multi-line prompt editor matched word/line delete and yank with
hardcoded chords via matchesKey() instead of the keybindings registry,
unlike cursor motion and the single-line Input component. As a result
ctrl+backspace (a declared default of tui.editor.deleteWordBackward)
never fired and keybindings.yml remaps of deleteWordBackward,
deleteWordForward, deleteToLineStart, deleteToLineEnd, yank, and yankPop
were silently ignored in the main prompt.
Route those six actions through kb.matches(). Also re-wire the Windows
Terminal raw 0x08 -> ctrl+backspace disambiguation into the TS
matchesKey/parseKey seam (where WT_SESSION is observable), replacing the
dead matchesRawBackspace helper that no longer had any call sites.
Fixes#6782
Recorded per-target PID and jobspec errors while continuing through every remaining operand, then returned a non-zero aggregate status.
Added a regression with a stale PID between two live processes.
Fixes#6779