mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 09:37:33 +00:00
* feat(mobile): show SSH host health on the workspace row host badge
Rows on an SSH host the desktop cannot reach looked healthy on the phone. The badge now
adds the desktop sidebar's own word ("devbox · Disconnected"), derived by the same shared
function from the connection status ssh.listTargetSummaries already sends; old desktops keep today's badge.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* feat(mobile): name an unhealthy SSH host even in a single-host list
The desktop card shows SSH status on any host count, so the phone now reads target summaries
whenever a repo is on SSH and badges an unhealthy host alone too. Labels and health share one
target-to-host keying, and a hook-level test pins the reply-to-row wiring.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(mobile): clear stale SSH host badges and announce them without the dot
A catalog that no longer spans hosts or holds an SSH repo now clears the health and label maps,
so a host that left cannot keep badging rows. The badge gets a screen-reader label ("devbox,
Disconnected") instead of reading the middle dot.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* feat(runtime): let a paired desktop register its phones as delegated mobile devices
A desktop paired to this runtime can now call pairing.delegatedMobileDevice.sync to make each of
its phones an ordinary mobile-scope device it owns, so the phone mirrors that host through the
desktop. Children are never pending, inherit the parent's reach, and die with the parent's grant.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* refactor(runtime): move the mobile device revoke primitive below dispatch
Dispatch binds the caller-bound delegated-device context, so the revoke path it needs now lives in
a layer under it as a pure move; this drops the abstract method seam. No behaviour change.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(runtime): keep a runtime grant until its delegated phones are revoked
A failed child cleanup now leaves the parent in place so a retry can still find the children, and
revokeRuntimeAccess lives beside the revoke it cascades to. Adds restart, rename and bounds coverage,
shares credential minting, and drops the timing-dependent census.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(runtime): fail a delegated sync whose dropped phone cannot be revoked
Matches the parent revoke: a child whose cleanup could not be saved is kept and the sync errors
before minting anything, so the desktop retries instead of believing the server matches its list.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* feat(mobile): relay a paired phone's server-workspace requests through the desktop
A phone mirrors its desktop, including workspaces on the desktop's configured servers. The desktop
now forwards a request that names `executionHost: runtime:<env>` to that server over one socket per
(phone, server), signed in as the phone's delegated device; replies pass through untouched except
stream ids. Hidden until the phone client ships: the relay capability is not advertised yet.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* test(mobile): type the single-host health fixtures inline so the test tsc passes
Fixtures hoisted into consts widened their health maps to string, which the now-required
hostHealthById rejects under the tests-typecheck ratchet; passing them inline keeps the union.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* docs(mobile): state the desktop relay contract in its entry module
main dropped docs/reference, so the relay's contract lives beside the code. Also pins that a
server whose delegated sync fails (e.g. delegated_device_revoke_failed) is unavailable until a
later request syncs it again.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* test(mobile): pin the relay's configured-server adapter
The production hosts adapter was only typechecked; this pins that it resolves configured servers
by exact id only (never a name or a removed server), fences by pairing revision and runtime
identity, and stops reporting retirements once unsubscribed.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* test(mobile): re-record the repo-metadata goldens for SSH host health
The settled metadata state now carries hostHealthById, and an SSH-only catalog now reads the
target summaries so a lone unhealthy host can be badged. Scoped re-record via rpc-recording.mts.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* refactor(mobile): tighten the desktop relay after elegance review
Reuses the shared E2EE socket opener, folds relay state into fewer fields, never sends a request
whose link ended while opening, passes failure codes through, relays only this desktop's own
phones, and drops the unused host-state reader until S2 needs one.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(mobile): bound relay frames and stop sticky relay verdicts
Restores the 8 MiB frame cap on every remote runtime socket, re-checks an update-needed server on
each new link so an in-place upgrade relays, answers a phone the server just declined without
syncing again, and ends a link whose mirrored capability update cannot be queued.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(mobile): run targeted desktop-owned calls on the desktop
The phone tags every call on a workspace screen with its execution host, so a
paired-desktop method carrying `runtime:<env>` now runs locally instead of
failing 'forbidden'. The Mac stays the only reader of the routing table.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* feat(mobile): list the desktop's configured servers and their last workspace rows for the phone
The phone needs the same host list the desktop shows, including servers that are offline or
too old to relay to. mobileRelay.hosts.list/worktrees answer from the desktop's own status and
its own worktree.ps fetches, cached per server and fenced by pairing, never from relayed replies.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* refactor(mobile): list server rows through one desktop fetch, with no side effect on listing
The phone now always lists a server's rows through mobileRelay.hosts.worktrees, so the
desktop's own fetch is both the live source and the cache, and stamping stays in main.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(mobile): fetch a server's full workspace list within a bound, and forget removed servers
The desktop now asks for the phone's full-catalog limit, answers within 5s with the last rows
when a server hangs, drops a server's rows when it is removed or re-paired, and checks the
server's identity after the fetch so a reply from before a re-pair is never served.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(mobile): list managed servers as the desktop sidebar does, and hide rows mid-delete
A server Orca manages on an SSH host now lists once under that host's name, or not at all while
the host is reached over the SSH relay, using the sidebar's own folding. Rows the server is
deleting are left out at reply time, as a phone asking the server itself would see.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(mobile): keep a disconnected server's last rows, and never join a re-paired server's fetch
Retirement also fires on a manual disconnect or managed-server update, which wrongly emptied
the phone's list; rows are now pruned only once a server is no longer configured. Fetches are
shared per server identity, so a poll after a re-pair asks the new server right away.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(ci): run the remote-runtime WebSocket opener test on Node
Under the bun vitest project, `ws` resolves to Bun's built-in client, which
ignores maxPayload, so the frame-cap test hung. The opener only ships on
Node/Electron, so run its test in the Node runtime project like its siblings.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* refactor(mobile-relay): derive the phone allowlist from the routing table
Adding a phone method now takes one edit (its route). A server-targeted call on a
legacy non-E2EE socket is refused instead of running locally, and only
execution-host methods enter the relay.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* refactor(mobile-relay): drop unread freshness fields from server workspace lists
The phone reads only the rows, so stale, fetchedAt, totalCount and truncated
were dead wire weight. The desktop still serves a server's last rows while
the server is unreachable.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
* fix(runtime): classify the mobileRelay RPC namespace as host-owned
main now requires every runtime RPC namespace in the host-operation ownership table; the relay-hosts methods are served by the desktop the phone is paired to.