Aligns the shim's runtime safeParse/__validator with the wire/tool-call
path, so legacy draft-07 documents (tuple items) accept the same values
validateToolArguments does. Adds a regression test.
customToolToDefinition rebuilt ToolDefinition without strict, so the
Task proxies' (and startup MCP tools') explicit strict:false was dropped
before RegisteredToolAdapter and the OpenAI-family serializers saw it.
Declare strict on ToolDefinition, copy it in the bridge, and cover the
proxy -> definition -> registered adapter path in the parity test.
Emitted session_shutdown after model rendering and centralized managed timer cleanup across one-shot listings and agent sessions.
Added regression coverage for the extension shutdown lifecycle.
Fixes#6297
Used the shared JSON Schema validator for Type.Unsafe so direct safeParse calls and composed shim schemas reject invalid values while preserving valid input identity.
Added direct and composed runtime regression assertions.
Preserved raw JSON Schema documents while keeping the shim validator identity-based, allowing provider wire conversion and runtime argument validation to consume MCP input schemas.
Added direct shim and remapped-extension regression coverage.
Fixes#6221
Passed the per-request model through SDK payload callbacks and ExtensionRunner context creation.
Added regression coverage for Codex-primary and Anthropic-request contexts.
Fixes#6006
omp's canonical getPackageDir() returns undefined inside a bun --compile
binary (import.meta.dir is /$bunfs/root, no owning package.json — issue
#1423). Re-exporting it directly broke pi's string-valued contract:
legacy extensions doing path.join(getPackageDir(), ...) crashed at
runtime in the shipped binary, the primary distribution.
Wrap the canonical helper so the shim always returns a string, falling
back to the executable's directory in compiled mode (where the binary is
the install root). PI_PACKAGE_DIR and dev/source/npm-dist walk-up still
win. Test covers the compiled-mode fallback via isCompiledBinary spy.
Fixes#5968
The legacy pi compatibility shim only forwarded getAgentDir (via
`export * from "../index"`). getProjectDir and getPackageDir were absent,
so any pi extension importing either from @earendil-works/pi-coding-agent
failed Bun's static export check during extension validation and the
install was rolled back.
Re-export getProjectDir from @oh-my-pi/pi-utils and getPackageDir from
omp's canonical config helper (returns the coding-agent package root,
matching pi semantics).
Fixes#5968
Create the resolved agent database parent before the synchronous compatibility store opens SQLite, and cover a fresh nested agent directory.
Fixes#5879
Extension/SDK/RPC registerTool defaulted an omitted loadMode to
"discoverable". A UI-only re-register of an essential built-in
(read/write/bash/edit/glob) then became discoverable and, with tools.xdev
on, was unmounted from the top-level schema. read/write dropping also
broke the xd:// transport (read xd://, write xd://<tool>), leaving the
model with no callable coding essentials.
- Add defaultLoadModeForToolName: omitted loadMode resolves to "essential"
for known essential built-in names, "discoverable" otherwise.
- Apply it at all four adapter boundaries (extension wrapper, custom-tools
wrapper, sdk customToolToDefinition, rpc normalizeHostToolDefinitions).
- Transport invariant: read/write never mount under xdev regardless of
loadMode (they carry the transport).
- Regression test covering the demotion, transport invariant, and a drift
guard tying the essential-name set to the tool classes.
Fixes#5764
The host guard's stdin restore only dropped listeners a module added; a
module that removed a snapshot listener (e.g. a factory calling
process.stdin.removeAllListeners("data") when a subagent re-runs preloaded
factories against a live parent TUI) permanently stripped ProcessTerminal's
input handler. Reconcile each guarded event back to the pre-load snapshot:
when membership changed, removeAllListeners then re-add the snapshot in
order, restoring both additions dropped and removals reinstated. Snapshot
via rawListeners so once-wrapped handlers round-trip intact.
Fixes#5618
Custom tool/extension/hook/plugin modules under ~/.claude/tools are
evaluated with live side effects during createAgentSession. A module that
attaches a stdin consumer at import time — an MCP StdioServerTransport
built at module top level, or a bare process.stdin.resume() — steals
Bun's single stdin reader, so the TUI receives exactly one data event and
goes permanently deaf after the first keypress. Under tmux the terminal's
automatic DA1 reply is that one event, so the first user keystroke is
already dead: the input-deafness reported in #5378/#5618.
Broadened the loader's withExitGuard (renamed withHostGuard) to also
snapshot and restore process.stdin around third-party module evaluation:
any data/readable/end/close/error listener the module adds is removed, and
the stream's paused and raw-mode state is restored to the pre-load
snapshot. The exit guard already fenced process.exit; stdin is the same
class of host-state hijack.
Fixes#5618
Extension-scheduled setInterval/setTimeout/detached callbacks ran outside
the handler-dispatch try/catch, so a throw surfaced as a process-level
uncaughtException and the global postmortem handler tore down the whole
session instead of isolating the misbehaving extension.
- Added ManagedTimers backing sanctioned ctx.setInterval/setTimeout/clearTimer:
callbacks run with handler-dispatch isolation (throw/rejection logged and
routed through onError), handles are unref'd, and all are cleared on
session_shutdown.
- Wired the helpers into ExtensionRunner.createContext and the runner-less
command-context fallback; onSession now inherits the runner context.
- Documented in-process no-isolation behavior and the managed timers in
docs/extensions.md and docs/skills/authoring-extensions.md.
Fixes#5664
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
Generated per-module loaders instead of eagerly evaluating the entire bundled compatibility graph during extension bootstrap.
This prevents appserver startup from cycling through its own retained command modules before the Unix socket is created.
Fixes#5568
Fetched current heads and tags into Bun's matching cached bare clone before running bun update.
Added an isolated HTTP git regression covering a moved branch with a stale cache.
Fixes#5401
ExtensionToolWrapper caught a thrown tool exception, emitted tool_result
with the modifiable result, then rethrew the original executionError whenever
the effective error state stayed true. This discarded any replacement content
or details a handler returned, so an extension could only surface modified
content by returning isError: false, which wrongly converted the failure into
a success.
Return the (possibly modified) result carrying isError instead of rethrowing.
The agent loop already honors AgentToolResult.isError (coerceToolResult) and
surfaces it as a tool error on the wire, so replacement failure content now
reaches the model while the call remains an error. No-modification, error->success, and success->error paths keep their existing semantics.
Fixes#5302
- Replaced legacy `pi/` role alias prefix with canonical `@` syntax across model resolution, documentation, and tests.
- Added support for bare `*` default alias and multiple alias prefix detection with custom role resolution in `resolveConfiguredRolePattern()`.
- Enhanced thinking suffix parsing to accept unambiguous abbreviations (minimum 2 characters) for effort and level selectors.
- Extended `resolveCliModel()` and `filterAvailableModelsByEnabledPatterns()` to accept settings parameter for role alias resolution from `--model` flag.
Validated custom tool factory results before registering plugin-provided tools so one malformed feature entry is reported and skipped instead of crashing startup.
Added regression coverage for null entries and mixed valid/null factory arrays.
Fixes#5189
Added an explicit timeout presentation capability so interactive queued dialogs defer the fallback while older UI implementations still get an immediate tool-owned timeout.
Refs #4995
Reset the ask tool fallback timeout whenever the interactive selector resets its UI countdown, preventing late keypresses from falling back to the original recommended option.
Refs #4995
- Removed the stale pinned dependency edge before invoking Bun for same-repository git source replacements so Bun does not construct a dependency loop.
- Added a regression test for the pinned-to-unpinned GitHub plugin replacement path.
Fixes#4960
Registered the bundled virtual resolver on the omp-legacy-pi-bundled namespace while keeping the file-namespace scheme fallback for build-time resolution.
Updated the regression test to cover registry-key resolver inputs.
Fixes#4954