The always-on Discord gateway worker now runs the same background sweeps as the API (queued posts, held starts, cleanup), so Discord replies go out at once instead of waiting for the scaled-to-zero API to wake. Posts are claimed with leases, so running the sweeps in both services never sends one twice.
* test: remove 37 low-value cases and 3 suites
* test: delete ten more renderer wiring and copy suites
* test: drop deleted suite from its contract entry point
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* test: load real modules before timed waits, and ratchet in-test vi.importActual
Two tests paid a cold real-module load inside their timed wait:
- the empty-remote wake test's 1s vi.waitFor raced the post-create refresh's
lazy session-tabs import; it now loads those modules in beforeAll;
- the runtime label-only create tests called vi.importActual inside each test
(19-23s of the 30s budget on the first case); it now runs in beforeAll.
test-no-in-test-import-actual flags vi.importActual outside vi.mock/doMock/
hoisted factories, beforeAll and module scope; the 50 existing findings are
grandfathered in the flaky-test ratchet baseline.
* test: flag vi.importActual in a doMock factory registered inside a test
* test: flag vi.importActual in any vi.doMock factory; its load runs on the next import
When an Antigravity parent ends its turn to wait for invoke_subagent helpers, agy reports the parent's Stop as fullyIdle=false, but its own terminal status says done at each turn end. After two minutes of hook silence Orca let that terminal done replace the hook row, so automations completed while helpers were still working. The parent's busy Stop now marks the row as held open for helpers, and a program's non-boundary done can no longer settle a row held open for child work. Late helper hooks after a completed turn are rejected before they touch parent state.
Verified with real agy 1.4.7: helpers slower than two minutes ended runs early on main (3/3) and complete with all helper output and the final report on this change.
Fixes#33973
agy 1.4.7 stores no id_token, so Save current account stayed disabled and the account could not be saved. Save now asks Google's userinfo endpoint which account owns the current access token (only on the Save click), then saves it, or updates the saved account with the same Google subject. The credential is re-read after the lookup, and nothing is saved if it changed.
Fixes#33323
When agy refuses a usage read with its own error envelope (for example the location eligibility rejection), Orca now shows agy's text, redacted and bounded to one line, instead of the generic "did not report a quota" message. Existing failure precedence and the last good quota bars are unchanged.
Fixes#33426
* fix(session-tabs): keep the server's per-device tab pick on the tab the desktop shows
The server hands its remembered pick back whenever the desktop has no tab groups of its own for a workspace. A desktop that kept its groups never reported what it showed, so that pick went stale and such an open landed on the wrong tab.
* fix(session-tabs): report only a ready visible pane, and retry after an error answer
Name the pane the desktop shows and require it ready, so a report never starts a pending sibling's terminal. A failure envelope no longer marks the pick as reported.
* fix(session-tabs): report a desktop's pane once per change and connection
Two windows sharing one device id could steer the pick back and forth. Report again only when this desktop's own pane changes, scope the record to the pairing and connection, and resolve the visible tab with the existing helper.
* fix(session-tabs): report only the on-screen workspace, compare panes, and remember agreement
Reports stay with the workspace on screen, whose pane attaches anyway, so a report never starts a terminal elsewhere. The pick is compared pane for pane, and an agreeing frame records the pane so a later change of this desktop's pane reports again.
* fix(session-tabs): settle before reporting, report on opening a workspace, and only to its owner
A click records its activation after an async hop, so a report now waits until the pane settles and compares against the latest frame. Opening a workspace reports from its latest frame. A workspace id two servers share is reported only to its owner. The e2e now drives the real flow: a stale pick, then a desktop restart.
* fix(session-tabs): keep one outstanding pick check per workspace, fenced to its connection
A busy workspace's frames no longer postpone the check. A frame from a replaced pairing or connection is dropped, and a frame without the per-device projection clears the cached one.
* fix(session-tabs): bound the pick report caches and clear them on mirror teardown
One record per workspace, with the connection in the value. Environment teardown drops reports, frames and timers. The tests use checked types, and the e2e notes why it waits and why it needs more time.
* fix(session-tabs): check again when the user moved on before a report finished
The host does not order activations, so a report that completes after the user picked another pane may have landed last. Clear its record and recheck from the latest frame.
* fix(session-tabs): type the visible pane's leaf as optional
* fix(session-tabs): send a browser or chat pick again when a late report landed after it
A terminal report that completes after the user picked a browser or chat tab may have had the last word. Re-send that pick the way a click does.
* fix(session-tabs): recheck a late report against the host's answer, and fence it to teardown
The activate answer is the host's per-device frame after the report, so a late landing is checked against it instead of a cached frame. A report answered after mirror teardown or a new connection does nothing.
* test(session-tabs): drop the in-connection suppression check from the restart e2e
Whether the desktop repairs a stale pick within the connection depends on which frames settle first; the guarded outcome is the pick after a restart.
* fix(session-tabs): reconcile the user's newer pick after any report outcome, timeouts included
A report whose answer timed out may still have landed after the user's newer pick. Settle every outcome the same way: retry on failure, then reconcile with what the desktop shows.
The registry watcher now reconciles orphaned runtime sessions on every
write, so the reconcile must only drop hosts the file proves are gone. It
read the filtered listing, which omits newer-format records and servers
hidden by an unreadable sidecar or WSL overlay, and checked file presence
before reading, so a file vanishing in between read as an empty registry.
Build the known set from every raw record id, fail closed on a missing
file or an id-less record, and keep the catalog broadcast running if the
reconcile throws. Follow-up to #34101.
* fix(files): open host files outside workspaces for any client with terminal access
Paired clients that can open terminals on a host can already read and write
anything its user can, so the per-terminal provenance gate on files outside
workspaces protected nothing. The host now grants any existing file outside
its workspaces; older hosts get a clear update message instead of a refusal.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(files): refuse SSH, device and WSL-home paths instead of misreporting them
Co-Authored-By: Claude <noreply@anthropic.com>
* perf(files): size grant digests to the file and skip status checks for local fallbacks
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(files): read procfs files whose stat reports size 0
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): let desktop edit host files outside workspaces
Paired clients with terminal access can already write any file on the host, and
phones can now save these files, so desktop grant tabs open editable too. Saves go
through the host grant, renewing it when it lapsed and keeping the disk-change check;
a grant tab never falls back to writing this computer's same path.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): renew lapsed host grants for reads, banners and restored tabs
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): ask older hosts for an update instead of reporting a lapsed grant as deleted
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): keep grant tabs read-only on hosts that cannot renew grants
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): check a discarded save right before the grant write is sent
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): pin grant saves to one pairing and grant restored tabs before saving
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): open grant tabs read-only when the host cannot be asked, and restore read-only grants as read-only
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): pin a restored tab's grant request to the save's pairing
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): treat only a proven not-found as a missing granted file
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): keep restored drafts by refusing read-only grant saves instead of locking the tab
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): read a restored grant on the pairing that issued it and keep read-only grants off the tab
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): let every reader of a restored host-file tab ask its host for a grant
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): add no await before ordinary reads and saves pin their pairing
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): explain unrecreatable deleted host files and hide rename for grant tabs
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): move the grant capability probe out of the store-importing module to break an import cycle
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): renew grants without cross-workspace retargeting and settle saves whose reply was lost
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): read back a lost write reply through a fresh grant after a disconnect
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): trust only an unanswered write with byte-exact readback as saved
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(editor): read back only sent writes that lost their connection, including desktop timeout envelopes
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Browser clipboards need a recent user gesture, and an OSC 52 copy from a
TUI arrives after a host round trip that can outlive it. The web client
now shows a replaceable toast whose Copy click writes the refused text.
Desktop keeps its existing failure toast.
Refs #33937
* fix(ssh): Stop and remove keeps the managed server removed across reload and restart (#34003)
* fix(ssh): recheck the removal hold after a queued Stop settles
* fix(ssh): a new managed-server claim lifts the Stop and remove hold
* fix(agents): launch Claude Agent Teams as plain orca on Orca servers
A paired Orca server has no SSH connection id, so client launches treated it
as a local Linux desktop and typed `orca-ide claude-teams`. Headless servers
only put `orca` on PATH. Client launches now read the resolved execution host
(SSH or server, except WSL workspaces), and launches built on a headless Linux
server use the launcher that server publishes.
Fixes#33920. Reported by @williamhrs. Client-side approach from #33987 by
@coolwindX; #33975 by @Shubham-Padkonde showed the host-built launch gap.
* fix(orcad): keep orca-ide working for older clients on Linux servers
Older clients type the desktop orca-ide claude-teams into server terminals.
Write an identical orca-ide launcher beside orca. Idea and test from #33975
by @Shubham-Padkonde.
* Size tabs to titles and preserve floating panel drag space
* Stabilize agent tab layout during activity changes
* Balance tab widths across titles and tab types
* Reserve terminal tab icon space before agent detection
* Run floating header drag E2E in the isolated headful project
* Prevent native text selection on the floating panel drag handle
* Cap expanded tab width at 24rem
* Let tabs expand to fit titles in available space
The desktop's connector accepts conversations from Slack, Discord and Linear and lists all three sources in its hello; per-source details (the Sent from line) come from one table. Nothing changes until those adapters are configured; behind the experimentalConnectors setting.
* fix(terminal): keep ConPTY's viewport top through a width change, checked against a captured transcript
A captured ConPTY 1.23 resize (wsl.exe) shows it keeps the line at the top
of its viewport through every resize and repaints only that viewport. xterm
keeps the cursor's rows instead: a wider grid that rejoins wrapped rows pulls
rows out of scrollback (ConPTY's repaint then overwrites them), and a
narrower one that rewraps pushes rows into it (the repaint then repeats
them). The windowsPty row rule covered neither. ConPTY-backed emulators now
put the top line back on its row after a resize.
* fix(terminal): ConPTY resize correction respects unfinished escapes and history replay
- Skip the widen correction while the parser is inside an escape sequence,
so a resize landing mid-SGR/OSC no longer aborts the app's sequence.
- Skip it when an app set a scroll region.
- Replay daemon history (cold restore from log, durable rebuild) with the
live emulator's ConPTY model, so replayed and live screens agree.
- Keep the saved cursor with its text when rows come back on narrowing,
and never drop a background-coloured blank row.
* fix(terminal): replay a saved log with the resize model of the daemon that wrote it
- A daemon now stamps resizeModel into each session's meta; the history reader uses the ConPTY
replay model only for a stamped session and keeps xterm's for one an older daemon recorded.
- Fix the DECSC adjustment: xterm keeps savedY absolute, so popping a blank row already keeps
DECRC on its text; the old +1 sent it to the top row.
- Tests: narrow-direction replay, older-daemon replay, DECSTBM skip, DECSC/DECRC after narrowing,
a background-coloured blank row kept.
* fix(terminal): take the history resize model from the daemon hosting the session
Main writes history and rebuilds durable checkpoints, but a daemon outlives an app update, so
main's own code is not what the live emulator ran. The daemon now reports its resize model in
hello (older daemons omit it, meaning xterm's); main stamps it into meta on open, restamps it
when a checkpoint starts a fresh log, and rebuilds durable history with it. The client's token
read moved to its own module to keep client.ts under the line limit.
Also clamps a saved cursor (DECSC) on a popped row to the new bottom row, as xterm's reflow does.
* fix(terminal): a disconnect leaves the history resize stamp alone
The client keeps the last daemon's reported model through a disconnect (the next hello replaces
it); undefined, before any daemon has answered, now means unknown and skips the restamp instead
of reading as an older daemon. Tests: a disconnect mid-commit keeps the stamp, and a Sleep-cache
wake onto a newer daemon restamps with its first checkpoint (#34060).
* fix(terminal): read the rebuild's resize model through the history manager
The durable rebuild called client.getDaemonResizeModel() in the checkpoint path, which tests that
fake the client with only request() could not answer, so the rebuild fell back to the live
snapshot. The history manager already holds the hosting model's provider; the rebuild reads it
there, keeping the checkpoint path's client use to request().
* fix(files): open host files outside workspaces for any client with terminal access
Paired clients that can open terminals on a host can already read and write
anything its user can, so the per-terminal provenance gate on files outside
workspaces protected nothing. The host now grants any existing file outside
its workspaces; older hosts get a clear update message instead of a refusal.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(files): refuse SSH, device and WSL-home paths instead of misreporting them
Co-Authored-By: Claude <noreply@anthropic.com>
* perf(files): size grant digests to the file and skip status checks for local fallbacks
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(files): read procfs files whose stat reports size 0
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(wsl-host): a cold wake that loses orcad recovers by itself; stopped-distro refusals stay final
* fix(wsl-host): identity and pairing refusals stay final; no second wake after a stop; settling is retryable
* feat(orchestration): add a Settings switch to turn worker heartbeats off
Dispatched workers are told to send a heartbeat every 5 minutes. A new
"Worker heartbeats" switch under Settings > Agent Orchestration (on by
default) lets users turn that off: newly dispatched workers are no longer
told to send heartbeats, and the stale-heartbeat check is skipped.
The interval the brief states and the stale check both derive from one
resolver over the live setting, read from the runtime's own store like
the other orchestration settings.
* Test heartbeat preferences across settings and worker dispatch
* Keep focused heartbeat preference contracts
* Explain partial runtime fixture assertion
* Correct CLI integration fixture contracts
The host's turn-start timestamp is the only turn id the connector uses: snapshots, turn ends and replies all carry it, and the desktop's separate turn cache is gone, so they can no longer disagree. The unused turn-bound cancel was removed (Stop is parked). The hook server reads the main agent state through the same shared accessor.
* fix(ssh): move enabled SSH automations to the host's Orca server
Connecting an SSH host moves its saved state to the host's managed Orca
server. An enabled SSH automation refused that move on every Connect
("automations (1), automation runs (4)"), leaving the host unconnectable;
Move anyway connected it but stranded the automation on the desktop, where
it no longer ran.
An enabled automation whose runs have all finished now moves with its run
history. The manifest still carries it disabled, which every server version
accepts; once the move commits the desktop disables its retained copy and
turns the server's copy back on through automation.update, re-sending its
start time so the next run is the next future occurrence. A server that
can't is noted in Settings; an unreachable one is retried on the next
Connect. While a move fences the host, the desktop scheduler, Run now and
the launch re-check write nothing for its automations, so a tick can no
longer break the fenced export; releasing the fence resumes them. A run
still in flight keeps blocking and the refusal now says to wait for it.
Fixes#29083
* test(ssh): mock the server automation enabler in the delta-move handler test
* test(e2e): keep the Move anyway specs refusing now that enabled automations move
The inline Move anyway spec seeded an enabled automation to force a
refusal, which this branch now moves instead. It seeds one pinned to an
earlier registration of the host, which still stays behind. The relay
bridge spec's Move anyway lookup also matched the refusal toast's
button since #34041; it now takes the pane's own.
Freezes the connector's shipped table definitions: later schema changes must be additive statements. Adds a baseline fixture and an upgrade test (baseline, then current schema, compared with a fresh database on SQLite and Postgres), plus the statement-shape check relay already uses. No runtime change.
* feat(wsl-host): start a WSL host's distro when one of its automations comes due
E9 connect policy, part 2. A WSL host's automations run inside its distro, so a
distro that is off (a reboot, an idle release) missed them. While a host is connected
the desktop now reads its enabled automations' next run (on connect and every 15 min)
and keeps the soonest one per host in userData. When that time comes with the host off,
it boots the distro once, and orcad's startup catch-up fires the run within its missed-
run grace. A run due while the computer was off fires once Orca starts. Nothing wakes
past the grace window, and a connected host is left to its own scheduler.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(wsl-host): a due automation boots a parked host once, never with WSL hosts off
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl-host): keep the following run, and forget changed automations (E9 review)
Review of #33839:
- A run handled while connected dropped the host's next due time. The wake now keeps
each host's enabled schedules and computes the following run locally whatever
happens to this one (wake failed, past grace, handled by the host), and re-reads the
real one from a connected host.
- A deleted, disabled or rescheduled automation kept waking the distro at its old
time. A successful automation.create/update/delete from this desktop now re-reads the
host's automations, as do the 15-minute re-read and every connect. Nothing boots a
distro to check: on wake, a distro already running is just reconnected.
- wakeForAutomation/isConnected live here now (moved out of #33838); isConnected reads
the host's reachability, never booting.
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor(wsl-host): say isConnected answers for this process; keep the service in bounds
isConnected reports whether the host answers through this process; false is not
"stopped" (a fresh process has no bridge yet, and the wake just connects). The
service's quiet record read moves beside the other record helpers so the file stays
within its line limit after the E9 additions.
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor(wsl-host): give the connector contract its own file; one wake path for focus and automations
After rebasing onto #34063, #34093 and #33110 the WSL host service was over its line
limit. The connector contract (what the service drives) moves to
wsl-host-connector-contract.ts, re-exported from the service, and the focus entry and
the automation wake share one private wake step: lift the park, then reconnect unless
the host answers, read with #33110's focusReachability so neither pays a WSL round trip
when this process has no bridge yet. An automation wake no longer reconnects a host
that already answers.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(wsl-host): an automation wake with no bridge skips the reachability probe
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Source control actions start chats and terminals on their saved model
A "start an agent" action's model lived only in free-text CLI arguments, which a native chat
never reads, so AI Fix opened a chat on the default model. Each action now saves a structured
model and effort that both routes apply: chat create options, or the agent's own flags in a
terminal (winning over the same flag in CLI arguments). Desktop, dialog, fix-checks and mobile
launches carry it; Settings rows get Model/Effort selects and the CLI arguments field says it is
terminal-only.
Tracked in STA-11102.
* Name the model in the repository override note
* Type the dialog's model hand-off; keep Agent in English in Japanese copy
* fix: preserve action chat model choices through launch
* Preserve action selection ownership across chat launches
* Keep terminal host contract fixtures aligned with preflight
* fix: wait for action Settings agent inventory
* fix: consolidate direct agent routing imports
* fix: use standard action option labels
* fix: align action launch contracts with shared types
* fix: sync action option localization metadata
* test: provide action Settings inventory in mounted fixtures
* Keep action options row height stable while loading
* Let each Source Control action choose its chat permission mode
An action's saved chat choice may now carry a permission mode, with or without a model;
"Same as new chats" saves nothing. A model is replaced only when the action names one,
so a permission-only choice keeps the chat's remembered model and options.
* fix(native-chat): leave older hosts their own permission mode and keep action options readable
- An action's saved permission mode is sent only to hosts that advertise
agentSession.create.options-mode.v1. Older hosts get no mode, in create
options or a later setOption, so the chat starts on that host's new-chat
default, as a phone launch to such a host already does. Hosts from
1.4.225 to 1.4.227 refused a mode their tables lacked (OpenCode, Grok,
OMP), leaving the action unable to start.
- Settings action rows give Model and Permissions full rows in the options
column so saved values are readable; the loading placeholder reserves the
same rows.
- Remove two unused locale keys; fix two stale comments.
- Tests: the older-host create carries no permission mode; a permission
mode picked alone keeps the remembered model on an acquired create.
* fix(settings): reserve one options row while loading an action with nothing saved
Terminal and permissions-only rows no longer shrink when loading ends; a chat
agent with a model list may grow by its Model row once known.
* fix(native-chat): keep the create options mode a checked literal type
* fix(settings): share verified action option fields
* fix(settings): keep action selectors on standard typography
* Keep the launch files under their length limits after the main merge
The structured route imports its result types where they are defined, and the two older-host
action-launch tests share one setup helper.
* One action settings section for chat and terminal launches
A Source Control action's Model, model options and Permissions now apply whether it opens a
chat or a terminal; terminals receive them as the agent's own flags, and a repository's own
CLI arguments keep the flags it sets. Extra CLI arguments stay terminal-only.
* fix(source-control-ai): one terminal projection for saved action choices
Ask in a terminal now states its permission instead of leaving it to the
user's own config: Claude and Grok pass --permission-mode default, Codex
passes -a on-request -s read-only -c approvals_reviewer="user" (the
interactive CLI has no untrusted policy, so a read-only sandbox is what
asks before edits). Agents whose CLI has no flag for a mode show the
existing "Applies to chats only" hint.
The strict launch-preferences projection now requires the launch agent at
every caller, composes model ids through the resolver's own step, carries
a mode only where the agent's terminal has a flag for it, and the local
string wire keeps booleans as 'true'/'false', so Cursor Thinking/Fast reach
the terminal and an OpenCode permission-only choice is not refused.
The argument parser knows flag arity, so removing a boolean permission
flag keeps other options' values, following positionals and '--'.
Pre-admission and executor share one terminal admission check on the
options the terminal will receive. Customize with Save launches the recipe
as it will resolve once saved; legacy partial repository overrides are
edited as the complete recipe they resolve to. Empty Extra CLI arguments
start collapsed.
* fix(source-control-ai): an edited repository action saves complete
Every Settings edit of a repository action (agent, model, permission,
prompt or arguments) now starts from the complete recipe the action
resolves to, whether its stored override is owned or a legacy partial.
The resolved agent selection is kept (never an agent only detected to run
a default), an explicit null args clear stays null, and empty args stay
empty instead of being dropped. Clearing the last preference therefore
means the action agent's own defaults rather than re-inheriting Global.
The action text draft is lossless: unset or cleared prompt and args stay
so until the user types, and the inputs show them as empty, so saving a
prompt no longer writes empty args that suppress the agent's default
flags. Untouched sibling actions are not rewritten by the edit.
* fix(settings): style the Extra CLI arguments toggle through Button's own variant and size
CI's changed-code quality check refuses restyle classes on Button and
CollapsibleContent. Use the ghost variant at size xs with a margin, and
put the content spacing on a plain inner wrapper.
* fix: keep saved action and restart launch recipes consistent
* fix: describe inherited arguments and chat-only permissions accurately
* test: check repository action settings fixture type
* test: map saved action options into terminal compiler inputs
* fix: retain saved action controls during agent detection
* fix(i18n): retire obsolete Portuguese action labels
* test: align folder launch fallback mock with outcome export
* fix: carry resolved connector launch intent and mode together
* test: pin shared action launch branches to recorded agent output
* test: preserve saved source control choices through detection and migration
* test: align launch fixtures with integrated result contract
* test: retain recipe and restart contracts after main integration
* Unify Source Control action permission settings
* Keep native Ask copy with its owning change
* Preserve action drafts and old-host permission intent
* Consume rejected Source Control action saves
* Follow the moved Settings persistence fixture
* Keep permission integration contracts in the cross-version test project
* Include the action permission inheritance label in English catalogs
* Align launch contracts with shared permission recipes
* Keep Source Control action controls within their Settings columns
* Use primitive variants for compact action settings controls
* Show action arguments only for terminal defaults and widen recipe rows
* Apply terminal-only action arguments visibility to repository overrides
* Align action permission control with model controls
* Use shared settings label for action permissions
* Hide action model controls until argument migration ships
Adds Discord as a second connector adapter on the shared core: signed interactions for answer buttons, one gateway worker (same image, single leader by database lock, commits on the lock's connection, checkpoints for resume), thread posts through the shared post queue, owner-only control, and teammate context only from linked accounts. Inert until the Discord settings are configured. A narrow gitleaks allowlist entry covers connector Discord env var names in config errors.
The parked watcher passes only hostCloseReason 'pty-exit' (so the pinned
guard still applies), and the local branch then let closeTab default the
reason to 'user': a process exit wrote a user tombstone and retired the
session. The local close now carries the pty-exit reason.
Co-authored-by: Claude <noreply@anthropic.com>
A connector-started agent is told it can answer in its thread with orca connector reply --text; the desktop posts the reply through its Orca Cloud connection, naming the conversation and turn, so the machine never holds a Slack token. Works for agents on this machine; elsewhere the command answers that replies aren't available from this host yet, and the turn's final message is still posted when the turn ends. Behind the experimentalConnectors setting.
* fix(orcad): find the app's bundled agent-browser driver for orca serve
Desktop orcad templates omit the driver for size, so orcad materialized from an
installed app reported driver_missing with ORCA_BROWSER_EXECUTABLE set. orca serve
now hands orcad the app's resources copy via ORCA_AGENT_BROWSER_DRIVER; the
slot's own driver still wins for standalone artifacts.
Fixes#33846
* test(serve): expect the app's agent-browser driver handed to orcad
* fix(serve): run a profile copy of the driver on Windows so app updates stay replaceable
* fix(serve): never lend the installed Windows driver when staging fails
* fix(serve): keep another launch's in-progress driver copy
* refactor(serve): share claimed snapshot publication for the Windows driver copy
The served-relay blackbox test closed the phone and data sockets from the client and sent the resume confirm before the relay had processed the close, so on a busy runner the relay correctly answered device-resume-confirmed and the test failed (about 1.8% under load). The test now closes only the phone and waits for the relay to close the data leg with 4408, which happens in the same step that marks the connection inactive. Test-only.
* fix(terminal): keep a brand-new remote pane's typing for the terminal it creates
* fix(terminal): new-pane typing goes only to a genuinely fresh create, never an adopted or restored terminal
* fix(terminal): decide a new pane looked blank at connect; at bind re-check only what the create can't cause
* test(terminal): replayed history from the real restore path drops a new remote pane's typing
* fix(terminal): type the replayed-history marks by xterm Terminal
did-start-loading fires for subframe loads too, so a page that reloads an
iframe on each poll invalidated the annotation document every cycle: the
pending card closed, grab mode was cancelled and saved-note markers were
retired. Main-frame did-start-navigation already invalidates for every
document replacement (including same-URL reloads) and same-document
navigation, so drop the did-start-loading handler and move the overlay
viewport reset next to that invalidation.
Fixes#23988
Co-authored-by: Neil <neil@stably.ai>
* fix(terminal): a WSL bridge pane whose distro went away keeps its tab and cold-restores
wsl --terminate (or a shutdown or crash) exits every live bridge pane with an
ordinary code, so Orca closed those tabs as if the shell had exited, and the
next launch opened new sessions instead of restoring the old ones. A proven
exit of a WSL bridge session now checks the shared, coalesced
wsl --list --running (never boots, bounded); if the distro is confirmed gone
it is host loss: code -1, history left unended, tab kept, exactly as after a
daemon crash. A running distro or an unanswered check leaves the exit as is,
so still closes the tab. Native and SSH sessions are untouched.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(terminal): trust only a running-list probe that started after the exit; close a kept tab's history
Review of the WSL bridge distro-loss check:
- A probe already in flight from before the exit can predate the distro's
boot, so it could call a user's own quick exit host loss. Only a probe that
started after the exit answers; one fresh probe is chained after an older
in-flight one and shared by the whole wave.
- The outer bound drops to 3 s: every bridge exit waits on it.
- Closing a kept tab later hit SessionNotFound before removeSession, leaking
its history; an explicit close now treats that as already stopped.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(terminal): only a session this adapter lost to its distro may close as already gone
Swallowing SessionNotFound for any id could remove the history of a session a
legacy daemon (sharing the history dir) still runs. The adapter now records
the sessions it turned into host loss, clears them on respawn or close, and
swallows SessionNotFound on an explicit close only for those.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* perf(native-chat): stop hidden chats re-rendering on every tab change
Skill discovery now subscribes to tab and workspace state only while the
slash/skill picker is open, and the per-chat image owner subscription
reads only its own workspace's tabs. Previously every mounted chat
re-rendered and rescanned the tab maps on any tab change anywhere.
* Resolve native chat image context from its selected owner
* Cover selected chat image owners through preview consumers
* Use typed reads in chat subscription performance fixture
* Key chat subscription probes by fixture chat identity
* Type dense chat subscription measurement results
* Name the read-only floating chat resolver view
* Exercise document markdown in selected-owner preview test
* Check unavailable chat image through its preview dialog
Moves routing, machine choice, held starts, the post queue, prompt cards and owner controls out of the Slack files into a provider-neutral connector core, with Slack as the first adapter behind one adapter type. Conversation records and delivery ids are keyed by source, so Slack and Discord ids cannot collide. Behaviour-neutral for Slack apart from a slack: delivery-id prefix and a 403 (not 404) from the reply route when Slack is off. Staging's connector database is reset after deploy.