* fix(browser): make orca set media --reduced-motion actually apply
agent-browser's set media only looks for the bare tokens dark, light and
reduced-motion and ignores anything else, so the documented reduce value
was dropped and the command still reported success. Map Orca's values
onto those tokens in one builder used by the desktop bridge and the
orcad external Chromium path, and reject unknown values.
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
* fix(browser): reject bad set media values before queuing and list both flags in help
---------
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
* 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>
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.
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
* fix(orchestration): preserve task reset lineage per Run
STA-10382
* fix(orchestration): record removed Tasks, Dispatches and workers per entity
Replace the per-Run capped JSON snapshot with one row per removed entity in
removed_orchestration_work, written by AFTER DELETE triggers on tasks,
dispatch_contexts, worker_dispatches, worker_terminal_resources,
remote_dispatch_attachments and federated_dispatches. The triggers are
rebuilt on every open after migrate and dropped at migrate start; a
recorded_since coverage marker moves forward whenever any trigger was
missing, so a Run created before recording reads partial, never
complete-and-empty.
reset --tasks keeps its delete list and order; its reply gains optional
removed counts computed after commit (a failed summary only drops the
field). run-show gains an optional constant-size removedWork summary and
--removed/--cursor paging. reset --all clears the record; deleting a Run
deletes its rows.
Removes the snapshot modules, the run_reset_lineage table, the in-transaction
receipt completion and alwaysRequestId from the first version of this PR.
* chore: drop accidental pnpm-lock.yaml churn
* refactor(orchestration): decode removed work entries through unknown before the checked cast
* fix(orchestration): count settled workers with open terminals and name affected Runs
- A worker may still be running when its state was possibly live or its
Orca-owned terminal was never released; the reset reply, run-show line and
listing share one derivation from the removed records.
- The reset reply names the affected Runs (optional runIds); the CLI prints
the exact run-show command for one Run and the list for several.
- The watermark read is no longer swallowed inside the reset transaction.
- run-show's removed-work read is guarded; a failure omits the field.
- Coverage compares created_at strictly after recorded_since.
- --removed lists a federated worker once, shows a user-taken-over terminal
as such, and says when a cursor is past the end.
* fix(orchestration): count removed workers by held process minus durable exit proof
- A removed worker may still be running when Orca held its process (live
state, federated dispatch pending or dispatched, or an Orca-owned terminal)
and no durable exit proof exists (stopped, released, released terminal, or
a certified termination reason on its Dispatch).
- The exit proof is one DURABLE_EXIT_PROOF constant shared by the fleet
liveness projection (no behavior change) and the removed-work reader.
- Dispatch records keep terminationReason.
- Coverage is complete when a Run was created at or after recorded_since; a
moved marker is stamped one second past the newest existing non-legacy Run,
and the capture installs after the stub home Run backfill.
* docs(orchestration): correct the terminationReason and coverage marker comments
* fix(orchestration): decode removed work entries through a checked schema
The stored record is parsed once with a discriminated zod schema per kind,
so the listed entry keeps its precise type without an assertion. The same
lineage field table drives the capture triggers' key set and integer casts.
* fix(orchestration): exhaustive removed-work listing switch; keep valid ids in id lists
List worker and remote worker entries with explicit cases so the switch is
exhaustive over the entry kinds. An id list drops non-string elements and
keeps the rest, as before the schema decoder.
* test(orchestration): build removed-work CLI fixtures without type assertions
Use a real RuntimeClient with a spied call and decode listing fixtures through
the entry schema, so the tests carry checked types instead of casts.
* fix(orchestration): name only the removed kinds in run-show and word the no-record message truthfully
The run-show line lists the kinds a Run actually lost, terminals included,
and the --removed message for a missing record no longer claims the host
keeps none, since a new host omits it when its read fails.
* fix(wsl-move): classify the removed-work tables with the other orchestration tables
removed_orchestration_work and its coverage marker live in the orchestration
database and go with its Runs, so the WSL mover rewrites them in place like
every other orchestration table.
* fix(orchestration): keep the removed-work hint when a reset removes only terminal records
When an imported or cloned folder's derived project id does not match the
selected project, the error now names the id the folder resolves to (for
example github:owner/repo) instead of a generic mismatch message. Host-local
ids and identical ids keep the generic message. The setup-existing-folder
help notes which ids --project accepts.
Fixes#23528
Co-authored-by: Neil <neil@stably.ai>
The bundled orca-cli skill guide never mentioned `terminal read --screen`,
so agents onboarded from it used the stream read on repainting TUIs and got
stacked fragments. Add a --screen example plus the stream-vs-screen and
--screen/--cursor rules, and realign the root help usage lines for
terminal read and terminal split with their command specs.
Fixes#15856
The orca-cli skill guide said `--direction horizontal` splits left/right and
`vertical` splits top/bottom, but terminal panes map `vertical` to a
side-by-side split (flexDirection 'row'), matching the "Split terminal right"
menu. Swap the wording and regenerate the bundled guides.
Fixes#9023
Dispatched workers were told to run `orchestration check` but never to ack
the returned deliveryId, so the same batch replayed on every check and newer
coordinator mail stayed hidden. The dispatch preamble, orchestration skill
guide, and worker contract now tell workers to ack each processed batch with
`--ack <delivery_id>` (which also reads the next one) and repeat until count
is 0.
Co-authored-by: Neil <neil@stably.ai>
cmd /c strips the first and last quote of a line that starts with a quote
unless exactly one quoted, paren-free executable path is present. A spaced
.cmd launcher plus any quoted argument (or a Program Files (x86) launcher)
was cut at its first space and the spawn silently failed. Prefix the batch
invocation with `@` so the line never starts with a quote, in both the
waiting and detached start /B forms.
Add a real cmd.exe round trip in the Windows CI lane.
Co-authored-by: Neil <neil@stably.ai>
An explicit empty --terminal (or orchestration --from) was treated as absent,
so `orca terminal send --terminal ""` targeted the active pane and
orchestration check/inbox/worker-start fell back to the ambient
ORCA_TERMINAL_HANDLE mailbox. Hoist the existing getPresentStringFlag into
flags.ts and use it for these handles so a present-but-empty value fails with
invalid_argument.
Fixes#16694
Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: wusiyuan05 <wusiyuan05@zuoyebang.com>
The resource panel summed RSS. On macOS that counts the Electron framework's
shared pages once per helper process, so main and renderer read 2-8x too
high, while the GPU process read 3-5x too low because RSS excludes graphics
memory. The detached terminal daemon was also missing from the app total.
On macOS, sample per-process phys_footprint from top (the figure Activity
Monitor shows) at most every 10 s while the panel is open, and fall back to
RSS when top is unavailable. Count the local terminal daemon in the app's
'other' bucket; its PTY children stay attributed to their worktrees. Linux
and Windows keep RSS/working set.
Co-authored-by: m4air <m4air@Mac.localdomain>
`orca fill --value ""` and `orca select --value ""` were rejected client-side
with "Missing required --value" even though the browser.fill/browser.select RPC
schemas already accept an empty string. Read --value with the existing
getRequiredStringFlagAllowingEmpty helper so an empty value clears a field or
picks the blank option, while an absent --value is still rejected.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* fix(ssh): keep machines cloned with one machine-id off each other's Orca server data (#32918)
Machines cloned from one image share /etc/machine-id. On a shared home both
got the same machine key, so both managed servers ran in ~/.orca, and each
judged the other's PID locally and reclaimed its live instance lock.
- Record the claiming hostname in the shared-home claim and machine homes;
a Linux machine whose machine-id matches but hostname differs gets its own
machine home. Older claims fall back to data-root owner records.
- orcad's instance lock no longer treats a holder with this machine-id but
another hostname as local, and refuses to start when an older clone's
profile-state owner record shows it is using the data root.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): keep a clone's established machine home, and let a host renamed within its boot restart
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): call a machine a clone only with positive evidence
A renamed host keeps its boot and a local disk has one machine, so only
another host and boot with this machine-id on a shared filesystem counts as
a clone, on Linux only. When both clones already write the login home, stay
and let the server lock refuse the second writer. Drop the machine-home
owner markers.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): refuse a second server from a cloned host instead of relocating data
Drop the inferred clone relocation. orcad refuses to start when a holder or
profile-state owner on a shared filesystem reports this machine-id from another
hostname and boot, naming that host and the fixes. Add ORCA_MACHINE_NAME, an
explicit host-env name that gives a managed SSH host its own machine home.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): judge cloned machines by boot and freshness, not hostname
A peer with this machine-id is another live machine only when its record is
from another boot, was written after this boot began, and is fresh. The orcad
lock now heartbeats its mtime. That drops the hostname test, which renames
broke and same-hostname clones evaded. It also drops the participant-owner
precheck that stale records could block forever, and keeps profile-state
owner cleanup from deleting a live clone's owner. stale-lock reclaim uses the
same rule. ORCA_MACHINE_NAME now rejects invalid names and keeps a host on
the home its running server or own machine-id already uses. Hints are
role-specific and aimed only at the clone.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(orcad): stale-lock reclaim waits out the lock freshness window
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(orcad): log a failed lock heartbeat and say a crashed clone's lock frees itself
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(orcad): align reclaim help, age evidence and clone hint with the freshness window
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): ORCA_MACHINE_NAME always selects its own home
Inferring which home to keep from running owners flipped after shutdown or
reboot and couldn't see macOS boots. A name now deterministically selects
its home, and a multi-line name is refused.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): refuse a whitespace-only ORCA_MACHINE_NAME, and pin reclaim test clocks
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(orchestration): refuse run-use by a worker on the Run it works for
A worker holding an active Dispatch in a Run could bind that Run as its coordinator.
That silently unbound the real coordinator, remembered the worker's address as a
coordinator address (so the worker's own mail in that Run routed to the Run mailbox
from then on), and when the worker later bound its own sub-Run, left the parent Run
with no coordinator at all.
bindRun now refuses a caller whose handle holds an active Dispatch in the Run, with
worker_cannot_coordinate_own_run, before any effect. Creating its own Run for
sub-workers is unchanged.
* fix(orchestration): tell a worker naming its own Run where its mail is
Workers that made a sub-Run ran `check --run <parent>`, were told "This
coordinator terminal is bound to X, not Y", and ran run-use on the parent
to "switch back", unbinding their coordinator. That refusal now says the
Run belongs to their coordinator, that their own mail arrives through
plain `check`, and that they report with `send`; it never mentions run-use.
The run-use refusal now matches the caller the way check and send do
(address, then pane, so a reminted terminal handle is still caught),
also covers Runs above the caller's own through recorded creator_dispatch_id
lineage, skips context-only self-dispatches so a coordinator can still
rebind its own Run, and passes its code through the RPC wire.
* feat(orchestration): refuse run-use over a live coordinator without --takeover
run-use silently took a Run from whoever coordinated it, even a chat or
agent that was still running. It now refuses with run_coordinator_live
when there is positive evidence the current coordinator is running (its
chat is still reachable, or the agent hooks prove its terminal agent
live) unless the caller passes --takeover. Anything unproven (closed chat,
exited or unhooked terminal, another host) rebinds as before, so restart
handoffs need no flag. The probe is async in the RPC handler; bindRun
enforces it only if the Run is still bound to the probed party.
A caller working a Dispatch can never take over, with or without the
flag (worker_cannot_take_over_run). The help text now says run-use is
for resuming a Run and that workers never use it.
* fix(orchestration): stop pointing workers at run-use
Workers learned run-use from error text: "No Run is bound. Use run-create
or run-use first", "Rebind with orchestration run-use", and "Rebind this
terminal with orchestration run-use". Each now says what the caller can
do instead. An unbound worker is told its mail arrives through plain
check and it reports with send; a displaced coordinator is told to stop
and take the Run back only if the user asks. The orchestration skill now
says run-use resumes your own Run, --takeover needs the user's word, and
workers never run it.
* fix(orchestration): stop routing mail to addresses that grabbed a Run's seat
Every address that ever bound a Run is remembered as one of its
coordinator addresses, so mail to it routes to the Run mailbox. When a
worker bound the Run it was working for, its own address joined that
list for good, and its direct mail in that Run kept landing in the
coordinator's inbox. The live database has 45 such rows since
2026-08-20.
All four readers of the remembered addresses now skip one that was first
bound while it worked an unsettled, delegated Dispatch in the same Run.
It is derived from existing rows, so no migration or delete is needed and
rows written by older builds stop mattering. The active-Dispatch check
also matches a worker's orca_session_id spelling, not only its handle.
* fix(cli): keep the orchestration spec file within its line limit
* fix(orchestration): read remembered coordinator Run ids without a type assertion
* fix(orchestration): compare seat-grab times at whole seconds
first_bound_at has no milliseconds, so a worker bound in the same second its
Dispatch settled was counted as grabbing the seat. Compare completed_at at
whole seconds with a strict >.
* fix(orchestration): a worker coordinates only Runs it created
The worker refusals depended on proving the target's coordinator alive, so
a worker could still take any Run whose coordinator was closed, unhooked,
remote or headless. Replace them with one rule derived from existing rows:
a caller working a Dispatch may bind only a Run it legitimately
coordinated before (a remembered, non-seat-grab address of that Run, or a
Run it dispatched work into), never the Run it works for, and never with
--takeover. A same-binding no-op is never refused, and workers are
classified before the legacy gate so they never see its
--takeover-legacy hint. The refusal names the Dispatch and how to end it
with worker-abandon if it is stale. The ancestor walk is gone.
run-use now records which coordinator it probed. If the binding moved
before the transaction, it probes again (three tries) and then refuses
with a retryable run_binding_changed instead of binding over a party
nobody probed. run_coordinator_live names the chat by its title and
worktree, or the terminal by its title and worktree, says it is still
open, and that closing it clears the refusal.
* fix(orchestration): say what happens to mail on takeover and stop naming run-use to readers
The help now says --takeover replaces the coordinator and replays its
unacknowledged mail to you. A replaced mailbox reader is told only that
another session coordinates the Run and to stop reading it.
* refactor(orchestration): throw one non-null refusal from the live gate
* refactor(runtime): host the coordinator presence probe beside the hook presence seam
Main moved the orphan-adoption runtime file; keeping the one-line probe next
to checkHookAgentPresenceFn leaves this PR off that file.
* fix(orchestration): use findLast for the worktree name
* refactor(runtime): move the coordinator presence probe beside the pty presence recheck
Main is moving the runtime construction files; the probe now sits with
recheckHookAgentPresenceForPty, which reads the same seam, so this PR stays
off the files being moved.
* fix(orchestration): keep workers out of their own Run seat
* fix(orchestration): clarify worker Run handoffs in skill
* test: align explicit Run gate refusal wording
* Move coordinator presence beside terminal presence checks
* Walk complete worker creator lineage when binding Runs
* Restore main documentation after merge hook formatting
* perf(orchestration): check run bindings without terminal snapshots
* test(orchestration): narrow SQLite instrumentation before access
* test(orchestration): import the explicit RPC methods module
* test: cover orchestration restart and continued Run handoff
* test: place orchestration CLI integration in CLI project
* test(cli): use explicit module extensions in restart handoff test
* test(orchestration): isolate source CLI integration in subprocesses
* refactor(orchestration): leave the live-coordinator takeover rule to #29292#29008 is the worker fix: a worker cannot bind the Run it works for or an
ancestor, cannot abandon itself to get around that, and addresses it held while
grabbing a seat stop redirecting its mail. The separate rule that refuses any
second coordinator while the first is still open (the presence probe, the
--takeover flag and the run_coordinator_live / run_binding_changed refusals)
moves to #29292, which models Run ownership and hand-over and already builds on
it. run-use binds synchronously again, as on main.
* test(orchestration): cover delegated worker legacy takeover refusal
* test(orchestration): explain source CLI integration timeout
When worker-start had to infer the coordinator terminal, the CLI scoped that
lookup with the command's own --worktree (and --terminal) flags. Those name
where the worker goes, often on another server, so the local runtime rejected
an existing remote selector with selector_not_found before any Task or
Dispatch existed. Infer the sender only from the caller's own directory.
Fixes#33579
* fix(orcad): drive Android emulators from headless orca serve hosts
orcad never installed an EmulatorBridge, so every `orca emulator` verb
failed with emulator_no_active once headless serve moved to orcad. The
emulator modules now read host paths and HTTP through the host ports
instead of importing Electron, and orcad installs the bridge and stops its
managed sessions on shutdown like the desktop does.
Fixes#33650
* fix(orcad): bound emulator teardown inside the shutdown deadline
* fix(orcad): keep idle exit from stopping Orca-started emulators; update emulator skill scope
* fix(orcad): count only still-running Orca-started emulators as idle-exit work
* fix(emulator): prune managed sessions only on a successful adb census
* fix(emulator): release a pruned device's stream and never prune a record reattached mid-census
`orca terminal send --text … --enter` now uses the bracketed paste + Enter agent-prompt path for every recognized agent (not just Claude/Codex), so Pi's #/@ completion and Grok's y/n trust question no longer swallow or answer typed prompts. Agents whose process names collide with ordinary tools (orca, acli, cn, vibe) still need title/hook evidence. A send into a permission/trust menu is refused with a hint to send --text and --enter separately.
Refs #20695
Refs #18399
* feat(managed-server): offer Update and Update anyway on a managed SSH server's row
A managed SSH server only updated on connect, and every connect deferred while
a terminal ran there. Its row now offers Update when this desktop bundles a
newer build than the Orca that runs the host. When running terminals defer it,
Update anyway restarts the server past them; the terminal daemon carries them
across the restart.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(managed-server): Update anyway passes only counted live terminals and keeps Update's version admission
Update anyway now sends the incumbent build it confirmed over; under the host
fence it is refused if another desktop activated a build since, keeps the
newer-host downgrade refusal, and never passes an uncounted terminal census.
The offer also covers hosts activated before the Orca version was recorded,
for the build this desktop already deferred there.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(managed-server): Update anyway also confirms a menu Update the row does not advertise
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(managed-server): the row shows one confirmation at a time
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* ci(e2e): route managed-server update sources to the Update anyway Docker spec
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(agent-teams): run the tmux shim through the headless host's CLI, never the GUI binary
On an orca serve host the runtime has no Electron resources directory, so the
shim fell back to PATH and picked the AppImage's Electron binary, which booted
Chromium and died on the SUID sandbox. Prefer the host's profile-scoped CLI
launcher, and route agent-teams-tmux through the packaged CLI redirect so a
direct Electron invocation never initializes the GUI.
Fixes#33354
* fix(agent-teams): prefer a fresh CLI over a shim bin inherited from an older leader pane
* feat(cli): add orca ports to list a workspace's detected ports
Scripts and agents had no way to read the ports Orca already detects for
a workspace, so finding a dev server on a random port meant redoing the
lsof scan by hand. `orca ports` reuses the host-scoped
workspacePorts.scanHost RPC, keeps the rows owned by the current (or
--worktree) workspace, and prints port, pid, process, connect host,
protocol, how the owner was matched, and the advertised URL. --all shows
every listener on that host. An older runtime without scanHost gets an
"update Orca" error instead of a raw method_not_found.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): resolve folder workspaces in orca ports and match rows by path
Run inside a native folder, `orca ports` failed with selector_not_found
(or picked an enclosing git worktree) because it only searched the
worktree list. It now resolves the cwd like `agent launch`, native
folders first, and shows that host's listeners. Rows are matched on the
owner's path instead of its id, so every instance of a repo-backed
folder workspace keeps its ports even though attribution names only the
first instance as owner. `--all` adds the worktree id when two owners
share a display name, and the skill guide notes that only workspace
rows carry `owner` and `advertisedUrl`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): refuse orca ports for folder workspaces without --all; document the command
Co-authored-by: Manuel Meurer <manuel@meurer.io>
* fix(cli): recognise native folder path selectors in orca ports; note SSH scan limits
Co-authored-by: Manuel Meurer <manuel@meurer.io>
* fix(cli): refuse a folder path shared by several folder workspaces in orca ports
Co-authored-by: Manuel Meurer <manuel@meurer.io>
* fix(cli): refuse a path a worktree and a folder workspace share in orca ports
Co-authored-by: Manuel Meurer <manuel@meurer.io>
---------
Co-authored-by: Manuel Meurer <manuel@meurer.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(connectors): cancel a conversation's queued work and stop its agent, behind experimentalConnectors (B4)
* test(connectors): drop a type assertion from the interrupt test
* fix(connectors): interrupt only a running main-agent turn, never background-only work
* chore(connectors): shorten the interrupt comment
* fix(connectors): fence cancel and prompt keys at transport handoff
* fix(connectors): clear the prompt Claude restores after our cancel, and end a turn our cancel rejected
* fix(connectors): require stronger evidence for cancel cleanup and settlement
* fix(connectors): cancel waits for a published agent's link, keeps cancel headroom in a full backlog, and pastes nothing after an unsettled clear
* fix(connectors): bound cancellation settlement and preserve unresolved lanes
* refactor(connectors): drop the leftover-prompt clear after cancel; keep the rejected-turn end
* fix(orcad): add --reclaim-stale-lock for a lock no start may judge
On a Linux host with no machine id whose ~/.orca is on a network or FUSE
home, a lock left by the host's own previous boot names a PID that is
evidence only on the machine that issued it, so every start after a
reboot refused it, and the only way out was deleting orcad.lock by hand.
Starts still refuse it: losing contact is not proof of exit, and a home
other machines may share must never be taken over automatically. Now:
- `orca serve --reclaim-stale-lock` (and `orcad --reclaim-stale-lock`)
checks that the lock was written on this host, in an earlier boot, at
least 2 minutes ago, and that nothing answers at its holder's
endpoints. It prints the pid, host, boot and age and warns about other
machines sharing the home, and clears the lock only with --yes,
through the normal race-safe reclaim of that exact record.
- Lock records now name their host, as evidence for that command.
- The refusal has its own code, orcad_instance_lock_holder_unverifiable,
names the command, and exits 3, so `orca serve --supervise` waits on it
instead of giving up, and the desktop refuses on it like a held lock.
- orcad advertises orcad.stale-lock-reclaim.v1 so a client can offer
the command on hosts that have it.
Fixes#32177
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): let --reclaim-stale-lock clear a reclaimer cut short by the reboot, and probe IPv6
A reclaimer from the same earlier boot on this host that the reboot cut
short left a recovery owner the command could never judge, so --yes
always failed. The confirmation now covers such an owner too, and only
one from this host's earlier boot. An IPv6 WebSocket endpoint is probed
by its bare address.
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(cli): ship the stale-lock reclaim module with packaged builds, and refuse an unreachable lock
The CLI loads main modules from out/main after the main build replaces
it, so the reclaim module becomes a stable plain-Node entry and is
unpacked from the asar. A lock that cannot be stat'ed for any reason other
than absence (a permission error, say) is now a refusal, not "nothing to
reclaim".
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): make --reclaim-stale-lock name the real data root and report a status
- The refusal prints a runnable command for the data root it refused:
an orcad names its own runtime and entry plus `--data-root <dir>`,
since managed hosts have neither `orca` nor `orcad` on PATH and their
data root is not the default. The hint is Linux-only.
- Both entry points take `--data-root` and `--json` and report one of
none, eligible, refused or reclaimed, each with its own exit code
(4, 2, 1, 0), so a missing lock never reads as a recovery.
- The evidence says nothing answers on this machine, and that the host
name and boot checks cannot rule out another machine with the same
name; --yes stays the gate.
- wss endpoints default to port 443, a same-boot branch that could never
run is gone, and the supervisor's standby line points at the command.
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): point the eligible message at the same command plus --yes
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): refuse an empty --data-root, and name the right program in reclaim hints
- `--data-root` with no usable value (a trailing flag, an empty or blank
string) prints usage and exits 1 on both entry points, never falling
back to the default profile.
- A refusal raised while the reclaim command itself runs names
`orca serve --reclaim-stale-lock`, not the binary the CLI runs under;
an orcad still names its own runtime and entry.
- The supervisor's standby hint includes this profile's --data-root.
- The unreadable-lock test is skipped when running as root.
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* test(cli): reuse the existing client stub for the --data-root refusal test
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
---------
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>