Native command turns keep #104144 source-keyed admission, but a turn that
continues into a full agent turn (/steer fallback, /goal, /learn, unhandled
body) now moves its reservation and lifecycle lease to the target session
before running. Concurrent target inbounds see the owner and queue/steer
instead of double-admitting and splitting the session into two conversation
families; steering also targets the registered run owner instead of a stale
source-keyed reservation.
Fixes#104844
* fix(ui): make indexed access explicit across the Control UI
Burns down all 322 ui-lane noUncheckedIndexedAccess errors: untrusted
markdown/diff/patch parsing gets miss-tolerant guards (renderer rules
degrade to empty output instead of throwing mid-render), accumulators
use canonical sparse initialization, DOM lookups stay null-guarded, and
length-checked constructions carry named invariants.
* feat(tooling): enforce noUncheckedIndexedAccess in the core and ui lanes
Flips the flag on for tsconfig.core.json and tsconfig.ui.json (covering
src, all packages including the two deferred ones, and ui) and retires
the strict-ratchet lane wholesale: config, script, projects reference,
check/CI wiring, changed-lane routing, and sync test. The assertion-ban
oxlint override stays as an independent surface.
* feat(mac): redesign menu bar critter to match the mascot
* fix(mac): draw happy-eye arcs upward and guard stale celebration expiry
* docs(mac): update menu bar icon states for critter redesign
* fix(mac): own celebration expiry with a start-only generation counter
* fix(mac): give voice-wake antennae real headroom at 18pt
Nextcloud Talk's supportsAction advertised support for all non-send
actions (including delete, pin, edit, read), but the handler only
implements 'react'. Unsupported actions passed the dispatcher boundary
check only to fail inside the handler.
This aligns supportsAction with actual implementation, matching the
pattern from PR #104788 (Signal adapter fix).
The parity test loaded the test-only bundled-plugin public-surface
helper from src/plugins, which the extension-test boundary forbids for
core source files; every PR touching the build-artifacts shard now
fails. Moving it to test/plugins keeps the dynamic-import lane
protection and passes both the boundary and parity suites.
The provider auth overview passed the caller's synthetic-auth object
through to the JSON payload. Status hands it the full runtime shape,
which also carries the raw credential, so structural typing let live
API keys/tokens ship in a diagnostic surface (#104713). Re-project to
the declared value/source fields at the overview boundary.
Fixes#104713
* feat(gateway): flag sessions with attached automations and disable bound cron jobs on archive
Session rows now carry hasAutomation, derived from a lifecycle-owned index
over the cron service's in-memory jobs; cron events push refreshed rows so
badges stay live. sessions.patch { archived: true } disables enabled cron
jobs bound to the session (locked binding re-check, internal/operator-admin
callers only); restore intentionally does not re-enable them.
Refs #104700
* feat(ui): sidebar session state slot and worktree/automation badges
The run spinner moves into a leading state slot shared with the unread dot,
keeping the timestamp visible during runs; muted fork/clock badges sit after
the title (outside the trail/action overlap so pinned rows and touch devices
keep them). New strings localized via ui:i18n:sync (English fallback pending
a keyed translation run).
Refs #104700
* test(gateway): pin cron binding broadcast test to the event mechanism
The shard shares one process; session-store state from earlier tests can make
the row load return null, which legitimately produces a keyless refresh
payload. Row-field projection stays covered by session-utils and
session-automation-index tests.
* feat(ui): fold Skills and Skill Workshop into a Plugins hub
One sidebar entry (Plugins) now covers plugins, skills, and skill-workshop
routes via a shared hub tab strip (Installed / Discover / Skills / Workshop).
Routes and URLs are unchanged; /settings/plugins gains ?tab= deep links and
the sidebar highlights Plugins for all hub routes.
Also latches Skill Workshop proposal loading so updated() no longer re-kicks
loads while one is pending or after one fails - the early-return finally
used to spin the page at 100% CPU whenever skills.proposals.list stalled.
* feat(mock): plugin catalog and skill-workshop fixtures for the mock harness
* docs(web): describe the Plugins hub tabs in the Control UI guide
* test(ui): backfill initialTab in plugins route-data fixtures
* fix(ui): review fixes for the plugins hub
- plugins route declares loaderDeps on the ?tab= param so query-only
navigation and back/forward re-run the loader instead of reusing the
cached match with the previous tab
- catalog tab clicks navigate so the URL and history stay in sync with
the documented ?tab=discover deep link (local switch stays instant)
- skill-workshop error banner gains a Try again button so a transient
proposals-list failure is recoverable without remounting the route
* fix(ui): restore the Installed tab on bare plugins URLs in history navigation
* fix(ui): manual-activation hub tablist with cross-route focus hand-off
Arrow keys only move focus now; activation stays on click/Enter so arrowing
can never unmount the strip under the user's focus. Keyboard activation of a
cross-route tab hands focus to the destination strip's active tab, and the
hub-route set uses a Set per lint.
* fix(ui): defer hub-tab focus reclaim until the strip is connected
* fix(ui): skip focus recovery for same-tab hub activation
* docs(css): note the hub-panel flex ownership for the workshop board
* fix(ui): adapt hub test to retired Overview route
* chore(i18n): sync locale bundles for the plugins hub keys
* docs(map): regenerate for the plugins hub section
An unprobeable api-key choice left its flag/env literals unchecked while CI
stayed green (ClawSweeper finding). The probe now supplies a real agent dir
and placeholder preflight opts (sentinel still bound to the declared
optionKey only, preserving the key-correctness proof), so every api-key
method must reach resolveApiKey — this immediately exercised
cloudflare-ai-gateway's account/gateway preflight path.
Loading built plugin dists pulls large module graphs into the shared vitest
worker cache and broke co-resident vi.mock unit tests (memory-host-sdk
embeddings, checks-node-compact-large-2). An explicit dynamic import of the
surface loader trips the lane classifier's dynamic-import rule, moving the
file to the plugins project where dist loading is the norm.
Silent skip on missing runtime registration recreated the drift class the
test guards (ClawSweeper finding); capability-only plugins now must register
zero text providers to be exempt.