commits on main
2026-09-01
bee1dc82 dawn feat(coding-agent): add loss-bounded compaction projection
feat(coding-agent): add loss-bounded compaction projection
f49ba1ee dawn fix(coding-agent): drain bash completion before RLM follow-up
fix(coding-agent): drain bash completion before RLM follow-up
94f25d4f dawn feat(coding-agent): add root session controls
feat(coding-agent): add root session controls
b0023ef6 dawn feat(coding-agent): add dot continuation shortcut
feat(coding-agent): add dot continuation shortcut
2026-08-31
ca7ba908 dawn fix(coding-agent): avoid subagent finalization deadlock
fix(coding-agent): avoid subagent finalization deadlock
bd35d3a8 dawn fix(update): preserve client reconnect across supervisor shutdown
fix(update): preserve client reconnect across supervisor shutdown
6d3e2609 dawn fix(update): restart prepared daemon when coordination fails
fix(update): restart prepared daemon when coordination fails
186ed0c5 dawn chore(models): refresh final live catalog changes
chore(models): refresh final live catalog changes
992bc7c2 dawn fix(update): freeze daemon workers before package mutation
fix(update): freeze daemon workers before package mutation
5a3bce07 dawn test(rlm): initialize hosted child runtime fixture
test(rlm): initialize hosted child runtime fixture
81707659 dawn chore(models): refresh generated catalog
chore(models): refresh generated catalog
2afe65a0 dawn fix(daemon): reclaim dead worker tombstones before updates
fix(daemon): reclaim dead worker tombstones before updates
72bc988e dawn fix(runtime): survive SystemExit in persistent REPL
fix(runtime): survive SystemExit in persistent REPL
d167f61c dawn fix(rlm): persist failed children without false result readiness
fix(rlm): persist failed children without false result readiness
aa476e6f dawn fix(daemon): freeze snapshot messages at capture
fix(daemon): freeze snapshot messages at capture
7e70aea0 dawn complete guarded RLM results and background completion wakeups
complete guarded RLM results and background completion wakeups
78a0e05d dawn reject cd prefixes in bash(): teach repo.cd()/os.chdir instead
reject cd prefixes in bash(): teach repo.cd()/os.chdir instead
7f881a4b dawn docs(rlm): reflect fail-closed spawn boundary in runtime architecture
docs(rlm): reflect fail-closed spawn boundary in runtime architecture
4a770d65 dawn make rlm spawns fail-closed: schema-bound results by default, guarded context, explicit unguarded opt-out
make rlm spawns fail-closed: schema-bound results by default, guarded context, explicit unguarded opt-out
63b9e269 dawn fix(ai): stop forcing disabled thinking on models that cannot disable it
fix(ai): stop forcing disabled thinking on models that cannot disable it
- GLM 5.3 rejects an explicit thinking disable ("use low, high, or max"); the zai/qwen/qwen-chat-template/deepseek wire formats treated unspecified thinking as an explicit disable, so /refine, compaction summaries, and other completeSimple callers failed with a 400 - unspecified or unsupported thinking now leaves thinking enabled for models whose thinkingLevelMap marks off as null - generate-models marks off/minimal/medium/xhigh unsupported for openai-completions GLM 5.3 entries (matching the OpenRouter-derived map), so clampThinkingLevel resolves off to low and getSupportedThinkingLevels stops advertising off - regenerated the model catalog
878bf913 dawn feat(coding-agent): unify RLM subagent lifecycle, messaging, and observation on rlm
feat(coding-agent): unify RLM subagent lifecycle, messaging, and observation on rlm
- rlm() and rlm.list_subagents() return one mutable RLMSubagent handle owning refresh, send, observe, info, result, and delete; RLMSpawnHandle is removed - agent messaging and observation move into rlm (send_parent, send_sibling, send_child, family, observe, info); agent_message.* and agent_observe.* host routes register whenever their controllers exist, independent of skill visibility - bundled agent-message and agent-observe skills are no longer model-visible; prompts document the rlm-native surface only - composable schema-validated result and context-admission contracts for RLM subagents - docs and changelog fragments updated for the unified surface
d9c54e19 dawn fix(ai): preload provider modules at process startup
fix(ai): preload provider modules at process startup
Upgrading a global install rotates the hashed bundle chunk files under a still-running process. Provider adapters load lazily via dynamic import, so the first request for a not-yet-loaded adapter after an upgrade resolves against the mutated install and fails with "Cannot find module". preloadApiProviderModules() warms every provider module at boot in every process that enters main() (interactive client, daemon worker, daemon supervisor), so a running process never resolves provider chunks from disk again. Load failures still surface per-stream through the lazy wrappers.
c718bf3c Sebastian Müller fix(coding-agent): steer the model away from subprocess.run toward bash() (#1910)
fix(coding-agent): steer the model away from subprocess.run toward bash() (#1910)
2026-08-30
c382f098 Sebastian Müller feat(coding-agent): render Mermaid diagrams inline in the terminal (#1893)
feat(coding-agent): render Mermaid diagrams inline in the terminal (#1893)
* feat(coding-agent): render Mermaid code blocks as inline Unicode diagrams Ports pi-mono's Mermaid rendering (grok-mermaid) into prime-agent: - pi-tui Markdown gains an options.transform hook that rewrites source Markdown with the exact content width before parsing (ported from upstream pi-tui). - New mermaid.ts transform replaces top-level mermaid code blocks with themed Unicode diagrams, falls back to the raw block when the diagram is wider than the message, and appends a themed warning line for partially rendered final diagrams. - AssistantMessageComponent applies the transform to text blocks only (never thinking blocks) and tracks streaming state so the streaming-to-final transition re-renders. - New markdown.mermaid setting (off/final/streaming, default streaming) with a settings-selector entry. Linear: ENG-5673 * test(coding-agent): kill mermaid mutation survivors Adversarial review mutation testing found three surviving mutants: - width guard flipped to >= (exact-fit diagrams would fall back) - codeSpan fence reduced to a single backtick (backtick labels break) - isStreaming inverted at the message_end call site (final mode never renders) Adds an exact-width boundary test, a backtick-label test, and a handleEvent-level final-mode transition test that kill them. * build(coding-agent): pin grok-mermaid exactly for renderer-output stability * test(coding-agent): collapse redundant mermaid coverage * docs(coding-agent): tighten mermaid comments * fix(coding-agent): tolerate non-object markdown settings values Normalize a malformed markdown settings value at the migration boundary (mirroring the telemetry handling) so changing the Mermaid mode cannot throw, and add the missing tui changelog fragment. * test(coding-agent): drop mermaid.test.ts * chore(coding-agent): one-line mermaid codeSpan comments
a903d4b6 Sebastian Müller chore: vouch sirouk as an external contributor (#1899)
chore: vouch sirouk as an external contributor (#1899)
2026-08-29
5b6c0e94 Sebastian Müller fix(coding-agent): enforce session ownership when joining an in-flight open (#1864)
fix(coding-agent): enforce session ownership when joining an in-flight open (#1864)
* fix(coding-agent): wait for worker recovery before session reuse * fix(coding-agent): join overlapping worker starts * fix(coding-agent): enforce session ownership when joining an in-flight open Joining an opening worker via openingWorkers returned the pending worker to any client with the same session path, bypassing the ownership check that the settled path applies in reuseWorkerForCreate. Await the pending open and apply the shared owner check before returning; a rejected open still propagates its original error to joiners. * fix(coding-agent): rejoin an open registered during stale-worker reclaim The reclaimStaleWorkerRegistration await sits between the pending-open check and openingWorkers.set, so a concurrent opener registered during that await was overwritten and a second worker launched for the same saved session (regression from the #1756 reordering). Re-check the map after the reclaim await and join through the shared owner-checked path. * test(coding-agent): cover foreign-owner join at the post-reclaim re-check An intruder client joining the open registered during stale-worker reclaim must get SessionAlreadyActiveError; kills the mutant that returns the pending promise without the owner check.
6322b7bb Sebastian Müller refactor(coding-agent): await in-flight bash completion during daemon close (#1858)
refactor(coding-agent): await in-flight bash completion during daemon close (#1858)
bcf69db5 Sebastian Müller refactor(coding-agent): remove the test-only daemon-lookup seam from main.ts (#1851)
refactor(coding-agent): remove the test-only daemon-lookup seam from main.ts (#1851)
8ca52555 Sebastian Müller refactor(ai): delete the unused getOverflowPatterns export (#1850)
refactor(ai): delete the unused getOverflowPatterns export (#1850)
* refactor(ai): delete the unused getOverflowPatterns export * docs(ai): fix changelog fragment placement for getOverflowPatterns removal The removed API belongs to @earendil-works/pi-ai, not the coding-agent package (whose root export never included it), so drop the misplaced coding-agent fragment and name the removed export explicitly in the ai fragment.
853041ec Sebastian Müller fix(coding-agent): abort every in-flight bash command with its own controller (#1882)
fix(coding-agent): abort every in-flight bash command with its own controller (#1882)
* fix(coding-agent): give each executeBash invocation its own abort controller Concurrent execute_bash_and_wait daemon commands shared the single _bashAbortController field: the first finisher cleared the second command's controller and abortBash could only target the most recent command, leaving earlier still-running commands unabortable. Track per-invocation controllers in a set; abortBash aborts all in-flight commands. Fixes ENG-5752. * fix(coding-agent): flag pending user bash abort while other bash commands run abortBash only set _userBashAbortRequested when no abort controllers were registered, so an abort arriving during user_bash extension dispatch was lost when a concurrent executeBash occupied the controller set and the user bash still started. Set the flag whenever a user bash is running; runUserBash clears it at each start. Also reword the per-invocation controller comments to present-tense behavior. * test(coding-agent): update fake REPLs to protocol 3 --------- Co-authored-by: Xeophon <46377542+xeophon@users.noreply.github.com>
dab03c00 Sebastian Müller refactor(coding-agent): wake RLM quiescence on activity changes instead of polling (#1859)
refactor(coding-agent): wake RLM quiescence on activity changes instead of polling (#1859)
* fix(coding-agent): serialize post-compaction continuation on run settlement * refactor(coding-agent): wake RLM quiescence on activity changes instead of polling * fix(coding-agent): guard post-compaction continue against auto-compaction and stale runners - Publish _compactionOperation from _runAutoCompaction so the post-compaction continuation runner (and other waiters) serialize against auto/threshold/overflow/requested compaction, not just manual compact(). - Identity-guard the success path of the continuation runner so a cancelled runner cannot forget continuation messages that a replacement settlement still owns (busy/error paths already did). * fix(coding-agent): recheck refine apply before dispatching post-compaction continue A refine() call could enter its apply phase (which disconnects the agent event listener) between the runner's top-of-loop _waitForRefineIdle() and agent.continue(), losing the continuation's messages. Recheck _refineInFlight under the commit fence like pauses/_compactionOperation; the path from that recheck to agent.continue() is synchronous, mirroring the final refine barrier used by normal turn dispatch. * fix(coding-agent): release the continuation runner's idle wait on cancel A cancelled post-compaction continuation left its runner parked inside waitForIdle when the pump was suspended with queued actions: the wait was not raced against the settlement like its neighbors, so the runner re-registered a session-input checkpoint waiter on every notify. The leaked waiter kept hasPendingAdmissionWaiters true and blocked daemon passivation until an unrelated resume. waitForIdle's loop now takes an optional settlement: the suspended-queue park races the settlement promise, deregisters its waiter on loss, and the loop exits once the settlement is superseded. The runner uses the settlement-scoped variant; public waitForIdle is unchanged.
85c236d5 Sebastian Müller refactor(coding-agent): derive scoped heartbeats at render time (#1857)
refactor(coding-agent): derive scoped heartbeats at render time (#1857)
* refactor(coding-agent): derive scoped heartbeats at render time * fix(coding-agent): keep the earliest heartbeat manager refresh deadline scheduleHeartbeatManagerRefresh now runs on every subagent snapshot update, and each call cleared and re-armed the refresh timer. An overdue heartbeat uses a relative 5s fallback delay, so children updating more often than every 5s postponed the open manager's refresh indefinitely. Track the scheduled deadline and keep the pending timer unless the newly derived deadline is earlier. * test(coding-agent): cover re-arming the heartbeat refresh to an earlier deadline The keep-timer-always mutant (returning whenever a timer is armed) survived the touched suites: nothing proved a sooner heartbeat pulls the pending refresh forward past the capped 60s poll.
18fe5d5b Sebastian Müller refactor(coding-agent): delete unreachable empty-selector auto-cancel timers (#1855)
refactor(coding-agent): delete unreachable empty-selector auto-cancel timers (#1855)
9db2722e Sebastian Müller refactor(coding-agent): remove the NODE_ENV=test telemetry branch (#1848)
refactor(coding-agent): remove the NODE_ENV=test telemetry branch (#1848)
dfffea27 Sebastian Müller fix(coding-agent): unify legacy RLM registry parsing (#1847)
fix(coding-agent): unify legacy RLM registry parsing (#1847)
* fix(coding-agent): unify legacy RLM registry parsing * fix(coding-agent): drop damaged rlmMaxDepth instead of rejecting the entry The unified parser hard-rejected a legacy registry entry when the optional rlmMaxDepth field was malformed, so a valid child edge vanished from ledger seeding and passive discovery. Normalize the field to absent instead; the required topology fields still gate the entry.
c0334a17 Sebastian Müller fix(coding-agent): single projection for RLM child snapshots (#1845)
fix(coding-agent): single projection for RLM child snapshots (#1845)
* fix(coding-agent): single projection for RLM child snapshots * fix(coding-agent): project live follow-up activity for session-only children A rehydrated child registered without an RlmChildRun always snapshotted as status done with no activity, so an attach mid-follow-up showed it idle. Derive activity from live session state, mirroring the run projection's done-plus-activity convention for follow-ups.
bab12421 Sebastian Müller fix(coding-agent): single-source the interactive queue state (#1842)
fix(coding-agent): single-source the interactive queue state (#1842)
* fix(coding-agent): single-source the interactive queue state * fix(coding-agent): close queue-state races around rebind, moves, and failed edits - rebindCurrentSession: re-sync sessionActions after resubscribing; a session_action_update fired in the unsubscribed gap was lost forever. - browseQueueSelection: block browsing while a queue move RPC is pending, matching the pendingQueueEdit guard, so the move response cannot reselect the original item under newly browsed editor text. - moveQueueSelection: when the applied move's session_action_update has not landed yet (sessionActions reference unchanged), mirror the swap locally so the moved selection is not dropped against the pre-move snapshot; reconcile the selection in the error path. - applyQueueSelection: reconcile the selection after the pending-edit flag clears, so a rejected/failed edit no longer leaves Enter targeting a row that was removed while events were suppressed.
ee8fd699 Sebastian Müller fix(coding-agent): wait for worker recovery before session reuse (#1756)
fix(coding-agent): wait for worker recovery before session reuse (#1756)
* fix(coding-agent): wait for worker recovery before session reuse * fix(coding-agent): join overlapping worker starts
05601462 Sebastian Müller refactor(coding-agent): remove test-only parser and feature-hint seams (#1860)
refactor(coding-agent): remove test-only parser and feature-hint seams (#1860)
* refactor(coding-agent): remove test-only parser and feature-hint seams * test(coding-agent): restore provider-overlap and invalid-suffix warning coverage via public resolver API
80bf72c8 Sebastian Müller fix(coding-agent): avoid retrying delivered remote agent messages (#1700)
fix(coding-agent): avoid retrying delivered remote agent messages (#1700)
* fix(coding-agent): avoid retrying delivered agent messages * Add the changelog fragment
2026-08-28
d60fab8a Sebastian Müller fix(coding-agent): repair corrupt REPL protocol frames (#1839)
fix(coding-agent): repair corrupt REPL protocol frames (#1839)
* refactor(coding-agent): unify kernel shutdown * docs(coding-agent): carry over shutdown rationale comments * fix(coding-agent): repair corrupt REPL protocol * fix(coding-agent): cancel the final kernel snapshot before disposal cleanup * fix(coding-agent): block new executions from splicing ahead of the final dispose snapshot flushSnapshotForDispose captured the execution queue while the kernel state was still 'running', so a concurrent execute() (which has no per-cell timeout) could enqueue after the capture; captureSnapshot then queued behind it and its timeout never started, hanging dispose() and shutdown({snapshot:true}) forever. Claim the flush before capturing the queue: non-internal requests are rejected while the final snapshot is flushing, keeping every wait on the dispose path bounded. * fix(coding-agent): close protocol-repair races and bound the repair - Gate queued requests behind an in-flight repair: a request whose queue slot opens during a repair releases the slot and requeues after the repair, so queued executes/snapshots can no longer run on the empty replacement kernel ahead of restoreState (and overwrite its result or clobber the last good snapshot). - Race the repair wait in execute() with opts.signal so an aborted call returns its aborted result promptly instead of pending through repair. - Bound the repair's restore with REPAIR_RESTORE_TIMEOUT_MS so a stalled replacement cannot wedge protocolRepairPromise (and every later execute) forever; a timed-out restore discards the replacement and returns to clean idle. - Stop respawn-looping when the replacement kernel itself emits a corrupt frame during repair: discard it and settle at clean idle instead of superseding into an unbounded chain of repairs. * fix(coding-agent): re-bootstrap repaired kernels and gate busy-waiting cells - A protocol-repaired kernel restored only the user namespace, so live handles (rlm, bash, skills) were missing and the next cell failed with NameErrors. KernelManagerOptions gains bootstrapCode (the provisioner passes its buildRlmBootstrapCode output); the repair re-runs it after restore, bounded like the restore, and discards the replacement to clean idle when it fails. - The repair requeue gate only ran right after taking the queue slot, so a cell busy-waiting on an interrupted execution when corruption arrived could proceed onto the unrestored replacement while blocking the repair's restore behind its slot. The gate now sits after the busy-wait (still exempting the repair's own requests), covering both windows. - Fold the repeated kill-to-clean-idle teardown into killChildToIdle and rename REPAIR_RESTORE_TIMEOUT_MS to REPAIR_STEP_TIMEOUT_MS since it now bounds restore and bootstrap. * fix(coding-agent): join concurrent teardowns into one final snapshot flush Concurrent dispose() and shutdown({ snapshot: true }) (e.g. a session dispose racing the SIGINT handler) each ran flushSnapshotForDispose: the first finisher's finally cleared flushingSnapshotForDispose while the second was still flushing, dropping the execution guard early and enqueueing a duplicate final snapshot behind the first. Memoize the in-flight flush so every teardown joins the same bounded flush. * fix(coding-agent): close protocol repair gaps for schema-invalid frames, startup chunks, and rebootstrap - Fail the protocol on JSON object frames that violate the frame schema (unknown event kind; done/host_request without a string id) instead of silently dropping them, which left the active request unsettled forever. The protocol version handshake is exact, so unknown kinds are corruption, not forward compatibility. - A corrupt frame sharing one stdout chunk with ready no longer lets the startup mark the corrupt child running: failProtocolFrame records the error while starting and doStart fails the start. - A fresh kernel started lazily after a discarded repair re-runs the configured runtime bootstrap before serving user code, so rlm/bash/skills handles are never silently missing. * test(coding-agent): reconcile chain-collapse suites and cover teardown racing the lazy re-bootstrap - Point the graceful-shutdown flush spies at captureSnapshot: the merged final flush (kernel-snapshot-dispose-timeout) snapshots through the bounded captureSnapshot path, not snapshotState, so the old spies let real snapshot requests hit the mocked wire and leaked fake timers. - The superseded repair's booting replacement is now hard-killed without a protocol shutdown (single-kernel-shutdown only drains running kernels), so it may die before journaling its spawn; assert spawn-count stability after teardown instead of an exact boot count. - New composition test: a teardown racing an in-flight lazy re-bootstrap stays bounded, spawns nothing new, and settles the raced cell. * fix(coding-agent): re-check the final-flush guard after the re-bootstrap wait - An external execute admitted before the final dispose flush could park on the lazy re-bootstrap, then take its queue slot after the flush captured pendingExecutions - splicing between the captured queue and the final snapshot and unbounding the teardown. Re-check the flush guard right after the ensure await; unit test proves the re-check is load-bearing. - Deflake the teardown-vs-re-bootstrap composition test: the fake runtime journals its spawn before ready, so poll isRunning before the teardown to race the re-bootstrap deterministically instead of the boot. * fix(coding-agent): close bot-review gaps in protocol repair and teardown seams - Terminal frames (done/host_request) with an EMPTY string id now fail the protocol like id-less ones: the runtime mints uuid hex ids and echoes the host's uuids, so an empty id is corruption that previously slipped past the validator into the silent-drop hang. - An execution aborted while waiting on the lazy re-bootstrap settles promptly: the wait races the abort signal (same pattern as waitForProtocolRepair) and the aborted request returns before parking on the queue slot behind the still-running bootstrap. - A failed kernel startup awaits its own teardown (final snapshot flush included) before surfacing the error, so a replacement provisioner gated on this dispose can no longer race the still-flushing kernel over the same snapshot files. - restart() during the final dispose flush is rejected instead of taking a queue slot and joining the owning shutdown, which could deadlock the flush's snapshot behind the held slot. * test(coding-agent): cover empty-string host_request ids in the frame validator Kills the surviving mutant that relaxed the host_request half of the non-empty-id requirement back to typeof-only: an empty-id host_request now has a corruption test mirroring the empty-id done one (protocol fails and the kernel is repaired instead of the awaiting cell hanging). * fix(coding-agent): restore the saved namespace on lazily reprovisioned kernels After a discarded repair whose failure never implicated the snapshot (the repair start died, or only its bootstrap failed), the lazily started fresh kernel re-ran the bootstrap but silently abandoned the user's saved namespace forever. Track restore separately: killChildToIdle marks both pending; the two snapshot-culprit discard paths (clean restore failure, replacement corrupted mid-repair) clear the restore flag so a poisoned snapshot is never retried; the lazy path restores one-shot best-effort (ordinary startup semantics) before bootstrapping, and a teardown's final snapshot never triggers reprovisioning. Restore-attempt journaling in the fake runtime pins the no-retry and no-double-restore semantics. * fix(coding-agent): protect the saved snapshot from unrestored kernels; phase-aware corruption attribution - The final dispose flush skips its snapshot while pendingRestore is set: a kernel that never restored the saved namespace must not overwrite it (the on-disk snapshot is strictly fresher). One interleaving-independent condition instead of joining the reprovision promise, which would reintroduce the 30-60s teardown stall the teardown guard prevents. The lazy one-shot clear moves after the corruption check so the flag also covers a flush racing an in-flight lazy restore. - The repair give-up path attributes corruption by phase: performRestore clears pendingRestore on success, so the flag still being set means the corruption struck at or before the restore (snapshot stays the prime suspect, loop-safe); corruption strictly after a successful restore keeps the namespace restorable at the cost of at most one bounded restore per later attempt.
af14f066 Sebastian Müller fix(coding-agent): dispatcher-owned host-reply envelope (#1836)
fix(coding-agent): dispatcher-owned host-reply envelope (#1836)
* fix host reply result envelope * docs(coding-agent): drop a stale handler-contract sentence from the merge
ceb41804 Sebastian Müller refactor(coding-agent): centralize agent-message admission in AgentSession (#1861)
refactor(coding-agent): centralize agent-message admission in AgentSession (#1861)
* refactor(coding-agent): query agent peers on demand instead of broadcasting mirrors * refactor(coding-agent): centralize agent-message admission in AgentSession * fix(coding-agent): respond to unknown worker commands instead of dropping them Legacy worker_sync_agent_peers commands from an older supervisor fell through handleWorkerCommand without a response, forcing the requester to wait out its full 5s timeout on every peer sync. A default case now writes an immediate failure for any unhandled worker command. * fix(daemon): re-check cron job runnability after prompt admission fence runCronJob snapshotted the runnable job before promptHeartbeat/ promptUntilAccepted, which can wait on the session admission fence. A job cancelled or completed during that wait was still delivered. Re-check via the admissionCommitted hook and skip when the job is no longer runnable. * fix(daemon): skip cron delivery when the job content changed during admission updateRlmHeartbeat mutates prompt/deliveryMode in place under the same job id, so the existence-only admissionCommitted re-check still delivered the stale snapshot captured before the admission fence wait. Compare the refreshed job's prompt and deliveryMode and skip on mismatch; the skip reschedules nextRunAt so the updated instruction is delivered next cycle. * fix(coding-agent): re-check prompt admission after async input normalization _prompt ran admissionCommitted before _normalizeSubmission, but async extension input handlers are awaited between that check and _admitSessionInput, so a cron job cancelled or updated during the await still delivered its stale prompt. Re-run the callback after the awaited normalization so invalidated content is not admitted.
80902713 Sebastian Müller fix(runtime): ordered bash output completion sentinel (#1838)
fix(runtime): ordered bash output completion sentinel (#1838)
* fix(runtime): fence bash output completion * docs(runtime): document post-fence output visibility in bash() docstring * fix(runtime): emit bash completion fence via absolute printf path A shell function named `command` shadows `\command -p printf` (the backslash only defeats aliases), swallowing both fence frames and wedging the await behind background jobs until shell death. A slash-qualified printf resolved on the system default utility PATH bypasses function and alias lookup in every POSIX shell. Also scope the changelog claim: EXIT-trap/background output lands after the completion marker by design and stays visible via handle.output(). * docs(runtime): soften the fence-printf comment per review
5e0e288a Sebastian Müller Remove unused kernel seams (#1835)
Remove unused kernel seams (#1835)
d90062b6 Sebastian Müller refactor(coding-agent): derive available connection models on read (#1853)
refactor(coding-agent): derive available connection models on read (#1853)
0f6a3885 Sebastian Müller refactor(coding-agent): read messageCount instead of a shadow flag (#1852)
refactor(coding-agent): read messageCount instead of a shadow flag (#1852)
378e32d5 Sebastian Müller refactor(coding-agent): remove test-only config cache reset APIs (#1849)
refactor(coding-agent): remove test-only config cache reset APIs (#1849)
8c4ab8f5 Sebastian Müller refactor(coding-agent): centralize the session-path predicate (#1846)
refactor(coding-agent): centralize the session-path predicate (#1846)
90343dca Sebastian Müller fix(coding-agent): trust supervisor-approved session renames in worker mode (#1841)
fix(coding-agent): trust supervisor-approved session renames in worker mode (#1841)