* fix(cron): validate failureAlert channel at the gateway boundary
`--failure-alert-channel` writes patch.failureAlert.channel, a field distinct from
delivery (own store columns, own delivery path in service/failure-alerts.ts). The
gateway validator only ran channel checks for delivery patches, so a
failure-alert-only patch stored an unknown channel unvalidated and only failed
later at delivery time with channel_not_found.
Add assertValidCronFailureAlert (reusing the announce-channel validation), wired
into create + update. It mirrors resolveFailureAlert() runtime resolution:
resolves the effective mode (job or global cron failure-alert mode; webhook alerts
skip channel-type validation), inherits the job delivery channel/target when the
alert names none (rejecting a routing-changing edit that would activate a
legacy-invalid inherited channel, while unrelated/threshold edits and already-
active alerts are not blocked), resolves a provider-prefixed target like the
delivery/failureDestination paths, and honors the channel:null last-fallback. Maps
failureAlert.channel errors to INVALID_REQUEST. Regression tests included.
Closes#103864
* fix(cron): align failure alert route validation
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* refactor(channels)!: shrink ChannelSetupInput to a generic envelope with a deprecated compatibility tier
* fix(channels): keep ChannelSetupInput structurally assignable without an index signature
* docs: regenerate docs map
* fix(onboard): survive inference owner drift and verify credentials route-aware
Guided onboarding crashed ("Could not start the CLI") on the openai-api-key
candidate when OPENAI_API_KEY was set and a Codex CLI login existed:
- owner revalidation resolved provider auth without the route model's
id/api, so the transport gate never applied and profile-first discovery
picked the Codex-imported ChatGPT OAuth profile instead of the env key
the probe ran with — a deterministic fingerprint mismatch
- that mismatch escaped the activation persistence path as a plain throw,
crashing the wizard ladder instead of moving to the next candidate
Owner re-resolution now carries resolved model transport facts (fail closed
when the model cannot be resolved), and all setup revalidation sites route
through one helper whose drift error activation maps to
{ ok: false, status: "auth" }.
* feat(onboard): prefer logged-in subscription CLIs over env API keys in setup ladder
* fix(onboard): promote codex only on verifiable ChatGPT OAuth tokens
* fix(onboard): surface detected AI candidates in the top auth-choice tier
* fix(onboard): name detected candidates and the current model clearly
* test(setup): mock model resolution in the bound-session lock test
* fix(system-agent): carry verified model transport facts
* fix(browser): tab creation steals window focus during agent automation
Agent-created tabs inherited CDP's foreground default: direct CDP
Target.createTarget omitted the background flag, and the extension
relay's createTab defaulted to active:true, so every agent tab open
activated the new tab (and, on the extension driver, focused the
window), interrupting whatever the human was doing in that browser.
Direct CDP tab creation now requests background:true (agent tab
ownership/selection is target-id based and never depended on
activation), and the extension relay defaults an omitted background
to true while preserving an explicit background:false, matching the
Codex/Claude-in-Chrome model the extension driver mirrors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(browser): keep focus fix LOC-neutral
Preserve background tab creation while keeping the oversized CDP and relay modules within the current LOC ratchet.\n\nCodex-Session: 019f5e93-780a-7350-88f9-1986cdb64914
* fix(browser): honor explicit CDP focus requests
Keep background-by-default automation while treating Target.createTarget focus=true as an explicit foreground request in the extension relay.
Codex-Session: 019f5e93-780a-7350-88f9-1986cdb64914
* fix(browser): preserve explicit CDP focus semantics
Apply the background-by-default automation policy only when focus is omitted, preserving focus=false foreground-tab requests as well as focus=true.
Codex-Session: 019f5e93-780a-7350-88f9-1986cdb64914
* fix(browser): preserve create target window focus
Carry the resolved CDP focus intent through the extension relay and explicitly focus the containing Chrome window when requested.\n\nCodex-Session: 019f5e93-780a-7350-88f9-1986cdb64914
* style(browser): refresh relay import order
* test(secrets): use secure node exec fixtures
* test(doctor): secure exec secret fixture
* test(doctor): retain narrowed temp path
* test(secrets): secure remaining exec fixtures
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
resolveComputerNode passed only the eligible (computer-capable) nodes to the
shared resolver, so an explicit exact node id belonging to an ineligible
device was never scored. Resolution could then fall through to display-name
matching and select a different eligible machine whose display name equaled the
requested id, observing and acting on the wrong desktop.
Mirror the mobile_ui-tool fix: match an exact node id against the full node
list first, reject an ineligible exact match with the eligible ids listed, and
only then resolve by display name among eligible nodes (still rejecting
ambiguous collisions, now with eligible ids in the error). Split the
node-selection tests into computer-tool.node-resolution.test.ts to keep the
main test file under max-lines.
* fix(sessions): archive the full transcript before manual compaction deletes rows
openclaw sessions compact <key> --max-lines N deleted the trimmed SQLite
transcript rows without writing any backup, then returned an archived value
that was a fabricated marker string pointing at nothing, so the CLI told
users their history was archived when it was permanently gone. Regression
from the SQLite storage flip (#98236): the previous flat-file path renamed
the live transcript to a real .bak.<timestamp> file before replacing it.
The manual compact trim now exports the complete pre-compaction transcript
through the shared durable session archive writer (exclusive create, 0o600,
fsync, atomic rename, optional zstd) as
<sessionId>.jsonl.bak.<timestamp>[.zst] in the per-agent sessions archive
directory before any rows are deleted, and archived returns that real path.
The backup is written outside the SQLite transaction; the destructive
replacement revalidates the row snapshot inside the write transaction and
aborts, removing the fresh backup, if the transcript changed after the
snapshot. Backup failure aborts compaction with every original row intact.
* fix: preserve reused compaction archives on conflict
---------
Co-authored-by: Josh Lehman <josh@martian.engineering>
* feat(gateway,ui): ask-the-observer card input over sessions.observer.ask
* refactor(ui): single home for observer run-identity helper after restack
* test(ui): drop duplicated observer hud test after restack
* test(ui): give the observer ask flow its own colocated suite
* refactor(gateway): leaf observer contract and ask module split for ci gates
* refactor(gateway): drop observer contract re-export shims
* fix(agents): emit diagnostic when sessions_yield parks without continuation evidence (#100146)
Add a shared hasYieldContinuationEvidence predicate in incomplete-turn.ts
and emit a user-visible diagnostic payload in terminal-resolution.ts when
a yielded turn has no same-turn continuation source (accepted spawn, async
tool, messaging delivery, cron add).
Simplified per ClawSweeper P1 review: remove overbroad activeDescendantCount
suppression — only same-turn evidence is considered. Pre-existing descendant
waiting deferred to separate lifecycle design.
Source +53, Tests +131. Total +184 across 3 files.
* fix(agents): remove unused export of hasAsyncStartedToolActivity
knip deadcode detected this exported function has no external consumers;
all usages are internal to incomplete-turn.ts. Removing export fixes
both check-dependencies and ci-gate CI failures.
* ci: retrigger Telegram proof
* fix(agents): preserve yielded client tool calls
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
* docs(agents): explain yield evidence scope
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
* docs(agents): bound silent-yield diagnostic
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Forward explicit sessions_spawn model choices through direct and queued child launches, and persist the exact authorization so restart replay cannot silently fall back to the default route. Fixes#91171.
Co-authored-by: mikasa0818 <0668001030@xydigit.com>
* fix(ui): allow direct sessions in non-Git folders
* test: align New Session fixtures with place picker
* fix(ui): preserve worktree intent on Git probe failures
* fix(types): keep worktree status alias internal
* feat(ui): session observer HUD, subtitle integration, and settings
* test(ui): observer demo fixtures for the mock control-ui harness
* fix(ui): satisfy lint and deadcode gates for observer surfaces
* test(ui): adopt renamed pull-request summary api after rebase
* fix(ui): clean rebase artifacts in observer test files