mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-20 17:41:33 -06:00
2b2c11e7486f620b6793a4e40ecb3296ecc2ecdc
80123 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2b2c11e748 |
fix(install): keep stable channel when npm install retries (#124778)
* fix(installer): keep npm channel target immutable Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(install): fail after repeated CLI package install errors Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(installer): verify npm package publication Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(install): satisfy shellcheck for entry validation * fix(installer): link the packaged OpenClaw launcher Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * test(installer): keep retry fixture version-valid Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae --------- Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
1027837d96 | fix(msteams): avoid ambiguous delivery replay (#125127) | ||
|
|
0e3a3aa203 |
refactor: finish canonicalization stragglers (#125056)
* refactor: finish canonicalization stragglers * chore: remove release-owned changelog entry * refactor: narrow SecretRef SDK import |
||
|
|
60f238c5af |
fix(ci): scope the Node toolchain cache to runners that need it
GitHub-hosted images carry Node 24.19.0 in /opt/hostedtoolcache, so hosted jobs resolved from there and never populated the cached root. They still ran a restore that could only miss and then a save whose path did not exist, logging "Path Validation Error: Path(s) specified in the action for caching do(es) not exist" on every hosted job. No entry was ever written, so nothing was poisoned, but the warning is noise and the steps are pure waste on ~30 jobs per run. Gate both steps on runner.environment != 'github-hosted', the signal this workflow already uses for Blacksmith-only behavior, and gate the save on the setup step reporting that a download actually populated the root. That second guard also covers a future self-hosted image whose toolcache clears the floor. Verified on Blacksmith: a satisfying image toolcache leaves the root absent so the save is skipped, and a download populates it so the save runs. |
||
|
|
53cede420f | perf(test): complete managed handoff explicitly (#125129) | ||
|
|
84853266e7 |
fix(ui): widen the review sidebar by default (#125116)
* fix(ui): widen code review panel by default * test(ui): align sidebar layout default --------- Co-authored-by: Peter Steinberger <steipete@gmail.com> |
||
|
|
2e1a9a1a3d | perf(gateway): reduce chat history read-path work (#125123) | ||
|
|
83d279a4c1 |
fix(cli): honor channel resolve agent ownership (#125109)
* fix(cli): honor channel resolve agent ownership Forward explicit channel owners through command-time secret collection and later workspace/channel resolution, preventing AGENT_SELECTION_REQUIRED in multi-agent configurations. * fix(cli): narrow explicit agent option value Use runtime string narrowing for the Commander option so agent-owner forwarding remains assertion-free and satisfies the assertion-safety ratchet. * docs(cli): document channel resolve agent owner |
||
|
|
7b18510e6c |
fix(config): materialize fresh-install defaults for missing config (#125110)
* fix(config): materialize fresh-install defaults for missing config
A missing config file (fresh install) skipped runtime-defaults
materialization on both loadConfig and readConfigFileSnapshot, while an
existing empty {} config got the full defaults (compaction safeguard,
session/cron/model defaults). Out-of-box behavior silently diverged from
the documented defaults until the first config write created the file.
The drift dates to
|
||
|
|
b1e76c4640 | refactor(ui): define review default document (#125105) | ||
|
|
29b105beda |
docs(gateway): record why Control UI admission exemptions exist (#125108)
* docs(gateway): record why Control UI admission exemptions exist * docs(gateway): state the configured-root exemption reason precisely |
||
|
|
1d65e7b449 |
test: default trusted checks to local execution (#125120)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com> |
||
|
|
4e1f26dc18 |
refactor(gateway,ui): one bounded display projection; delete marker strip sites (#124997)
* refactor(gateway,ui): one bounded display projection; delete marker strip sites Persisted transcripts are marker-free since the write-boundary projection (#124793), the historical migration (#124888), and TTS facts (#124913), so display surfaces stop compensating. sessions.list.lastMessagePreview and its siblings (sessions.preview/describe, TUI picker, sessions_list tool, MCP) now share one bounded role-aware projection (240 chars, tool/system/thinking and suppressed control replies excluded, directive-only rows fall through). The web reply chip reads the typed openclawDelivery fact instead of parsing text; chat.history preserves the field to the UI. Post-hoc display strips are deleted across web/TUI/MCP/sessions-list; live streaming cleaners stay. Stale gateway-protocol preview comments corrected; no schema change. Assertion-safety baseline pruned for shrunk files (sanctioned direction). Production net -173, tests net -137. Fixes the sidebar [[reply_to_current]] preview leak and the empty-code-pill overstrip of quoted markers. * fix(agents): preserve restart recovery transcript reads * refactor(gateway): remove obsolete transcript exports * fix(gateway): normalize injected delivery directives * fix(ci): scope projection and recovery checks * chore(ci): shrink plugin SDK surface budgets * test: deflake loaded side question and worker checks * test: align display projection CI fixtures * style: format display projection fixture |
||
|
|
59c661bf66 |
fix(gateway): prevent large history from blocking chat startup (#124994)
* fix(gateway): bound startup history materialization Apply SQLite byte limits before loading history payloads and share a yielded, fingerprinted Claude CLI snapshot across concurrent startup clients. Preserve marker, cursor, redaction, and external identity semantics, and clarify that shrink-only ratchet updates need no separate approval. * test(browser): await all lazy command groups * fix(gateway): bound history snapshot state * fix(gateway): preserve oversized history responsiveness |
||
|
|
73ab74eccc | fix(discord): preserve routed agent for realtime voice (#125111) | ||
|
|
6b86199892 |
fix(ui): keep session status icons visible (#125096)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com> |
||
|
|
3010318ba3 | fix(android): isolate debug app installs (#125099) | ||
|
|
ac5c8be001 | fix(ui): keep agent terminals backgrounded (#125101) | ||
|
|
1204225303 | chore(scripts): enforce erasable TypeScript syntax (#125104) | ||
|
|
c26eda0620 |
feat(approvals): add request kind discriminant (#125084)
* feat(approvals): add request kind discriminant * test(approvals): expect normalized legacy request |
||
|
|
76b26c31dc |
fix: keep device identity reads lock-free (#124745)
* fix: keep device identity reads lock-free Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * feat(lint): enforce import ordering and deduplication (#124730) * refactor(imports): dedupe and hoist imports * feat(lint): enforce import/no-duplicates and import/first * feat(voice-call): sessionScope "main" routes calls into the agent main session (#124708) * feat(voice-call): add sessionScope "main" for main-session call routing Inbound and outbound calls can now share the configured agent's main session instead of a dedicated voice session. The new scope resolves through the existing explicit-key canonicalization path, honoring core session.mainKey and global-scope aliasing. The inbound webhook path now forwards coreSession like every other resolver call site. * style: format events.test.ts * test(voice-call): split events.test.ts under the max-lines cap * fix(cli): forward agent name through setup (#124740) Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 Co-authored-by: Amp <amp@ampcode.com> * refactor(mcp): centralize tool filter policy (#124739) * fix(agents): preserve restart-unsafe delivery evidence (#124737) * fix(ci): snapshot synced Testbox candidates (#124743) Co-authored-by: Amp <amp@ampcode.com> * fix(ci): keep QA evidence output repo-relative (#124760) * fix(cli): allow hook toggles to select an agent (#124761) * test(upgrade): drop retired agent context assertion (#124765) Amp-Thread-ID: https://ampcode.com/threads/T-01a00a6a-b64e-74a5-8b15-2d3b966a468d Co-authored-by: Amp <amp@ampcode.com> * fix(skills): report missing ClawHub skills as not found (#124764) * feat(codex): show sessions from additional homes (#124660) * feat(codex): register additional session homes * fix(codex): preserve automatic session homes * docs(codex): explain automatic home discovery around sessionCatalog.homes --------- Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com> * fix(qa): preserve effective fast mode (#124762) Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 Co-authored-by: Amp <amp@ampcode.com> * fix(ui): keep Control UI device identity working on plain-HTTP origins (#124724) * fix(ui): keep Control UI device identity working on plain-HTTP origins @noble/ed25519 defaults its SHA-512 provider to crypto.subtle, which browsers gate to secure contexts, so device identity silently vanished on http:// LAN dashboards and connects fell back to shared-credential auth with no pairing. Wire a lazy pure-JS @noble/hashes fallback for SHA-512 and the fingerprint SHA-256, and drop the isSecureContext gate in the connect path. Secure contexts keep the platform digests and pay no startup bytes: the fallback loads as its own lazy chunk, kept out of the gateway-runtime startup chunk on purpose. * test(ui): cover device identity minting and signing without crypto.subtle New jsdom regression suite fails on pre-fix code (subtle-less crypto stub with getRandomValues, which real insecure contexts keep). Rewrites the gateway connect tests that previously asserted the device-less insecure fallback: an insecure context now attaches a device identity. * docs(web): plain-HTTP dashboards now pair with a device identity The signing key never crosses the wire, so HTTP+pairing is strictly stronger than the old HTTP token-only fallback; HTTPS (Tailscale Serve) stays the recommendation for transport privacy. * fix(ui): drop unnecessary boolean literal compare in secure-context timing meta * test(ui): declare device.id on the connect-frame test shape * test(ui): split the subtle-less scope-upgrade e2e into the two real invariants Without crypto.subtle the browser can now sign, so the banner offers the explicit admin upgrade; manual-only guidance is reserved for browsers that cannot mint an identity at all (no WebCrypto RNG). Also corrects the connect-path comment: blocked storage yields an ephemeral identity, only a failed mint degrades device-less. * fix(ui): address review findings on the HTTP device-identity path - Storage-blocked pages keep one stable in-memory identity per page lifetime instead of minting a fresh unpaired key on every reconnect, and a write-rejecting store no longer fails the mint (regression tests bite pre-fix). - Connect timing now reports the real browser secure-context fact via a shared browserSecureContext() helper instead of inferring it from device-identity presence. - Docs state the accepted trusted-proxy contract: browsers attach a device identity on every origin, so first connects follow the standard pairing flow (deviceAutoApprove or a one-time approval); device-less admission remains only for browsers that cannot mint an identity. * refactor(ui): trim the connect-path additions under the max-lines cap * fix(line): retry lost pushes without duplicating an accepted send (#124464) A LINE push made exactly one attempt, so a transient provider or transport failure dropped the reply even though retrying was safe to do. Retrying alone would have duplicated a send LINE already accepted, so every push now carries an X-Line-Retry-Key and reuses it across attempts: LINE answers a replayed key with 409 and the accepted request's sent messages, which resolves to the original delivery instead of a second message. Retries follow LINE's documented policy - server errors and transport failures only, never 2xx, 409 or any 4xx - and run through the shared channel API retry runner in strict mode. Replies stay single-attempt because LINE offers no retry key for them. * fix(outbound): record queue-write loss and fail every payload on prep abort (#124756) * fix(outbound): record queue-write loss and fail every payload on prep abort Two silent-observer gaps in the outbound queue admission path: 1. Best-effort staging/queue-write failures were swallowed with a bare 'return null'. The send proceeded live-only, so a crash mid-send lost the message with zero forensic trace of why the write-ahead row was missing. Every sibling degradation on this boundary logs (persistQueuedPreSendState, the dispatch-refresh fallback); this one now warns with channel/target and the error. 2. Batch preparation failure emitted message_sent for only the first payload while audit emitted per-payload terminals, so plugins with message_sent hooks saw 1 failure for an N-payload batch. The failure path now emits one hook failure per logical payload, matching the audit terminals and the recovery sibling's queuedTerminalFailureEvents. The unused error.payload pick and its OutboundPayloadPreparationError import went with it. Regressions: queue-write warn asserted in the existing best-effort fallback test; new multi-payload prep-failure test asserts 2 hook failures. Both fail pre-fix. * chore(outbound): keep OutboundPayloadPreparationError module-local Last external consumer went away with the per-payload emit; the deadcode:exports gate rejects unused exports. * refactor(gateway): drop dead session-subscriber registry surface (#124754) * refactor(gateway): drop dead session-subscriber registry surface getForConnection and both registry clear() methods had no production callers — only server-chat-state.test.ts consumed them (verified by repo-wide grep incl. plugin-sdk). The recency-sorted connToSessionKeys index existed solely so getForConnection returned keys in subscription order, an ordering nothing read, rebuilt via toSorted() on every subscribe/unsubscribe/settle — including the provisional-replay settle path. unsubscribeAll now reads the reverse index directly from connToSessionRecency's keys (same contents, no ordering), removing the per-call O(k log k) rebuild and the duplicate map. Tests assert through get()/getApprovals(), the production read paths, per test-audit norms. Behavior-neutral: subscription state transitions and event-visible delivery unchanged; chat-state, broadcast, node-subscription, instance-runtime, agent-events, session-events suites pass. * test(gateway): fix ETXTBSY flake in workspace-sync candidate bounding The test rewrote its mock git script between two createGitTransferList calls. On Linux CI the second spawn can race a lingering fork of the first child still holding the script's write fd, failing exec with ETXTBSY. Write the script once; vary the entry count through a data file the script reads instead. * fix(config): preserve migration notice paths (#124719) * fix(runners): preserve device sessions through lifecycle faults (#124744) * test(runners): cover paired-node lifecycle wire * fix(runners): preserve retryable device lifecycle * test(runners): keep wire fixture internals local * fix(runners): stop fallback on device capacity * fix(doctor): keep identity probe within typed storage APIs Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(openai): keep setup auth choices consistent (#124729) * fix(openai): centralize setup auth metadata * refactor(openai): overlay auth hooks in place * fix(tasks): cancel subagents through gateway (#124752) * fix: honor context caps on Codex-routed models (#124735) * fix(codex): forward authored context caps * test(codex): keep binding fixtures uncapped * fix(agent-harness): separate authored context cap * fix(config): render actionable validation errors (#124763) * fix(config): render actionable validation errors * fix(config): cover service and gateway validation * docs: remove agent-hierarchy guardrail from VISION roadmap Agent-created agents (durable roster entries with provenance) are now planned work, so the blanket VISION.md guardrail against agent-hierarchy frameworks no longer reflects direction. The adjacent guardrail against heavy duplicative orchestration layers stays. * fix(gateway): preserve worker lifecycle failure reasons (#124774) * fix(cli): explain empty directory lookups (#124753) * fix(cli): explain empty directory lookups instead of printing nothing * fix(cli): distinguish unsupported self lookups * fix(codex): honor session node exec host (#124777) * refactor(line): replace nine-marker prompt DSL with typed rich messages (#124755) * refactor(line): replace nine-marker prompt DSL with typed rich messages Delete the LINE plugin's double-bracket marker language (quick_replies, location, confirm, buttons, media_player, event, agenda, device, appletv_remote) and its parser. Portable interactions now flow through the existing presentation-block seam (renderPresentation, matching Discord and Feishu); LINE-specific cards ride closed channelData.line schemas mapped to the existing Flex renderers. Prompt section shrinks to four capability lines and explicitly de-fangs marker text. Removes the stale assertion-safety baseline entry for the deleted parser. Production LOC net -69, tests net -433. Suite: 510/510 green. * fix(line): declare rich message schema dependency * fix(line): satisfy rich message type checks * docs(line): mark card fragments as partial * feat(ui): surface approvals passively and redesign the approval card (#124767) * feat(ui): surface approvals passively and redesign the approval card Approvals no longer auto-open the centered modal: the queue is reachable only through the sidebar attention chip, while the owning session shows the inline card and other sessions surface via the session-row shield icon, agent badges, and the chip. Deletes the inline-vs-modal exclusion machinery (modalApprovalQueue, inlineApprovalId, forceShowAll) and makes modal dismissal close the view instead of denying the active request. Card: severity now drives the accent color instead of a table row, plugin/agent render as header chips, the session key moves behind a collapsed Details disclosure (modal only), and low-value exec rows (Resolved/Security/Ask) collapse into the same disclosure. The codex app-server bridge stops duplicating the session key into description text; the envelope already carries it. * fix(ui): gate settings Escape on the approval dialog's recorded open state ClawSweeper caught that shouldIgnoreSettingsEscape still inferred an open approval dialog from queue non-emptiness; with passive approvals a pending queue no longer implies a visible dialog, so settings would swallow Escape. The exec-approval element now records dialogOpen as a fact and the guard reads it. * refactor(channels): carry typed approval-prompt bindings through signal/imessage send seams (#124742) The Signal and iMessage channel plugins inferred approval prompts by regex-sniffing rendered message text (header matching like 'Exec approval required', /approve command parsing), violating the transport-only channel doctrine: approval actions must stay typed until channel encoding. The typed envelope already existed (channelData.execApproval with approvalId/approvalKind/allowedDecisions) and every payload-level delivery path consumed it; the regex paths were redundant re-derivation at the raw send seam plus restart recovery for in-memory iMessage poll state. - Signal: delete send-level prompt sniffing entirely; all approval sends already flow through typed structured-payload or native-handler paths. - iMessage: sendMessageIMessage takes a typed approvalPrompt binding (id/kind/decisions) from the native approval handler instead of an approvalKind flag plus text re-parsing. - iMessage poller: persist pending poll targets in the plugin keyed store so restart recovery no longer regex-scans chat history; typed recent-chat discovery for handle-only DM targets stays. Split poll-target ownership into approval-reaction-poll-targets.ts (max-lines). - Plugin SDK: remove extractApprovalReactionPromptBinding — beta-only surface, never in a stable release, so no deprecation window applies; AGENTS.md now records that rule. Accepted tradeoff: approval prompts delivered by a pre-upgrade process are not rediscovered from chat text after restart (<=24h transient state; persisted reaction bindings and event-driven tapbacks still work). * fix(ci): select aggregate QA evidence by manifest (#124802) * docs: correct code mode runtime contract (#124792) Amp-Thread-ID: https://ampcode.com/threads/T-01a00b7c-b9f0-73d5-8fb7-e619e8e458e1 Co-authored-by: Amp <amp@ampcode.com> * fix(ci): invalidate extension boundary cache for attempt types (#124800) * refactor(plugin-sdk): consolidate session catalog families (#124801) * fix(memory): fail corrupted index commands (#124770) * fix(memory): fail corrupted index commands * fix(memory): preserve promotion output limit * fix(memory): keep ranked promotion output * feat(codex): name additional session-catalog homes (#124807) * fix(state): copy-safe agent database registry via state-relative paths (schema v9) (#124728) * fix(state): store in-root agent database registry paths relative to the state dir (schema v9) Copied state directories retained stale absolute agent database registry rows. The combined gateway store then merged old and new copies, causing every sessions.list request to fail with SessionCanonicalKeyMigrationRequiredError. Schema v9 stores in-root registry paths relative to the state directory; migration rewrites eligible rows, deletes stale duplicates, and preserves external paths. * fix(voice-call): describe state-relative registry migration * fix(state): preserve registry locator traversal * test(macos): move PortGuardian schema-version boundary to v9 The store opens any state database up to maximumSupportedSchemaVersion, which the schema v9 bump moved from 8 to 9. Shift the supported/newer partition in the boundary test accordingly. * fix(state): re-anchor copied default-layout registry rows instead of deleting them Resolve the ClawSweeper P1 by preserving genuine external default-layout registrations, re-anchoring copied rows when an in-root counterpart exists, and deleting only dual default-layout conflicts. * fix(upgrade): retain owners in legacy cron stores (#124809) Amp-Thread-ID: https://ampcode.com/threads/T-01a00a6a-b64e-74a5-8b15-2d3b966a468d Co-authored-by: Amp <amp@ampcode.com> * feat(tools): prompt proactive widget use (#124810) * fix(ui): stop stale clients from acting connected (#124772) * fix(ui): stop stale clients from acting connected Carry reload metadata on terminal Control UI build rejections, render an explicit refresh-required recovery state, fence reconnect-only actions, and surface disconnected approval failures with accessible modal controls. * fix(ui): preserve reconnecting session drafts * fix(ui): preserve offline preference intent * fix(ui): return owned fallback digest bytes * test(ui): follow passive approval presentation * fix(ui): distinguish stale builds from protocol mismatches * style(ui): format gateway recovery phase * refactor(validation): type producers and drop internal re-validation — pilot lane C (#124808) * fix(cli): restart disabled installed services (#124786) * refactor(agents): persist directive facts at the assistant write boundary (#124793) * refactor(agents): persist directive facts at the assistant write boundary Assistant final text is now stripped of inline delivery directives once, at the SessionManager append boundary, with the parsed facts persisted as a typed openclawDelivery field on the assistant message (openclawDeliveryMirror precedent, inside event_json — no schema change). Live session state is replaced with the persisted canonical bytes so same-run continuations and next-turn store rebuilds never diverge (prompt-cache invariant). Delivery and restart recovery consume the stored facts instead of re-parsing persisted text; pre-upgrade in-flight messages without facts intentionally get no text-parse fallback (commented tradeoff at the read site). Directive parsing is now code-region aware, so markers quoted in inline code or fences neither parse nor strip — fixes the empty-code-pill display bug. The undocumented reaction marker DSL ([[react:]], [[react_to_current:]]) is deleted; structured message-tool reactions remain the canonical path. Stale assertion-safety baseline entry removed with the parser. Production net -10, tests net +38. Focused suites: 9,068 passed; pre-fix regressions fail for the intended reasons. Codex autoreview clean. * fix(agents): satisfy directive persistence gates * fix(config): drop unused directive export * fix(agents): preserve indented directive examples * perf(test): remove ClickClack scheduler waits (#124819) * refactor: split max-lines pilot files and retire suppressions (#124813) * fix(runners): align reclaim results with runtime (#124791) * refactor(runners): prepare placement move targets * fix(runners): preserve normalized dispatch targets * style(protocol): format reclaim result type * fix(ui): make light-theme diff syntax readable (#124814) Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com> * fix(ci): render only aggregate QA evidence (#124823) * fix(ui): show session changes in review panel (#124824) * fix(gateway): stop closed clients from restoring session subscriptions (#124771) * fix(gateway): reject closed session subscribers * test(gateway): type subscription race params * test(gateway): use public subscription assertion * fix(ci): invalidate SDK declarations on attempt types * chore(ci): align boundary cache comment with main * fix(gateway): surface failed node event delivery (#124798) * fix(gateway): surface failed node event delivery * fix(plugin-sdk): preserve authored context cap * fix(mcp): make Codex approval dead ends actionable (#124766) * fix(mcp): make Codex approval dead ends actionable * fix(mcp): preserve native approval fallback * fix(mcp): configure saved approval modes * fix(mcp): preserve saved Codex metadata * style(mcp): simplify saved metadata spread * improve(ui): one primary composer button, Enter-steer, Esc-stop, quiet mic, no transcript focus ring (#124799) * fix(ui): drop the transcript keyboard-focus ring The .chat-thread:focus-visible 2px inset outline (added in #120693) boxed the entire main content whenever the transcript took keyboard focus (Shift+Tab, closing transcript search) and read as a broken border that stopped above the composer. The transcript stays keyboard-focusable for scroll keys; it just paints no focus box. Accepted tradeoff: no visible focus indicator on the scroll container. * feat(ui): single primary composer button with Enter-steer and Esc-stop The composer now renders exactly one primary action, always rightmost: - draft or attachments present: one send-shaped button whose label follows the session follow-up mode (Send / Queue / Steer); the stop button no longer renders beside it - empty while a run is active: Stop (tooltip "Stop (Esc)"); Escape in the composer aborts the run, deferring to reply-clear and menu precedence - empty while idle: disabled send labeled "Write a message to send." Enter on an empty composer while a run is active steers the oldest steerable queued message — Enter queues, Enter again steers — using the same eligibility predicate as the queue chip's Steer action (shared steerableQueuedMessage helper). The mic/dictation control is now always a compact secondary control left of the primary instead of morphing into the primary when the composer is empty. Dead ChatRunControlsProps fields (hasMessages, onExport, onNewSession, showPrimary, showSecondary) and the composer exportMarkdown wrapper are removed; the assertion-safety baseline entry for chat-composer.ts shrinks 8 -> 7. * refactor(ui): quiet the idle composer mic The idle mic was an accent-tinted two-segment pill (mic + permanently visible device-picker chevron) that outweighed the primary action. It now matches the attach button's ghost weight: transparent idle, subtle hover, and the accent treatment is reserved for the recording and talk-active states so the idle -> recording escalation reads stronger. The device picker chevron collapses at idle and reveals on hover/focus-within (kept always visible on coarse pointers, where dictation matters most; reveal transition disabled under prefers-reduced-motion). The idle tooltip now teaches the gesture split — "Tap to talk · Hold to dictate" — while the aria-label stays "Start voice input". * refactor(ui): split composer keydown and oversized composer test files chat-composer.ts crossed the 700-line oxlint budget after the keyboard additions; the keydown handling (menu routing, history keys, Escape-stop, Enter steer/send) moves to chat-composer-keydown.ts behind a typed deps factory. The composer unit tests split their primary-action/keyboard coverage into chat-composer-actions.test.ts over a shared chat-composer.test-support.ts, and the catalog/model-discovery e2e cases move to chat-composer-catalog.e2e.test.ts. Pure moves, no behavior change; no max-lines suppressions or baseline entries added. * chore(ui): keep composer test-support ComposerProps internal The split exported a type nothing imports; the dead-export scan is a merge gate. * fix(ui): narrow composer keydown target and adapt keyboard tab-order proof The keydown split moved two bare textarea assertions into a zero-baseline file; a single instanceof narrowing at the handler entry replaces both (the handler only binds to the composer textarea). chat-composer.ts's own assertion baseline ratchets 7 -> 5. The pointer-activation e2e now walks the real post-redesign tab order (mic, focus-revealed picker trigger, then primary send) instead of assuming one Tab. * fix(ui): gate Enter-steer on the queue chip's visible availability ClawSweeper P1: the Enter path only required an abortable run, so offline Enter swallowed the keypress and invoked a steer lifecycle that returns at !connected with no visible outcome, while the queue chip's Steer button was correctly hidden behind connected && canCompose. The keydown path now mirrors the chip's exact boundary (connected, canSend, abortable, visible queue surface including sessionKey-less pending rows). * refactor(ui): align approval page with redesigned approval card (#124816) * refactor(ui): align approval page with redesigned approval card Follow up #124767 by carrying severity accents and identity chips onto the standalone approval page. Remove the unused execApproval.labels severity, plugin, and agent keys. * refactor(ui): keep approval-page helpers in repo idiom Reverts drive-by rewrites from the build pass: restore the exhaustive decisionLabel switch (the ternary lost the never check), the early-return appliedDecisionMatches, explicit gatewayCode comparisons, and align the severity mapping shape with the sibling exec-approval-card.ts. * test(ui): type approval severity fixtures * test(scripts): wait for a parseable descendant pid in Bun smoke cleanup The readiness gate only required the descendant pid file to exist, but existsSync can observe it between open() and write(); a loaded runner then reads an empty file and the integer assertion flakes (seen on PR #124816 CI run 31971191374). Readiness now requires parseable content. * perf(webui): reuse the chat metadata catalog across pages (#124794) * refactor(webui): centralize chat metadata caching * test(webui): cover shared chat metadata store * refactor(webui): move ChatMetadataResult type to its store owner * fix(webui): let the metadata store own revalidation lifetime * fix(webui): satisfy no-promise-executor-return in retry delay * fix(browser): stop local actions when agent turns are cancelled (#124795) * fix(browser): cancel local actions with agent signal Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 * fix(agent-harness): expose authored context cap Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 * chore(agent-harness): drop redundant context-cap override Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 --------- Co-authored-by: Amp <amp@ampcode.com> * improve(ui): make chat disclosures compact (#124832) Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com> * fix(gateway): share generated session titles with worktree names and start title work at dispatch (#124787) Worktree sessions now derive their worktree/branch name from the same concise generated title the sidebar shows (bounded 8s wait, raw-prompt slug then crustacean fallback), persisted once as displayName so the chat-send pass never duplicates the model call. Dashboard title scheduling moves from the dispatch chain's finally (after the whole first turn) back to dispatch start, so long or interrupted first turns no longer leave sessions silently untitled (regression from #122471). slugifyWorktreeTitle truncates at word boundaries; dead generatedDisplayName plumbing removed. * fix(browser): support Chrome Web Store native bootstrap (#124775) * fix(browser): support Chrome Web Store native bootstrap * chore: keep browser release note in PR body * docs(browser): document Store identity trust boundary * docs(browser): correct Store recovery guidance * fix(media): bound image-optimize fetch headroom to the image cap (#124838) When a caller passed an explicit maxBytes with optimizeImages on (the default), the source-read bound was inflated to max(maxBytes, 100MB document cap). A channel with a 5MB attachment cap therefore let a hostile or oversized URL buffer up to 100MB before the final size check — 20x resource amplification, and the inflation applied before content classification, so it was not limited to images. The inflation exists so oversized-but-compressible originals can be fetched and compressed under the delivery cap. Size that headroom off the thing that justifies it: 4x the 6MB image cap (24MB), enough for large phone photos, instead of the document cap. Accepted tradeoff (named at the constant): originals above 24MB that would have compressed under the cap now fail; the fetch error names the bound. Callers without an explicit cap keep per-kind defaults. Live proof on a real localhost HTTP server (no mocked fetch): an 8.1MB PNG under a 5MB cap compresses to 3.75MB and delivers; a 30MB-declared image is rejected at the Content-Length precheck in 7ms with 'content length 31457280 exceeds maxBytes 25165824'. Regression: headroom-bound test fails pre-fix (30MB passes the old 100MB bound); companion test proves compression headroom still works. * fix(channels): route direct DM replies to sender (#124837) Default direct-message reply context to the authenticated sender address so targetless Reef and Nostr replies do not resolve to the local recipient. * feat(auto-reply): record message-tool mute outcomes (#124830) * feat(auto-reply): record message-tool mute outcomes * fix(auto-reply): require source delivery evidence * test(infra): preserve historical agent schema fixtures * fix(agent): preserve implicit roster in configless exec (#124805) Amp-Thread-ID: https://ampcode.com/threads/T-01a00b7c-b9f0-73d5-8fb7-e619e8e458e1 Co-authored-by: Amp <amp@ampcode.com> * fix(delivery): unify terminal settlement ownership (#124825) * fix(delivery): unify terminal settlement ownership Treat identityless adapter returns as potentially visible across channel, queue, and cron paths. Let recovery own terminal completion so ambiguity persists as notice debt instead of being double-settled or silently suppressed. Co-authored-by: ruel225 <ruel225@users.noreply.github.com> * refactor(delivery): narrow terminal internals Remove now-unused internal exports after terminal-settlement ownership was consolidated. * test(tts): preserve message runtime exports Import and spread the actual message runtime so the focused mock retains every runtime binding while overriding only the durable send core. --------- Co-authored-by: ruel225 <ruel225@users.noreply.github.com> * fix(ui): give queued-outbox badges their own outbox icon (#124842) The sidebar queued-message badge and the composer queue reused the clock glyph that also marks attached automations, so a session with both showed two identical clocks distinguishable only by tooltip. Add an outbox tray icon (Lucide inbox with the roof swapped for a rising arrow) and use it for queued-to-send surfaces; the clock stays automation/cron-only. The mock dev fixture now flags one session with hasAutomation so the badge renders in mocked-dashboard proofs. * refactor(plugin-sdk): extract stream and SecretRef primitives (#124835) * refactor(ui): derive cron types from gateway protocol (#124827) * refactor(ui): derive cron types from gateway protocol * fix(protocol): preserve cron session target type * fix(ui): keep sent images visible through history handoff (#124839) * fix(memory): report indexed SQLite sessions (#124834) * fix(memory): report indexed SQLite sessions * refactor(memory): remove unused state path export * refactor(validation): consolidate boundary guards into schemas (#124820) * refactor(validation): consolidate boundary guards into schemas — pilot lane B * fix(meetings): reject non-object browser status * perf(test): remove Gmail watcher shutdown wait (#124851) * refactor(types): discriminated unions for internal contracts — pilot lane A (#124845) * refactor(slack): mark approval headers with typed block ids (#124841) * feat(ui): add steer-now composer shortcut (#124826) * fix(slack): drop the tool-call receipt from finished progress cards (#123851) The Block Kit session card terminalized into a '🛠️ N tool calls · ⏱️ Ns' footer, leaving a per-turn receipt in the Slack transcript on the default progress path. PR #122976 deleted the same receipt from the native progress surface but left this sibling rendering it. Finished cards now keep only the durable diff stat and the session link; tool-call and elapsed counters stay live working state. Also corrects the documented channels.slack.streaming.mode default, stale since #122552. * fix(agents): keep queued followups from missing post-compaction context (#124850) * fix(auto-reply): order post-compaction context before followups Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 * test(auto-reply): clean compaction workspace fixture Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 --------- Co-authored-by: Amp <amp@ampcode.com> * fix(test): propagate parent heavy-check ownership (#124859) Amp-Thread-ID: https://ampcode.com/threads/T-01a00b7c-b9f0-73d5-8fb7-e619e8e458e1 Co-authored-by: Amp <amp@ampcode.com> * fix(cli): emit one JSON failure contract for --json invocations (#124849) * fix(cli): unify JSON failure output * test(cli): update skills verify failure envelope * fix(gateway): preserve prepared plugin metadata under load (#124844) * fix(gateway): preserve prepared plugin metadata under load * fix(gateway): project metadata before catalog preparation * test(agents): assert projected startup metadata * test(gateway): bind load probes to each finalization wave * docs(ci): record artifact checkout experiment * perf(test): reuse postpublish file-cap fixture (#124871) * fix(protocol): model cron run delivery trace (#124856) * fix(protocol): model cron run delivery trace * chore(protocol): refresh generated cron run model * test: replace assertion chains with typed fixture builders — wave 2 (#124865) * refactor(security): consolidate path containment onto canonical fs-safe guard (#124870) * refactor(security): expose canonical path containment modes * refactor(agents): use canonical path containment guard * refactor(security): consolidate core path containment sites * refactor(plugins): consolidate path containment sites * test(security): cover canonical path containment behavior * fix(gateway): persist agent turns before acknowledgement (#124857) * fix(gateway): persist agent turns before acknowledgement * fix(gateway): revalidate exec approval handoffs * docs(gateway): clarify durable session ownership * fix(gateway): reject stale transcript admission targets * fix(ui): show recovery when Control UI does not render (#124861) * fix(ui): retire bootstrap fallback after render * test(ui): avoid returning from Promise executor * fix(qa): recover repeated gateway restarts through channel ingress (#124746) * fix(qa): repair repeated gateway restart recovery * test(qa): satisfy restart recovery checks * fix(audit): rekey repeated recovery identity * fix(plugin-sdk): expose authored context cap * test(android): synchronize process tree readiness * fix(ui): restore task count badge (#124840) * fix(ui): align update status card spacing (#124878) * fix(browser): cancel node discovery with tool runs (#124880) Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89 Co-authored-by: Amp <amp@ampcode.com> * perf(webui): render cached model catalog while the chat pane refreshes (#124868) * perf(webui): render cached model catalog while the chat pane refreshes * test(webui): fix seed-test types and shrink assertion baseline * fix(state): report v9 registry migration row decisions (#124862) * fix(state): report v9 registry migration row decisions in doctor and logs * fix(state): consume registry migration summary type * fix(state): avoid registry path observer import cycle * fix(workboard): include actual length in bounded-string error The shared normalizeBoundedString helper in extensions/workboard/src threw an opaque error like 'comment body must be 2000 characters or fewer.' whenever an oversize string hit any bounded field. Agents that posted a long run summary or oversized link URL had no way to tell how far over the limit they were, so they could not retry with a trimmed payload. Include the actual length in the error so the message tells the agent exactly what to do next: comment body must be 2000 characters or fewer (got 3502). The format applies uniformly to every bounded field routed through this helper (labels, link URL, link title, link target, comment body, title, notes, worker log message, session key, run id, protocol violation detail, etc.) since the helper is the single canonical owner of the message. Cover the new format with a focused unit test that pins the regex for the comment-body repro from #118845 and exercises the six other bounded fields listed in the issue. Update the existing gateway.test.ts assertion to allow both the old and new format so the format change is a forward-compatible improvement. * test(workboard): align matrix with real normalizeBoundedString consumers ClawSweeper flagged that the prior matrix at line 31-48 tested labels/title/notes by manually invoking normalizeBoundedString, even though those fields use the independent normalizeTitle, normalizeNotes, and normalizeLabels functions (each with its own generic message). A regression that drops the (got N) suffix from normalizeBoundedString would not be caught for those three surfaces — operators would still see the old opaque error. This commit narrows the matrix to only the consumers of the shared helper (comment body, link title, link target, link URL, card id) and restores the exact labels gateway assertion that should match the unchanged normalizeLabels error. Verification: 9/9 inline Node 18 AST harness (node /tmp/verify-pr-118888-v77.mjs); parent-commit proof-gate (pre-PR helper without the got suffix) fails 4/9 of the post-fix expected messages. Closes ClawSweeper review on PR #118888 (P2 + P3). * test: cover Workboard length errors at gateway boundary * docs: note length-aware Workboard errors (#118888) * perf(ci): split Windows CI two ways instead of one serial lane `checks-windows-node-test` ran the whole 222-266s Windows body in a single Blacksmith lane, so every run that scheduled it finished at 287-334s against a ~180s plateau. Measured across 45 canonical main runs it was the wall in all seven runs that triggered it (324-519s vs a 210s median elsewhere). Blacksmith's Windows class admits exactly 2 concurrent jobs (run 31865243804), which is why the earlier 3-part split failed: its tail queued 211s behind a finished part. Pin the split width to that measured capacity instead. The two parts are balanced by measured per-project wall time -- part 1 keeps the old list 1 plus list 2's non-infra projects (~108s), part 2 takes list 2's infra project plus the old list 3 (~112s) -- so both land near 113s and the lane stops setting the wall. One canonical partition now serves every backend; the github-mode/dispatch 3-part variant and its separate file inventory are gone, along with the single-lane `task: test` case and the per-row `matrix.runner` the collapsed lane needed. The complete 65-file Windows inventory is preserved exactly, and the guards pin the width on both sides (mutation-checked: restoring 3 parts fails the matrix guard). * fix: stop forked commands after Gateway timeouts (#124081) * fix: stop service child trees before timeout completion * fix: preserve service child root results during cleanup * test: isolate relay selection from linux spawn wrapping * refactor: keep service anchor payload internal * test: validate lifecycle probe pid output * fix: close service child adversarial races * fix: preserve service startup failures * fix(process): flush service output before root result * fix(process): bound cleanup on held output * chore(process): satisfy promise executor lint * fix(process): finish cleanup after lineage loss * fix(process): retain relay output before subscription * fix(ci): register service child runtime entries * fix(ci): expose relay safety invariants * fix(process): preserve service cancellation grace * test(process): prove service grace on macOS * fix: prevent clipped session selections and Code Mode timer crashes (#124879) * fix(agents): support timers in code mode * fix(ui): keep selected sessions clear of scrollbars * fix(agents): propagate timer cancellation after resume --------- Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com> * fix(ui): reveal clipped session history (#124866) * fix(ui): reveal clipped session history Show a persistent earlier-history action for paginated sessions and reveal loaded content without chaining observer fetches. Related: #110771 * refactor(ui): split chat history support * fix(cli): keep internal error causes out of operator output (#124887) * fix(skills): expand explicit references on agent turns (#124784) * fix(skills): expand explicit references on agent turns Route generic Gateway, CLI, webhook, and local agent turns through the same explicit skill-reference renderer as channel auto-replies. Keep original transcript text, preserve unknown slash behavior, and fail visibly for allowlist-hidden skills. Maintainer review: scoped Option 1 — generic agent turns expand both $skill-name and leading /skill-name args through shared skill rendering; they do not run the channel command dispatcher, and all other slash commands retain their existing behavior. * fix(skills): bound explicit reference prompts * fix(skills): prefer allowed reference collisions * fix(skills): preserve command invocation boundaries * fix(skills): reject hidden channel slash commands * perf(skills): skip literal dollar discovery * fix(ui): replace the broken terminal tab underline (#124875) * fix(ui): redesign dock panel tabs * fix(ui): remove stale terminal tab overrides --------- Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com> * fix(tui): close selection overlays and report rejected handlers (#124876) openSelector's onSelect fired the async handler with void and only closed the overlay after a successful await. A rejecting handler (e.g. setAgent -> setSession against a failing gateway) left the selector stranded open with an unhandled rejection: the TUI froze on the picker with no visible cause — a silent dead-end. Root cause: failure path missing from the overlay lifecycle. The handler now catches, surfaces the cause via chatLog, and always closes the overlay. Regression: /agent selection with a rejecting setSession asserts the overlay closes and the cause reaches the chat log — fails pre-fix. * fix(ui): make terminal open failures retryable (#124890) * fix(sandbox): surface list probe failures instead of empty results (#124881) sandboxListCommand and fetchAndFilterContainers swallowed backend and registry probe failures with catch(() => []). A broken Docker daemon or corrupt registry rendered as 'No sandbox runtimes found.' — and in recreate, filtered an entire fleet down to nothing — indistinguishable from a clean empty state. --json emitted a success envelope for a failed probe. Root cause: failure collapsed into the empty success shape at the consumer. The listers now propagate; the sandbox CLI runner already owns the error path (message + exit 1), and the new --json failure contract ( |
||
|
|
a3eb8787ff |
fix(cli): keep offline gateway RPCs read-only (#125102)
Gateway health, suspend, and resume now preserve shared SQLite state when the target is unreachable. Related: #101290 Follow-up to #123674 |
||
|
|
f77d2ec3a8 | fix: stop repeated static catalog manifest scans (#125090) | ||
|
|
35695cb3bc |
fix(test): intersect scoped CLI filters with each lane's own scope (#125004)
narrowIncludePatterns returned the caller's CLI pattern whenever it overlapped
a lane's include list, instead of intersecting the two. A directory argument
therefore replaced the lane's curated scope with a broad glob:
pnpm test src/plugins
-> unit-fast include became ["src/plugins/**/*.test.*"] instead of its
60 curated files
-> contracts-plugin include became ["src/plugins/**/*.test.*"] instead of
["src/plugins/contracts/**/*.test.ts"]
Both lanes run isolate: false, so every re-admitted file shared a worker with
unrelated files. unit-fast re-admitted exactly the files it excludes for being
stateful (module mocking, dynamic import, filesystem state), and contracts-plugin
pulled in every sibling test outside contracts/. That produced nondeterministic
cross-file pollution: failures that moved between files and lanes run to run,
reproduced in neither isolation nor CI.
Keep the lane's own pattern when it is rooted deeper than the CLI selection,
otherwise keep the CLI pattern. Equal-depth selections are unchanged, so the
existing scoped-config expectations still hold.
Coverage is unchanged; only duplicate execution is removed. `pnpm test src/plugins`
went from 1171 file-executions (3.4x duplication over 346 files) to 344 — the two
remaining files are .e2e.test.ts, excluded by the shared config by design.
|
||
|
|
2915e563d6 |
feat(workboard): show full boards on session dashboards (#125094)
* feat(workboard): full-board dashboard widget
Adds a third trusted plugin widget kind, workboard:board, rendering the
complete Kanban board (all columns, live plugin.workboard.changed
refresh) inside a session dashboard. Props {boardId} scope it to one
board; without it the widget shows every board, matching workboard:mini
semantics. Card rendering reuses the workboard page renderColumn with an
explicit surface option so page and widget cannot drift; the shared
board filter moved to ui/src/lib/workboard/board-filter.ts. Mutations
follow the connection's canMutate; read-only connections get a
view-only board.
Proof: pnpm test ui/src/lib/board ui/src/pages/workboard
ui/src/lib/workboard extensions/workboard (9,494 passed), i18n baseline
green, autoreview clean (codex/gpt-5.6-sol). tsgo core/ui/extensions
green locally; remote check:changed blocked by Daytona capacity and the
tsgo:core Daytona exit reproduced locally as a heavy-check lock race,
passing on retry.
* test(ui): seed workboard fixtures in the mocked dev server
* fix(ci): register workboard proof capture script
|
||
|
|
a3578c7790 |
test(qa): cover Discord progress draft lifecycle (#125089)
* test(qa): cover Discord progress draft lifecycle * test(qa): allow live Discord draft proof * ci(qa): select Discord provider mode |
||
|
|
7b4981bfd2 |
fix(tui): clear stale overlays after session restore (#125086)
Centralize TUI session identity in state so remembered-session restores use the same invalidation path as interactive switches. Fixes #125013. |
||
|
|
0af3b865d7 | fix(gateway): fence legacy pending-result recovery (#125083) | ||
|
|
2e52aa436e |
fix(agents): scope embedded prompt media roots to the owning agent (#124957)
* fix(agents): scope embedded prompt media roots to the owning agent (#123273) * test(agents): exercise session-key-first media owner resolution per review * fix(agents): hydrate embedded images from agent workspaces Image attachments sent to a named (non-default) agent never reached the model. The embedded prompt path hydrated images without an agent-scoped media-root allowlist, so it fell back to the default roots, which grant <stateDir>/workspace but not a named agent's workspace-<id>. Both call sites now carry the owner already resolved for that path instead of re-parsing session identity during prompt hydration. The plugin-harness path passes workspace.sessionAgentId, and the settled embedded path passes setup.sessionAgentId. The former threw on failure; the latter returned early and silently dropped the image. Roots are scoped only when workspaceOnly is off, because images.ts falls back to [workspaceDir] when localRoots is absent. Passing agent-scoped roots unconditionally would widen workspaceOnly rather than narrow it. Sibling workspaces remain blocked because the scoped roots add only the owning agent's workspace. Related: #123273 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: sallyom <somalley@redhat.com> * fix(agents): preserve scoped media on history replay Signed-off-by: sallyom <somalley@redhat.com> * fix(agents): scope native video replay media Signed-off-by: sallyom <somalley@redhat.com> * fix(media): preserve scoped workspace isolation Signed-off-by: sallyom <somalley@redhat.com> --------- Signed-off-by: sallyom <somalley@redhat.com> Co-authored-by: Sai Sashankh D <530713+sashankh@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: sallyom <somalley@redhat.com> |
||
|
|
84f342a87e |
refactor(webui): drop gateway-version fallbacks per version-lock decision (#124971)
* refactor(webui): drop gateway-version fallbacks per version-lock decision * refactor(webui): drop chat.startup history fallbacks * test(webui): advertise full method catalog in terminal e2e scenarios * refactor(webui): enforce the build-identity handshake at connect * docs(webui): state exempted skew paths fail visibly by design |
||
|
|
b097d64574 |
test(node-host): wait for complete grandchild pid (#125034)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00b7c-b9f0-73d5-8fb7-e619e8e458e1 Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
67ea9c2281 |
fix(cli): replace stale service selectors on profile switch (#124790)
* fix(cli): replace stale service profile selectors Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * refactor(cli): own service identity checks with daemon constants Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(update): preserve managed home selector ownership Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * test(update): keep selector coverage within limits --------- Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
e84a45e28e |
test(plugins): reset the whole plugin metadata lifecycle between tests (#125037)
* test(plugins): reset the whole plugin metadata lifecycle between tests Tests that touch process-global plugin metadata were calling clearCurrentPluginMetadataSnapshot, which drops the published snapshot but leaves every memo registered through registerPluginMetadataProcessMemoLifecycleClear populated. Those memos are not content-addressed: setup-registry keys its cached registries on resolveCurrentSetupSnapshotCacheId, which returns the literal "nosnap" whenever no snapshot is published. A registry cached by one file is therefore served to any later file that also runs without a snapshot. The affected lanes run isolate: false, so that is a live cross-file leak. It matches the observed failure shape, e.g. setup-registry descriptor lookup failing with "Cannot read properties of undefined (reading 'flatMap')" only inside a shared worker and never in isolation. Switch these files to clearPluginMetadataLifecycleCaches, which clears the snapshot and every registered memo as one lifecycle unit. Two files kept both calls; the narrow one is now redundant and removed. current-plugin-metadata-snapshot.test.ts keeps the narrow primitive: it is the unit test for that function. No production change. * test(plugins): drop the duplicate lifecycle reset in provider-runtime hooks The blanket clearCurrentPluginMetadataSnapshot -> clearPluginMetadataLifecycleCaches substitution collided with the lifecycle call this suite already made, so each test boundary ran every registered metadata-cache clear twice. Keep one call per hook. Addresses the ClawSweeper P3 finding on #125037. |
||
|
|
f9b1ccc4fa |
refactor(plugin-sdk): discriminate delivery and exec results (#124979)
* refactor(plugin-sdk): discriminate delivery and exec results * test(plugin-sdk): update delivery target expectations * fix(outbound): preserve canonical delivery targets * fix(irc): normalize message delivery target |
||
|
|
54cbce25bd |
fix(onboard): give actionable managed gateway recovery (#124783)
* fix(onboard): keep managed gateway recovery on service path Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(onboard): distinguish install and restart recovery Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(onboard): localize gateway recovery guidance Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * style(onboard): format gateway recovery test Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * chore(ci): refresh service recovery validation --------- Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
515fe51d8c | perf(test): reuse setup registry module (#125087) | ||
|
|
c4eb9078d9 |
feat(workboard): link boards to owning automations (#125076)
* feat(workboard): reference the automation job that owns a board's prompt Boards can now record automationJobId, linking a board to the cron automation whose prompt/model/schedule categorize its cards. The cron job remains the single owner of that configuration; workboard stores only the reference. The board toolbar shows an Automation chip linking to the cron page when set. Deleting a board never deletes the job. Proof: pnpm test extensions/workboard packages/workboard-contract ui/src/pages/workboard ui/src/lib/workboard (9,492 passed), autoreview clean (codex/gpt-5.6-sol). check:changed blocked by remote capacity (Blacksmith down, Daytona lease cap); local fallback lanes green except a parent-branch lint finding fixed on that branch. * fix(ui): describe workboard automation destination |
||
|
|
3d1185f137 | refactor(ui): colocate sidebar panel header actions (#125019) | ||
|
|
d6be4f3552 | fix(ui): fill short transcripts with earlier history (#125080) | ||
|
|
b2709ce10d |
fix(gateway): honor selected model for worktree titles (#124902)
* fix(gateway): honor selected model for worktree titles Carry the create request’s explicit or catalog-backed provider, model, runtime, and auth profile into create-time title routing without blocking on model-catalog loading. Related: #124787 * fix(gateway): validate worktree title route Reuse the canonical model-policy resolver before prestarting title generation. Denied or invalid selections now skip title completion while persisted creation remains the sole live-catalog availability validator. * fix(gateway): normalize denied title selection Preserve the null suppression sentinel at the preparation boundary while forwarding only the title generator’s optional entry shape. * fix(gateway): inherit worktree title route * fix(gateway): preserve normalized session categories Keep post-commit category registration aligned with the normalized category persisted by session creation after the helper extraction. |
||
|
|
ea3a5bf726 |
fix(config): record when the post-write canonical reread degrades (#125075)
The canonical reread after a committed config write silently kept the in-memory config whenever the reread came back invalid or missing (a concurrent edit racing the commit). Runtime and disk then diverged with no recorded reason. Record the degradation via the config IO logger, including the reread's issue summary. Expose the deps logger on the createConfigIO facade (it already carries logger internally). |
||
|
|
49ff3e5b69 | fix(validation): preserve wave 2 boundary compatibility (#125031) | ||
|
|
bb5c27bf76 | refactor(tts): derive runtime types from implementation (#125055) | ||
|
|
2af054fb9a | fix(qa): prove repeated gateway restart recovery (#125052) | ||
|
|
0c4e2f6681 |
fix(onboard): open browser handoff in display-less WSL (#124704)
* fix(onboard): use canonical browser open support Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * test(onboard): type WSL browser detector mock Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(onboard): preserve WSL detection cache Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(onboard): remove stale browser platform probe Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * test(onboard): tolerate injected browser probes --------- Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
816ae22921 |
fix(ui): recover channel setup after status check failure (#124680)
* fix(ui): recover Custodian channel status Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(ui): invalidate channel status on reconnect Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * fix(ui): retain channel retry feedback Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae * chore(ci): refresh channel retry validation --------- Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
fecb223e5b | fix(plugins): align registry freshness inspection (#125048) | ||
|
|
e3595c50ad |
fix(plugins): failed plugins retain diagnostics without activating capabilities (#125046)
* fix(plugins): make loader failures atomic * style(plugins): avoid rollback key shadow |
||
|
|
b3ab276077 |
fix: steering near run completion receives a response (#125038)
* fix(agent): consume late steering before terminalizing * test(gateway): split provider bootstrap coverage |
||
|
|
a2b5345b2b | docs(agents): require explicit advisory authorization |