The previous #runSerialized waited on the shared #dispatchTail, then ran
unconditionally: when two or more events queued behind an in-flight run,
each resumed from the same settled await and started its own run in
parallel, defeating the ordering guarantee for a burst landing in one
coalescing window (message_end + agent_end behind a suspended flush).
Each waiter now chains its own link onto the current tail
(tail.then(run, run)), so queued runs start strictly one after another;
the idle path still runs synchronously, preserving the flush timing the
coalescing tests assert on. The in-flight flag clears only when the
settling link is still the tail, so a later chained link's settle does
not clear it early.
Regression test: two message_end events queued behind a suspended window
flush stay serialized (init call count steps 1 -> 2 -> 3 as each gate
opens); fails on the previous implementation.
The Claude/Cursor/Gemini/Windsurf importers appended user entries before
project entries, so a project `enabled: false` could not claim its dedupe key
ahead of a same-named user server and the disable was silently ignored. Load
project entries first, matching the native/Codex loaders, so a project disable
suppresses a same-named user server.
Updated docs/mcp-config.md to reflect the project-first precedence and added
compound regression coverage.
Fixes#7652
Set HOME and os.homedir() to a dedicated temporary directory for each translated-provider fixture, then restore both after every test. This prevents real user MCP configs from shadowing the project fixture through capability deduplication.
The Claude Code, Cursor, Gemini CLI, Windsurf, and VS Code importers built
their canonical MCPServer object without mapping serverConfig.enabled, so a
server declared with "enabled": false stayed undefined and the central
suppressServer filter never fired. Only disabledServers masked the gap.
Map the field in each importer, mirroring opencode.ts and codex.ts, and add
a table-driven regression test across all five importers.
Fixes#7652
AgentSession.#emit fires listeners fire-and-forget, and the coalesced
message_update flush fires from its own 33ms timer — neither path awaited
the other. A rapid stream tail (message_update -> message_end ->
agent_end) could therefore run the end handlers while the flush was
suspended mid-await, agent_end removing streamingComponent before
#handleMessageEnd finalizes and records the final message (issue #7443
follow-up).
- #runSerialized chains listener dispatch and the timer flush through one
promise chain; an in-flight run holds later events until it completes.
Idle dispatch stays synchronous (no added microtask), preserving the
timing the coalescing tests assert on.
- Regression test: a message_end landing while the window flush is
suspended on init is queued behind it (initCalls 1 while suspended,
then 2), where the pristine code ran both concurrently (2 while
suspended). Fails without the fix.
Per-event stdout writes in --mode json (and text) were fire-and-forget
and relied on an empty-write flush barrier before dispose/exit. The
barrier awaited its own callback, not the preceding large write, so a
big final agent_end could be truncated when the process exited before
the pipe drained -- while still exiting 0.
Serialize every print-mode stdout write on its own completion callback
(honoring backpressure) and block shutdown on the tail so the terminal
record is delivered in full.
Fixes#7635
Added the no-op setter to lightweight print-mode session mocks so text-mode runs without a submitted prompt no longer throw at the final commit call.
Fixes#7625
Made text replay safety depend on whether the active output sink has committed streamed text.
Kept tool calls, images, and server tools replay-unsafe while covering text and JSON print policies plus a transient socket-close recovery.
Fixes#7625
Completes the maintainer's removal of per-call model selection from
subagent spawns (9f8aa87dbf removed it from the task tool and the
model-facing agent() docs/prompt, but the eval agent() runtime and all
four preludes still accepted and forwarded a per-call model).
Subagents now always resolve through the selected agent's frontmatter
model and settings, so an explicit model: "default" can no longer
silently route children onto the parent session model.
- agent-bridge: drops "model?" from agentArgsSchema and the request
forward; adds "+": "delete" so a legacy model argument is stripped
(same contract as the task wire schemas).
- JS/Python/Ruby/Julia preludes: remove the model parameter from
agent(); completion()'s tier selector is unchanged.
- docs (tools/eval.md, python-repl.md) updated to the removed surface.
Refs #6438
Selected PUPPETEER_EXECUTABLE_PATH before probing system browser installations so compatible headless-shell binaries remain usable by the shared daemon.
Added an isolated Windows candidate-selection regression probe.
Fixes#7601
The grep/glob multipath detector probed the raw joined string with lstat
and only split when the probe reported "missing" (ENOENT/ENOTDIR).
ENAMETOOLONG was classified as "unknown", which suppressed the split, so
a semicolon-delimited path list long enough to exceed NAME_MAX or
PATH_MAX collapsed to one literal path and failed with
"Path not found: <whole list>" even though every entry existed.
Classify ENAMETOOLONG as "missing" in probeLiteralPathExists and
delimitedPathPartResolves (a too-long string can never name a real
single entry), and broaden glob's stat catch so the raw errno never
reaches the caller.
Fixes#7597
Detected path-embedded OMP line selectors when reporting Cursor read results and stopped treating ranged payload lengths as whole-file totals.
Exposed exact source line counts from EOF-reaching read results and covered both the wire response and read metadata contracts.
Fixes#7590
The shared `recall` tool description instructs a follow-up `read memory://<id>`,
but the memory:// handler resolves only `root` and mnemopi ids. Under
memory.backend=hindsight, following the tool's own docs hit the generic
"Unknown memory namespace" error that only mentions mnemopi, causing repeated
failed reads and derailment.
Make the handler backend-aware: when a memory://<id> read arrives while a
Hindsight session is active and no mnemopi state can serve it, throw a
corrective error pointing at `recall`/`reflect` so a stray read self-corrects
in one turn.
Fixes#7587
OpenAI-compatible endpoints such as Synthetic advertise vision support through a top-level input_modalities array. Include that response field alongside direct input and nested architecture.input_modalities, with regression coverage for a catalog-absent id.
Warm context-v2 rows cached before server input-modality parsing pinned vision-capable ids at input: ["text"] until a forced refresh. Bump the namespace to context-v3 so the modality fix takes effect on the next online-if-uncached refresh, and add a regression proving v2 rows are orphaned.
Keep the richer LM Studio /api/v0/models input metadata ahead of the thin OpenAI-compatible row while retaining row-first behavior for generic openai-models-list discovery. Add a regression covering a text-only /v1/models row paired with a native VLM record.
discoverOpenAIModelsList never consulted the /v1/models row's input
field, so custom virtual tier ids absent from the bundled catalog fell
through to the ["text"] fallback and showed images: no even when the
server advertised input: ["text","image"]. Parse the direct input array
and OpenRouter-style architecture.input_modalities from the response row,
preferring server-reported modalities over native metadata and the
bundled reference.
Fixes#7583
Two recall paths shared the hasRecalledForFirstTurn flag: the agent_start
subscription (maybeRecallOnAgentStart, fire-and-forget with an unawaited
background prompt rebuild) and beforeAgentStartPrompt (awaited before the
turn builds). When the event path consumed the flag first,
beforeAgentStartPrompt returned undefined and the recalled context reached
the model only if the background rebuild had already landed -- on a fast
turn it had not, so autoRecall intermittently never reached the model.
Make beforeAgentStartPrompt the sole injection path and drop the racing
agent_start recall.
Fixes#7568