Commit Graph
13437 Commits
Author SHA1 Message Date
OrcaWinandm4air 4f03c23796 refactor(projects): repo, project group and folder catalog calls route by their owner (#27288)
Catalog fetches, path-status probes, project and group mutations, nested
scans and imports now take the owner's host explicitly instead of falling
back to the Active Server setting. A new project with no picked host still
goes to the default host, through defaultCreationHost.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 12:58:09 -07:00
OrcaWinandm4air 81867c8ea0 refactor(sources): row-less sources and host-less surfaces name their host (#27290)
* refactor(sources): row-less sources and host-less surfaces name their host

Linear and Jira clients take a RowLessSource: a task-source context, an
explicit host, or defaultScopeSource(settings) when no Tasks source is
chosen, so raw settings no longer compile. defaultScopeHost joins
defaultCreationHost as the second sanctioned reader of the default-host
setting (both behind one private read, both ratchet seeds), and the status-bar
account switchers, settings navigation and the settings host picker's initial
default use it. Skill discovery routes by the owner id its install terminal
resolves, and the workspace-board Linear sync by the workspace owner.

* fix(lint): count the default scope source and assign-then-return readers

defaultScopeSource is a sanctioned read of the default host, so its call
sites count. A function that assigns a reader's result to a local and returns
that local is a reader too, which keeps the skill-discovery hook counted.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 12:32:46 -07:00
OrcaWinandm4air ca1aac6af4 refactor(github): PR and work-item calls carry the repo owner's host (#27289)
getRuntimeRepoTarget takes the transport its caller already routed by
instead of reading the Active Server setting (with a raw focus default).
Work-item, comment, check and review-thread requests get it from
getGitHubSourceTarget (task source host, else the repo's owner); PR
lookups from the repo row; PR refreshes from the candidate's owner.
Hosted-review fetches route by hostedReviewRepoOwnerTarget. An unknown
repo stays on this computer instead of following the focused server.
Cache keys are unchanged. Deletes settingsForHostedReviewRepoOwner,
settingsForGitHubFocusedRepoOwner and getGitHubWorkItemSourceSettings.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 12:14:05 -07:00
OrcaWinandm4air 572f178080 refactor(agents): agent, session and port calls route by their workspace owner (#27283)
Agent note sends, background agent and terminal launches, structured chat
reveal and activation, and the tab strip's Windows shell probe take their
transport from the workspace owner's environment instead of building
owner-shaped settings for getActiveRuntimeTarget. The automation observer and
the Codex selection lane read the owner from the PTY id alone, so an
ownerless remote id is never assigned the focused server. Local
advertised-URL events always rescan this computer, even when a server is
the default host.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 12:02:01 -07:00
OrcaWinandm4air 314993c200 refactor(terminals): terminal input and inspection route by the PTY's owner (#27279)
* refactor(terminals): terminal input and inspection route by the PTY's owner

A remote PTY id already names the server that owns it. inspect, confirm,
send, verified send and the data subscription took settings only to fall
back to the focused server for an id without an owner segment, so an old
ownerless id could reach a server that does not own it. They now route by
the id alone: an ownerless remote id is never dialed and never confirmed
locally.

Dropping the parameter removes the settings plumbing the native chat,
agent draft paste and follow-up paths carried only for this, including the
raw focused-settings default in sendBracketedPasteToAgent, and deletes
getSettingsForAgentTabRuntimeOwner.

* test(e2e): native chat SSH delivery and remote completion follow the narrower terminal signatures

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 11:43:05 -07:00
OrcaWinandm4air 7de3710dbe refactor(files): file reads and edits route by the file's owner (#27278)
* refactor(files): file reads and edits route by the file's owner

The runtime file clients took a settings object and turned its Active Server
field into a connection, so any caller that passed raw settings silently read
or wrote on the focused server. They now take `target: RuntimeClientTarget`,
and every caller derives it from the owner: the tab's stamped owner, else its
worktree's owner (getRuntimeTargetForFileOwner / getRuntimeTargetForWorktreeOwner),
the file-explorer operation owner, or an already captured owner id.

Behavior: single-host (local-only) users see no change. An editor tab opened
without an owner stamp, a terminal link with no PTY owner, an OS file drop and
a notebook link now go to the workspace's owner instead of whichever server is
focused when the read happens.

Removes getEditorFileDropSettingsForWorktree and the native-chat settings clone
cache; settingsForWorktreeOperationRoute loses its editor caller.

* fix(files): file owner targets come from the rows, never the focused server

getRuntimeTargetForWorktreeOwner/getRuntimeTargetForFileOwner move to
lib/file-owner-runtime-target.ts and resolve through the focus-free
resolveOwner. A workspace with no row yet stays on this app (tabs and drops
stamp a server owner when one exists); rows that disagree return null, and
callers with an error path refuse via requireRuntimeTargetForFileOwner.

* test: keep the editor content-state fixture within the line limit

* fix(files): an unresolved document owner blocks local image reads

A null owner target became runtimeContext undefined, which image readers take
as a plain local file, so a server-owned document's images were read from this
machine. It is now runtimeContext null, the readers' do-not-load sentinel, in
the rich editor and the preview, and prewarm skips it.

* fix(files): read the image node view's storage through a named type

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 11:23:18 -07:00
OrcaWinandm4air 2eb6a920dd refactor(forge): forge reads and edits route by the repo's owner or the task source (#27276)
GitHub PR and issue dialogs, task-page cells, Project boards, slug metadata,
the repo slug index, hosted-review actions, GitLab MR base resolution and the
Settings API-budget panels now carry a RuntimeClientTarget derived from the
repo row, the row-less task source, the board row's cache key or the Settings
host scope, instead of settings-shaped objects resolved through
getActiveRuntimeTarget. A repo row with no owner stamp is local; an untracked
Project row edits on the host that loaded it.

Owner-routing ratchet 209 -> 165; focus-read ratchet 401 -> 352.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 10:50:17 -07:00
OrcaWinandm4air 75dfd75460 refactor(runtime): owner transports, the creation default and a focus-read ratchet (#27275)
* refactor(runtime): owner transports, the creation default and a focus-read ratchet

Adds runtimeTargetForOwnerEnvironment, runtimeTargetForOwnerHostId and
runtimeTargetForWorkspaceOwner so routed call sites can get a transport from
the resource's owner, and defaultCreationHost as the one sanctioned reader of
the Active Server setting for creation flows with no source row.

The owner-routing ratchet gains a second per-file counter for reads of the
setting (member reads, the focus-routing helpers and defaultCreationHost), so
swapping a helper for a direct read can no longer lower a count. Baseline rows
may carry a trailing note that survives --prune.

* chore(lint): pin defaultCreationHost's own read in the focus-read baseline

* fix(lint): the focus-read ratchet counts shared focus helpers and destructuring reads

* fix(lint): discover functions that read the default host instead of hand-listing them

A hand list let a look-alike such as getAutomationListTarget replace
getActiveRuntimeTarget and lower both ratchets. Every exported top-level
function whose body reads the setting or calls a seed helper now counts as a
reader, and nested destructuring reads count too.

* fix(lint): readers are found through imports and returned values

Readers are keyed by defining file and resolved through imports and
re-exports, so a same-named function elsewhere is not mistaken for one, and
a function that returns a reader's result (a wrapper of a wrapper) is found
too. Components are not readers, and a declaration ends at the next
top-level statement.

* fix(lint): a reader called through a namespace or dynamic import still counts

* fix(lint): renamed, parenthesized and .then() dynamic imports bind readers too

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 10:27:37 -07:00
OrcaWinandm4air 5c7c493042 fix(sources): GitHub Projects boards read from the task page's source host (#27270)
* fix(sources): GitHub Projects boards read from the task page's source host

The Projects board, its project picker and unmatched-row edits picked their
host from the Active Server setting on their own, while the Tasks header
named the selected repositories' hosts. The board now takes the same
row-less source host that Linear and Jira use, converted through
getTaskSourceRuntimeSettings, and the header names that host in Projects
mode. fetchProjectViewTable takes the source explicitly instead of reading
settings. The ownership table marks the four board-level GitHub Projects
reads as scope-picked.

* fix(github-projects): an open unmatched-row dialog keeps writing to its row's host

The dialog took the board's live source, so a source change while it was
open sent its comment and field edits to a different host than the one the
row was loaded from. It now routes by the source encoded in its row's cache
key, like the row field edits already do.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 09:17:11 -07:00
5b676777ba fix(web): the paired server is the web client's only host (#27266)
* fix(web): the paired server is the web client's only host

A paired web client is a browser tab with no PTYs, files, browser or
second window of its own, yet owners it read as "local" still routed to
it: setup terminals and server-local rows hit the local PTY stub, the
dashboard pop-out was a silent no-op, Open in Orca Browser threw an
uncaught error, and the macOS traffic-light inset was reserved.

Route a transport-less owner through the paired server at the shared
owner resolvers, open the in-window dashboard, refuse document previews
with a reason, and reserve no traffic-light inset in the web client.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(web): type the owner fixtures instead of casting

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-10 08:57:47 -07:00
OrcaWinandm4air 865183cff9 feat(settings): host-owned settings panes choose their host explicitly (#27265)
* feat(settings): host-owned settings panes choose their host explicitly

Settings gets a Host menu (this computer or a saved server). Provider
accounts, agent detection and terminal capabilities follow it instead of
the Active Server setting, which is only the menu's starting value. A
server that is no longer saved reads unavailable and never falls back to
another host. The provider-account client now takes the owner target
instead of settings.

* chore(i18n): regenerate runtime-required English catalog

* fix(accounts): Codex restart notices follow the host the switch wrote

A Settings account switch on the chosen host flagged panes on the focused
host instead. markLiveCodexSessionsForRestart and its lane matcher now take
the owner target explicitly; Settings passes the picker's host, the status
bar its focused target, and local sign-in this computer.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 08:47:25 -07:00
OrcaWinandm4air ba1474f960 feat(hosts): Resource Manager lists the owning host's processes (#27263)
While the Resource Manager is open, each paired server that hosts one of this
client's projects is asked for its own process samples through the existing
diagnostics.memory method, and those rows render under the server's projects,
named by host and without a kill control. A server that cannot answer is named
as unknown instead of looking idle.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 08:09:00 -07:00
ec1a01a4bf fix(accounts): a server's late account result stays with that server (#27262)
* fix(accounts): a server's late account result stays with that server

The Accounts pane kept one roster across default-runtime changes, so a
select or remove still in flight on the previous server overwrote the new
owner's roster when it returned. Key the pane by its account owner so
rosters, account ids and in-flight results are scoped to one owner.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(accounts): drop a stale owner's result instead of remounting the pane

Remounting lost an in-progress local login's spinner and Cancel button and
hid an account added after returning to the same owner. Guard each action's
result by the owner it was sent to instead.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(accounts): keep the stale-owner check on the roster write only

The toast, settings refresh and restart prompt describe what happened on
the owner the action went to; only the roster belongs to the shown owner.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-10 08:07:51 -07:00
OrcaWinandm4air 6cbbe456c0 fix(hosts): agent launch platform and shell come from the execution host (#27259)
* fix(hosts): agent launch platform and shell come from the execution host

Agent startup commands were quoted for this client's OS (and its Windows shell
setting) whenever the workspace's repo row had no SSH connection, so a Windows
client driving a Linux Orca server sent PowerShell to bash. SSH hosts were
guessed from path shape.

One resolver now reads the OS from the host that runs the agent: the server's
reported hostPlatform, the relay-reported SSH remotePlatform (nested SSH read
through its server), WSL as linux, and this client only for local workspaces.
A missing fact withholds the launch with a reason. Plain-SSH mode now
publishes the OS the runtime ladder detected.

* fix(hosts): new-tab and background launches read the worktree's own host

Review follow-up: the new-tab resolver reads folder workspace paths (WSL folders),
a caller's platform only refines a local launch, background launches resolve the
worktree's host (nested SSH) and drop this client's shell setting for remote hosts.

* fix(hosts): background launches on an SSH worktree keep the relay CLI name

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 07:45:38 -07:00
OrcaWinandm4air af80ba3652 fix(skills): say an SSH repo was not scanned instead of dropping it silently (#27261)
Discovery skipped every SSH-backed repo without a trace, so the Skills page
counted only local folders and never said a repo was left out. Each skipped
SSH repo now appears as a source with skippedReason 'remote-repo', which the
Skills folder list already renders as 'Remote repo - not scanned'.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 07:44:09 -07:00
Neil 83db5b5ec1 [CI] Reduce test teardown waits and duplicate CI setup (#27253)
* [CI] Reduce test teardown waits and duplicate CI setup

* [CI] Map browser ownership to the combined test check
2026-10-10 07:30:43 -07:00
OrcaWinandm4air 291549e83f fix(ports): the ports panel scans and stops on the workspace's own host (#27258)
* fix(ports): the ports panel scans and stops on the workspace's own host

The panel now picks its host from the workspace owner instead of the repo's
connectionId and the Active Server. A direct SSH or recipe VM workspace uses the
SSH view for its own target; an SSH target behind a paired server is scanned by
that server through workspacePorts.scanHost (workspace-ports.host-scoped.v1),
and Stop goes through killHost with the host the row was scanned on. An older
server is never asked and the panel says to update it; an unknown owner says so
instead of scanning another host.

* fix(ports): scan recipe VMs through this app's runtime so an unreachable VM reads as unavailable

Recipe VM targets publish no connection state to the renderer, so the SSH view
cannot tell a reachable VM from one whose relay is reconnecting. Route them
through workspacePorts.scanHost on this app's own runtime, which reports a
missing relay as unavailable, and keep the SSH view for user SSH targets.

* fix(ports): keep the host-scoped panel's host stable without a render-time ref

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 07:24:36 -07:00
OrcaWinandm4air 61a99d7e91 feat(terminals): dashboard terminal previews from the owning host (#27250)
* feat(terminals): dashboard terminal previews from the owning host

A paired host's agent pane now previews over the same multiplexed terminal
stream panes already use, routed by the host named in the pty id. The web
client and desktop pop-out no longer render a blank dialog when no preview
bridge exists; they show the unavailable message instead.

* fix(terminals): hold the preview's snapshot boundary and transport credit

A requested snapshot is followed by every chunk the host buffered, covered
ones included, so live output is now trimmed against the snapshot's output
high-water for as long as the stream lives. Each emitted chunk keeps the
host's delivery credit until the preview parses it, so a slow preview
applies backpressure instead of overrunning its parser.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 06:58:43 -07:00
OrcaWinandm4air 3a8f8e1790 fix(review): PR reads and actions follow the ownership table (#27248)
* fix(review): PR reads and actions follow the repo owner, not a host-less task source

A GitHub task source without a runtime host used to spread
activeRuntimeEnvironmentId: null over the repo owner's settings, so
assignee, reviewer, label, status and merge cells for a runtime-owned
repo ran on this desktop. Every PR read and action site now routes
through getGitHubRepoRoutingSettings (renamed from the merge-only
helper), and the store's source-scoped routing defers to the repo owner
the same way. Focus is never a fallback.

Fixes #7623

* fix(review): a host-less source never inherits an ambiguous repo owner

Duplicate repo ids across hosts made the host-less source fallback pick a
server owner by focus (UI) or by first row (store), so a local item could
read or write on a paired server. The owner is now inherited only from
the single row with that id; ambiguity stays on the source's own host.

* test: drop stale repo-owner mocks from GitHub repository scripts

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 06:49:00 -07:00
OrcaWinandm4air 3e7ab3f5a1 fix(review): review providers resolve the repo on its host (#27247)
* fix(review): GitLab reads and actions run on the repo's own host; failed reads show as errors

GitLab task lists, the item dialog, right-sidebar MR actions and the Checks
panel now pick their host from the repo or workspace row: a server-owned
repo asks its server over runtime RPC, a local or SSH repo uses this
computer's glab. The focused Active Server is never consulted. The runtime
arm reuses the web client's gl-over-RPC table, now shared.

A failed checks or comments read in the Checks panel renders as an error
that names the machine that answered, instead of 'No checks configured'.

* fix(review): keep the server for SSH workspaces behind it; pin the MR host for post-launch thread resolves

An SSH workspace reached through a paired server keeps ssh:<target> as its
host and names the server separately; its GitLab credentials live on that
server, so the Checks panel and job-log tab now route there.

A comment-resolution launch now records the MR's credential host when it is
queued, so the post-launch resolve no longer looks the repo up by a bare id
that two hosts can share.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 06:04:26 -07:00
OrcaWinandm4air b9502e5a14 fix(terminals): automation runs, CLI tabs and folder-workspace browser tabs follow the owner (#27246)
* fix(terminals): automation runs, CLI tabs and folder-workspace browser tabs follow the owner

- An automation run on a paired server opens its mirrored pane, or asks the
  server to focus it when the mirror has not loaded it yet, instead of
  reporting "Run terminal is unavailable." while the server still runs it.
- This desktop's CLI browser tab create/close/profile requests are refused
  only for a workspace a paired server owns, not whenever a paired server is
  the Active Server.
- browser.tabCreate resolves folder workspaces for server-hosted pages, as it
  already did for client-hosted ones.

* fix(terminals): refuse ambiguous browser owners and name a failed run reveal

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 06:03:42 -07:00
github-actions[bot] 5fae0fa327 Update README downloads badge 2026-10-10 12:37:29 +00:00
OrcaWinandm4air e41b8e17f0 fix(terminals): terminal IDs, agent rows and dashboard rows follow the owner (#27243)
* fix(terminals): terminal IDs, agent rows and dashboard rows follow the owner

Copy Terminal ID on a paired-server pane copies the owning server's handle
instead of asking this desktop's runtime, which has no record of that pane.
Sidebar agent rows and dashboard reveals tell the workspace's owning server
which tab was opened, as a tab-strip click does. A paired-server dashboard card
with no preview says the session is remote instead of claiming its pane closed.

* fix(terminals): owner activation keeps the picked pane and yields to later navigation

The row and dashboard reveal now send the exact split pane to the owner and
record it in the focus intent, guarded by the tab visible at the click, so a
later navigation away is never overridden when the tab arrives.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 05:28:40 -07:00
Neil 4dfc74e5e6 [CI] Reduce repeated test imports and unrelated runner allocations (#27222)
* [CI] Reduce repeated test imports and unrelated runner allocations

* [CI] Exercise macOS packaged CLI invocation receipts

* [CI] Unmount workspace hook fixtures before environment teardown

* [CI] Wait for replacement Bash readiness before the child command
2026-10-10 05:24:35 -07:00
OrcaWinandm4air f361455c73 fix(files): links to this computer in a remote terminal open on the client with trusted provenance (#27234)
* fix(files): a link to this computer in a paired-server terminal opens here when the host disowns it

* fix(files): keep client-local link tabs on this computer; gate the fallback on host support and native clients

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 05:20:26 -07:00
OrcaWinandm4air aea19ae7a5 fix(files): client drops on a remote composer upload through the import transaction (#27227)
The new-workspace composer addressed a paired server's files by the project
path instead of the project's worktree id, so every drop onto a server-owned
project was refused with selector_not_found. Pass the repo's main worktree id
so the existing import transaction (unique temp, no-clobber commit, fenced
cleanup) runs against the right worktree.

Fixes #16558

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 04:56:36 -07:00
OrcaWinandm4air 9d43038840 fix(files): a paired-server link outside its workspace opens in the host workspace that holds it (#27226)
* fix(files): a paired-server link outside its workspace opens in the host workspace that holds it

Links an agent or terminal prints for a paired server's file in another
workspace (the main repo, a sibling worktree) failed with "Remote file is
outside the owning runtime worktree". The link now asks the host through
files.resolveTerminalPath with crossWorkspace, and opens the file in the
workspace the host names. A path outside every host workspace is refused
with a message that says so; a sibling file the host verified absent
reports not found.

* fix(files): open the host's spelling of a cross-workspace link path

* fix(files): a paired server's path never opens with this computer's default app

The client-OS open decision looked at whether the path sat inside the source
workspace, so a server path outside it read as local. Decide by owner: any
paired-server or SSH workspace downloads first.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 04:26:31 -07:00
OrcaWinandm4air f050e57a98 fix(agents): one agent inventory per host and execution context (#27225)
* fix(agents): one agent inventory per host and execution context

Launch surfaces that pick an agent for a workspace now read and load the
agent list through one helper keyed by the workspace's own host, instead of
each re-deriving "SSH connection id, else this computer". A paired server's
workspace (including one on the server's own SSH target) reads the server's
list; this client's own list and its SSH map are never consulted for it.

- Source Control AI actions (Resolve with AI, recovery, Fix checks), the
  new-agent-tab shortcut, Explain commit, session continuation and the
  checks panel use readDetectedAgentsForWorktree / ensureDetectedAgentsForWorktree.
- An old paired server without workspace-scoped detection probes its own SSH
  target with preflight.detectRemoteAgents instead of answering its default list.
- A disconnected SSH host rejects detection instead of answering [], so it is no
  longer cached as "no agents installed"; Quick Launch says the host is unreachable.
- On Windows, an active workspace on another host no longer drops this machine's
  agent context to the Windows host; it uses the global runtime default.

* chore(i18n): add the unreachable-host quick launch copy

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 04:22:15 -07:00
OrcaWinandm4air fff0bb0d06 feat(runtime): the host refuses a request meant for another runtime (#27224)
A CLI launched from an Orca terminal now sends, with each request, the
runtime it verified before sending (expectedRuntimeSource: the launching
profile's installation id plus the verified runtime id). The host checks
it before parsing params or running any handler and refuses a mismatch
with runtime_source_mismatch, so a runtime that took over the endpoint
between the CLI's check and its send cannot apply the request.

Optional field: an old CLI sends none and an old host ignores it (the
CLI's pre-send probe stays the fence there). Hosts advertise
runtime-source-fence.v1.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 03:50:26 -07:00
OrcaWinandm4air e0376015a4 refactor(runtime): route adapter, split fences, ownership table, combined ratchet (#27218)
* refactor(runtime): route adapter, split fences, ownership table, combined ratchet

Adds callHostRoute, which calls a host-owned method on the host a HostRoute
names and reports a reply whose host identity moved mid-call as unverifiable
instead of applying it. Host fences are split: an identity fence (pairing,
runtime connection generation, the route's own SSH target) for mutations, and
the catalog data fence built on top of it for snapshot reads, so unrelated
catalog or SSH-state churn no longer moves a mutation's fence.

HOST_OPERATION_OWNERSHIP classifies every runtime RPC namespace. A new
ratchet counts getActiveRuntimeTarget( + legacyRouteFromSettings( +
settingsForRuntimeOwner( together per renderer file (227). One exemplar, the
folder workspace review-note write, moves onto the adapter.

* fix(runtime): fence the folder note write on its server; refuse aliased ratchet helpers

The folder catalog row lives on the paired server, so its write is fenced on
that server's identity, not on the SSH target the folder names. The ratchet
now counts spaced calls and value uses, and refuses an aliased import or
re-export that would hide calls from the count.

* test(ci): pin the owner-routing ratchet step to the static phase

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 03:48:48 -07:00
OrcaWinandm4air 26bca8914a refactor(hosts): stamp events and optimistic rows at ingest (#27223)
Worktree change/activation events and the just-created worktree's owner now go
through adoptFromEndpoint, and a dev counter reports rows that reach a reader
unstamped but get attributed to a non-local host.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 03:38:23 -07:00
OrcaWinandm4air 7aa91f730a fix(cli): check the runtime source before sending (#27206)
* fix(cli): check the runtime source before sending

A terminal Orca launches now carries which Orca launched it
(ORCA_RUNTIME_SOURCE_ID = the profile's installation id,
ORCA_RUNTIME_SOURCE_INCARNATION = the launching runtime id). Before a
request is sent, the CLI compares that with the runtime the profile's
runtime record names. Same runtime: sent as before. Different runtime:
a read-only status.get asks which profile it serves; the same profile (a
restart or update) is accepted, anything else is refused before the
request reaches it.

The vars cross into WSL through WSLENV. The SSH bridge stamps the
bridging runtime itself rather than trusting the remote env. The
existing orchestration compatibility stamp is untouched.

* fix(orcad): drop an inherited runtime source at startup

* fix(cli): an explicit switch to another profile is not fenced

The stamp also carries the launching runtime's userData path. A CLI that
dials a different profile than the one that launched its terminal, and
not the platform default an unpinned terminal falls back to, was pointed
there on purpose (orca-dev from a packaged Orca's terminal), so the
fence does not apply.

* refactor(cli): reuse the shared userData path comparison

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 03:19:14 -07:00
OrcaWinandm4air bbe9a11456 refactor(hosts): one ingest adapter for fetched rows (#27216)
Repos, project groups, project host setups and folder workspaces fetched
from this app or a paired server were each stamped with their owner by a
separate function. They now go through adoptFromEndpoint, one adapter with
a per-kind arm. Behavior is unchanged; a characterization test was run
against the old stampers before they were deleted.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 03:12:00 -07:00
OrcaWinandm4air 6af18ab07a refactor(hosts): host authorities and owner resolution (#27176)
* refactor(hosts): host authorities and owner resolution

Adds HostAuthority {endpoint, at} with authorityKey (existing host-id
spellings kept; nested 'SSH target behind server' gets an in-memory key no
host-id parser accepts), HostRoute {target, at}, and resolveOwner, a
focus-free owner resolver over the existing route resolvers. Today's
focus-reading answer is kept behind resolveOwnerWithLegacyFocus, which
counts every answer focus changed. No caller migrates in this PR.

* fix(hosts): resolveOwner keeps nested SSH places and strict active selection

The active workspace's host now resolves through the strict path, so rival
servers proxying one ssh:t stay ambiguous. A folder or repo row on a paired
server that names an SSH connection resolves to that nested target instead
of the server's own machine.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 02:47:06 -07:00
OrcaWinandm4air 31b2b17d9b refactor(wsl): move the WSL guest bundle sources out of src/relay (#27174)
* refactor(wsl): move the WSL guest bundle sources out of src/relay

The WSL hook relay and WSL browser network relay are built from src/relay but are
not part of the SSH relay. Move them, and the 46 relay modules the hook relay
bundles, to src/wsl-guest so the SSH relay can be deleted on its own. Pure
renames; the built bundles are byte-identical.

Adds a boundary test so nothing outside src/relay imports it except relay tests.

* fix(ci): exempt renamed files' existing lint debt in the changed-lines gate

* test(relay): keep the cast suppression on the wrapped line

* test(relay): only parse files that mention relay in the import boundary check

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 02:46:27 -07:00
Neil 3c71318d5b [CI] Overlap independent process waits and remove two static tests (#27198)
* [CI] Overlap independent process waits and remove two static tests

* [CI] Use the declared conditional Vitest chain
2026-10-10 02:20:22 -07:00
OrcaWinandm4air 0ba67e1181 fix(mobile): agents for workspaces another runtime owns show why (#27196)
* fix(mobile): agents for workspaces another runtime owns show why

The paired host no longer lists its own agents for a workspace another Orca
server owns: preflight.detectAgents refuses with workspace_on_other_runtime,
and the phone shows 'Agents on Another Server - Pair that server directly'.
The phone also recognises an unambiguous runtime-owned repo row itself, so an
older host is never asked.

* fix(mobile): a shared repo id with a runtime-owned row defers to a refusing host

Rows on several hosts can share a repo id, and the first row's SSH connection
could name the paired host's own target. When any row is runtime-owned the phone
now asks a host that advertises preflight.other-runtime-refusal.v1 to decide by
worktree, and shows the other-server row on an older host.

* fix(mobile): keep the agent-loader change inside the web bundle budget

Move the refusal code beside its capability in protocol-version, read the
capability in the loader, and test the runtime: prefix directly: importing
execution-host into the loader split a web bundle chunk (129 > 128 assets).

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 02:09:10 -07:00
b80c420054 feat(pairing): re-pairing the same server keeps its environment (#27197)
* feat(pairing): re-pairing the same server keeps its environment

The web client minted a new environment id on every runtime-scope pairing link,
even for the same server key, so existing terminals kept the old id and failed
as ambiguous. A key-matched re-pair now keeps the id (bumping the pairing
revision) and pins the server's host descriptor; a same-key server with a
different installation gets a new id, and a downgraded server never replaces
the pin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(web): a reply from the replaced pairing never overwrites a same-server re-pair

Re-pairing now keeps the environment id, so fence on the pairing revision too:
a request captured before the re-pair can neither reopen a client with the
replaced token nor save the old pairing back over the new one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:07:28 -07:00
Brennan Benson dab3f6efeb fix(native-chat): preserve running subagent rows in long chats (#26798)
* fix(codex): keep running subagent groups in long chats

* fix(codex): remember superseded settled child turns

* fix(native-chat): retain running Claude subagent groups
2026-10-10 02:03:58 -07:00
Neil 991fd5ca4b Keep folder Git upgrades responsive and recheck project ownership (#26791)
* Keep repository detection off the main IPC thread

Share repository discovery decisions across synchronous compatibility callers and the existing asynchronous Git runner. Await discovery in project registration, nested imports, and folder upgrades, and recheck folder ownership after discovery completes.

* Make repository detection fixtures work on native Windows

* Await asynchronous Git checks in folder upgrade fixtures

* Prevent duplicate project registration after async discovery

* Check authoritative registration identity before renderer convergence

* Narrow repository responsiveness to detection and registration

* Keep one local project identity after concurrent registration

* Run registration SSH coverage in the existing Docker lane

* Keep folder upgrades responsive and recheck pending project ownership

* test(git): cover classifier failure stages and literal path identity

* test(git): use the current process host package

* test(repos): use current process host in folder upgrade fixture

* test(repos): use current process host in registration fixture
2026-10-10 02:02:16 -07:00
Neil 803ab30598 Await Git checks while discovering and importing nested projects (#26790)
* Keep repository detection off the main IPC thread

Share repository discovery decisions across synchronous compatibility callers and the existing asynchronous Git runner. Await discovery in project registration, nested imports, and folder upgrades, and recheck folder ownership after discovery completes.

* Make repository detection fixtures work on native Windows

* Await asynchronous Git checks in folder upgrade fixtures

* Prevent duplicate project registration after async discovery

* Check authoritative registration identity before renderer convergence

* Narrow repository responsiveness to detection and registration

* Keep one local project identity after concurrent registration

* Run registration SSH coverage in the existing Docker lane

* Await Git discovery when scanning and importing nested projects

* test(git): cover classifier failure stages and literal path identity

* test(git): use the current process host package

* test(repos): use current process host in registration fixture
2026-10-10 02:01:40 -07:00
Neil 4bdeff3ec3 chore: remove verified unused Orca code (#27175)
* chore: remove verified unused Orca code

* chore: remove translations orphaned by dead code cleanup
2026-10-10 02:01:24 -07:00
Neil b63d39ebe5 Keep repository detection off the main registration thread (#26760)
* Keep repository detection off the main IPC thread

Share repository discovery decisions across synchronous compatibility callers and the existing asynchronous Git runner. Await discovery in project registration, nested imports, and folder upgrades, and recheck folder ownership after discovery completes.

* Make repository detection fixtures work on native Windows

* Await asynchronous Git checks in folder upgrade fixtures

* Prevent duplicate project registration after async discovery

* Check authoritative registration identity before renderer convergence

* Narrow repository responsiveness to detection and registration

* Keep one local project identity after concurrent registration

* Run registration SSH coverage in the existing Docker lane

* test(git): cover classifier failure stages and literal path identity

* test(git): use the current process host package

* test(repos): use current process host in registration fixture
2026-10-10 02:00:15 -07:00
Brennan Benson d91921a9c6 Let a Grok chat list and stop the commands it left running in the background (#27022)
* Let a Grok chat list and stop the commands it left running in the background

A command Grok backgrounded (a dev server, a watcher, a monitor) showed only as a
transcript line: it never reached the background-tasks card above the composer, so
it could not be seen as running or stopped from Orca. Grok's subagents and Claude's
and Codex's background commands already list and stop there.

The ACP lane that publishes Grok's subagents as child records now also publishes
its background-task rows: a running task as a live background command or monitor,
an ended one as removed, derived from the rows the journal admitted. A Stop for one
of them goes through the same adapter route to Grok's own per-task kill
(x.ai/task/kill); Grok's completion notice ends the row, and a task Grok no longer
holds is removed at once. A refusal reports the task as not stopped; no answer or an
unreadable one leaves the outcome unknown.

Each Grok process is checked once at start with a no-target kill, beside the
existing subagent check. Only Grok naming the method unknown hides Stop.

* Settle a Grok task's transcript row when Stop finds it already gone

When Grok answered a Stop with already_exited or not_found, the card row was
removed out of band while the transcript row kept saying it was running, and a
later restated running notice could bring the card row back with Stop. The
answer now settles the transcript row through the translator, like the
subagent Stop, so the card row leaves because its row settled, the existing
no-relight rule keeps it gone, and a completion Grok still sends after
already_exited writes the real result. Also covers /clear being refused while
a Grok background command runs.
2026-10-10 01:59:04 -07:00
OrcaWinandm4air 180e8c186f feat(ports): host-scoped port scan and stop on the server (#27188)
* feat(ports): host-scoped port scan and stop on the server

Add workspacePorts.scanHost/killHost, addressed by workspace and resolved on the
server to the workspace's own execution host (this machine or one of its SSH
hosts). Stop is bound to the host its row was scanned on and is refused on SSH
hosts, where ownership cannot be proven. Advertised as
workspace-ports.host-scoped.v1.

* fix(ports): only this host's workspaces authorize Stop; a failed relay scan is not empty

Port ownership probes now come from host routing instead of the repo row's
connectionId, so an SSH repo that carries only executionHostId (or a runtime-
hosted repo) can no longer make a local listener look workspace-owned.

The relay's ports.detect now fails when it could not read the socket table
(unreadable /proc/net/tcp, or neither Windows scanner answering) instead of
answering an empty list, so a host scan reports unavailable rather than none.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 01:27:49 -07:00
OrcaWinandm4air cbeb703490 feat(hosts): servers publish a host descriptor (#27193)
* feat(hosts): servers publish a host descriptor

A paired server now reports a stable installation id, created once per
profile, plus an optional machine binding (HMAC keyed by that id over
the machine id and profile path) in status.get and in runtime pairing
offers. Optional fields only: older clients ignore them and older hosts
omit them. Clients start using it in the follow-up.

* fix(hosts): serialize installation id creation so concurrent starts never fork it

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-10 01:26:26 -07:00
NeilandMatheus Breguêz b3aa719a57 Preserve Git history lanes through unrelated roots (#26932)
Preserve active graph lanes through unrelated root commits and share node/reference colors.

Isolate real-Git fixtures from inherited Git settings and use the existing public process-host import after the current-main package migration.

Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
2026-10-10 01:10:30 -07:00
cb69d52455 fix(repos): deleting a project with live terminals warns and needs --force (#27172)
* fix(repos): deleting a project with live terminals warns and needs --force

orca project setup-delete now refuses a repo-backed project that still has
terminals not known to have exited or saved workspace details, unless --force.
The sidebar remove dialog says how many open terminals will close.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(repos): count a sibling host's host-qualified workspace metadata in the delete guard

Co-Authored-By: Claude <noreply@anthropic.com>

* test(sidebar): cover the remove dialog's open-terminal warning

Co-Authored-By: Claude <noreply@anthropic.com>

* test(sidebar): type the dialog mock state without assertions

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-10 00:44:55 -07:00
NeilandYEONGUK LEE f4c4eaeece fix(i18n): correct Korean Finder menu label (#26866)
Use the approved Korean Finder wording and preserve it during locale regeneration.

Co-authored-by: YEONGUK LEE <contact@abruption.dev>
2026-10-10 00:34:58 -07:00
NeilandMatheus Breguêz e3bca6c5a8 fix(a11y): name Agent Dashboard column regions (#26865)
Name Agent Dashboard columns using their translated visible headings.

Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
2026-10-10 00:34:54 -07:00