Commit Graph
1228 Commits
Author SHA1 Message Date
Neil 7e0e8324af [CI] Fix account fixture timestamps and SSH listing assertions (#27704) 2026-10-11 18:55:59 -07:00
OrcaWinandOrca Worker 83056e5edb fix(skills): judge official skill updates by ownership, not snapshot matching (#27603)
* fix(skills): judge official skill updates by ownership, not snapshot matching

Orca decided whether an installed official skill was pristine by matching its
bytes against a shipped list of past snapshots, falling back to the skills CLI's
lock hash. Copies installed between releases, CRLF copies, and installs whose lock
recorded a sha256 hash all read "doesn't match the official version" and could not
be updated (#26841), and older content could be labelled newer and never offered.

Now an official skill is Orca's when the skills.sh global lock says it came from
stablyai/orca, and it is current only when its listed files equal the bundled
manifest (line endings and sidecars ignored); anything else is outdated. Install
and update are one pinned `skills add .../tree/v<appVersion>` command, used by the
in-app runner, `orca skills update`, and the Settings rails. The update dialog
preselects Orca-owned rows and lists same-named skills from elsewhere unchecked.

Removes the snapshot registry, release mapping, git-tree identity, lock trust and
convergence logic, and the release-cut provenance step.

* ci(skills): run the pinned-add round trip on a skills CLI that can fetch a commit

* fix(skills): let orca skills update target the shared folder on a bare host

Update became the same pinned add as install, so it inherited install's
refusal when no agent is detected. That broke the bare-host update the old
command guaranteed, and the built-CLI check (update --dry-run, no --agent) on
CI runners. The in-app runner already fell back to universal; both now share
one detectSkillsCliUpdateAgentKeys rule.

Also brings the CLI skills docs off `npx skills update`.

* refactor(skills): derive the update selection from the grouped rows

The selection hook took the live and the retained inventory, re-derived Orca
ownership from installations beside the grouping's own orcaOwned, and kept a
separate display count. Groups already carry both eligibility and ownership,
so the hook reads them once; the button's existing live-scan gate is the only
authorization check. The unselected line is inlined into the headline.

* refactor(skills): drop helpers the ownership design made redundant

- isOwnerManagedSkillScope only negated into the participation check once
  plugin caches stopped participating; fold it in.
- Eligibility re-checked resolvedPath/physicalIdentity, which observation
  already turns into 'inaccessible'.
- The manifest verifier probed access() before a readFile that throws anyway.
- orchestration-install-command.ts only forwarded one constant from the lib
  module its three importers already import.

* i18n(skills): stop naming npx skills update in four skipped-copy strings

The es/ja/ko/zh cantUpdateReason and tipDuplicate strings still named
`npx skills update`, which Orca no longer runs for its skills. Say 'the update
command' instead.

* refactor(skills): inline the single-use pinned source URL helper

orcaSkillsSourceUrl was exported but only called by the builder beside it.

* fix(skills): let an update choice lapse when the install source changes

The selection froze every checked name, Orca's preselection included, the
moment the user ticked anything. A re-check that then attributed a name to
another source kept it checked, replacing it without consent. Store only the
user's explicit choices, keyed by name and lock source, and default to
ownership otherwise.

* fix(skills): label the empty update action 'Update skills', not 'Update 0 skills'

The button stays whenever a row is updatable, so unticking every row (or a
dialog with only non-Orca copies outdated) doesn't reflow the footer. At zero
selected it stays disabled and reads 'Update skills' instead of a zero count.
The label lives beside the dialog's other count copy.

* fix(skills): let keyboard focus open the Not from Orca tooltip

The source of a non-Orca copy is only in the tooltip, and its trigger was a
plain span. Make it focusable like Orca's other tooltip-on-text triggers
(tabIndex 0, cursor-help, the row primitive's focus ring), as in the agreed
mock.

* test(skills): hold the round-trip add equal to the shared install builder

The CI round trip hardcoded its skills add argv, so it could drift from what
Orca runs. A .mjs script can't import the TS builder (extensionless imports),
so the argv moves into an exported roundTripAddArgs and a unit test asserts it
is the builder's unattended add with the tag swapped for the PR commit. The
script runs under the same main guard as the manifest generator.

* i18n(skills): translate the skill row's location count and duplicate reason

es, ko and zh still carried English for SkillUpdateRow.oneLocation and
manyLocations, and es and ko for SkillFreshnessRow.skippedReasonDuplicate.

* fix(skills): pin official skill installs to the build commit and skills CLI

`skills add .../tree/v<version>` only works for stable and RC builds: hourly,
daily and adhoc builds publish elsewhere, so stablyai/orca has no tag for their
version and both install and update failed there. Every build is made from a
commit that exists in stablyai/orca, so the build now stamps `git rev-parse HEAD`
and the one shared builder pins to `tree/<commit>`, which equals the bundled
skills by construction. Main, renderer, web and vitest get it as
ORCA_BUILD_COMMIT (replacing ORCA_APP_VERSION); the tsc-built CLI reads it from
the compiled out/package.json boundary. A missing or malformed commit fails the
build or the command with a clear error instead of building a bad URL.

The builder also pins the skills CLI (`npx skills@1.7.2`): 1.5.x cannot fetch a
commit, and a bare `npx skills` can reuse a stale cache or resolve to another
binary (#18687). The CI round-trip script reuses the same constant.

* ci(skills): run the round trip on the shared pinned skills CLI version

* docs(skills): document the commit-pinned skills add

* refactor(skills): keep the pinned skills CLI version in the install builder

skills-cli-version.ts existed only so the plain-Node round-trip script could
strip-load a .ts file, which needed --disable-warning in CI. The version now
lives beside the builder that uses it; the script keeps a literal, and the
existing round-trip test already asserts its argv, skills@<version> included,
equals the builder's.

* refactor(skills): validate the build commit once, where it is resolved

resolveBuildSourceCommit already refuses anything but a full hash, and both the
define and the CLI's stamped package.json come from it. The builder's second
check could only fire as a module-load throw in the renderer's command
constants. Also drops the resolver's unused cwd parameter.

* test: stamp a fixed build commit instead of running git in the vitest config

Tests only interpolate ORCA_BUILD_COMMIT, so they need not read HEAD (or fail
outside a git checkout) on every run.

* refactor(settings): match only skills add in the Windows npx preflight

Every official skill command is now the builder's skills@<version> add; no
rail emits skills update any more.

* fix(skills): fail an update that leaves a broken skill link behind

Eligibility already skips names with a broken link before the run, so one
afterwards is the run's own damage; report it instead of claiming success.

* ci(release): refuse to tag when the skill manifest is stale

The removed --release step implicitly checked the committed manifest against
skills/. Keep that guarantee with a verify-only run; it writes nothing.

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
2026-10-11 18:30:03 -07:00
Brennan Benson 4526d8bab4 native chat: queued-message actions and question answers accept through their own receipt (#26988)
* feat(native-chat): add a chat-owned command receipt store

Adds the agent_session_command_receipts table and an insert-if-absent
receipt write that runs inside a command's own journal transaction. A
receipt records the command's identity, canonical hash, status and a
pointer to the row holding its result; it dies with its chat record.
Nothing uses it yet: the existing operation ledger stays authoritative.

* fix(native-chat): key command receipts like today's ledger ids

Rows are keyed by caller and operation id; a send looks across callers and
other methods look up only their caller's row, matching the existing ledger.
Bad rows and newer table shapes read as unreadable instead of throwing.

* fix(native-chat): order receipt lookups by insertion and key by operation id

Global lookups now take rows in insertion order, so a read and an insert
agree on which receipt answers an id regardless of the host clock. The
primary key leads with the operation id, so its own index serves both
lookups.

* fix(native-chat): accept sends through their own receipt

Send (direct, queued, steer) and /compact no longer commit a separate
ledger reservation before the message is saved. Their command receipt is
inserted-if-absent in the same transaction as the submission or queued
draft; a repeated id replays from it, a changed request conflicts.
Operation ids are checked for syntax only, so age, clock skew, pruning
and the reservation's own storage can no longer refuse a send.

The ledger success row they already co-committed stays as a temporary
insert-if-absent write so families not yet switched keep seeing these
ids; it is never read on this path.

* fix(native-chat): answer a send's receipt one way, share /compact's id space with Send, wake delivery once

- After its commit, a send whose publication fails answers through the same receipt replay a retry takes, so one id gets one answer; the in-memory copy and journal reload are gone.
- /compact ids are global like Send's: a retry under a new connection replays instead of needing a second acknowledgment write.
- The receipt route calls its runner directly; the runner wakes delivery when a new message row commits.
- The compatibility ledger row expires from host time; each temporary site is labelled.
- Receipt read errors and post-commit failures are logged.

* test(native-chat): expect receipt answers where tests assumed the send ledger

Restart-continuation tests now model the case Send cannot vouch for (saved but
not loaded into memory) and keep it unconfirmed; a later throw after the message
is in the chat answers continued, as a resend would. Drop /compact's unreachable
legacy replay branch and fix stale comments.

* test: run the queued tests that open the journal database in the Node runtime project

* fix(native-chat): queued-message actions and prompt answers accept through their own receipt

Send Now, Delete, Resume and prompt answers move onto the command-receipt route
Send uses: the receipt is inserted with the command's own write. A no-op answers
only once its receipt commits (otherwise outcome unknown), and a prompt answer's
replay reads the exact revision it was accepted at.

* fix(native-chat): replay a queued action from what its receipt recorded

Send Now's acknowledgement points at the submission it handed off; a question
answer's receipt keeps the accepted resolution; a no-op that cannot save its
receipt answers outcome unknown and holds nothing in memory; classified refusals
pass through.

* docs(native-chat): receipt comments say what a replay answers from

* fix(native-chat): refuse a prompt answer on a newer Orca's journal with the update words

A prompt answer now runs through the same newer-Orca refusal the queued-message actions use, so a read-only journal answers agent_session_journal_unreadable instead of throwing journal_read_only.
2026-10-11 18:25:26 -07:00
OrcaWinandm4air e2b31cbc59 ci(e2e): one managed-SSH lane and routing regex; no relay build in e2e setup (#27640)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 18:18:59 -07:00
Jinwoo Hong 8dfa2b1875 test(e2e): mixed-version, two-client and phone layout baselines recorded on main (#27688)
* test(e2e): record mixed-version, two-client and phone layout baselines on main (P3)

* test(e2e): P3 review fixes: reconnect and I/O proof, restart order bounds, Linux-only baselines

* test(e2e): re-record Linux phone and serve-restart baselines

* test(e2e): P3: echo drawn in the desktop pane; bound the group selection after restart

* test(e2e): re-record serve-restart group selection

* test(e2e): name P3 baseline helpers for what they record
2026-10-11 21:18:16 -04:00
Brennan Benson c9097ac991 test: run a structured chat against the packaged headless server (#26527)
* fix: preserve module URLs in the headless server bundle

* test: exercise structured chat on the packaged Node server

* test(orcad): run the packaged chat check from the desktop's server template

The chat check loaded the server bundle directly, so a desktop build missing its
server template still passed. Materialize the slot from the built template the way
the desktop does, and replace the fixed streaming pause with a test-owned
acknowledgement so the partial-reply assertion can't race.

* Connect the packaged chat test through a paired connection

Main now sends remote runtime requests over a paired connection rather than a
pairing offer, so the test converts the server's offer once when it is ready.
2026-10-11 17:46:15 -07:00
Brennan Benson ee34f729be Keep SSH chat providers alive after the desktop disconnects (#26473)
* fix: preserve structured chat work during automatic server stops

* fix: require stop-request support before automatic cleanup

* fix: retain unverified session owners until exit is proven

* fix: preserve unreadable work and retry expired prompt stops

* fix: give unheld reservations and queued sends retirement exits

* fix: clear empty recovery leases and preserve unverified owners in tests

* Keep managed servers alive while chat providers are loaded

* Recheck returning clients before managed idle shutdown

* test: run the managed idle exit chat provider test in the Node runtime

It builds on the native chat rest test rig, which opens a real SQLite database.
2026-10-11 17:24:25 -07:00
Jinwoo Hong 29dca8c031 ci: the layout oracle gates merges (#27600)
* ci: the layout oracle gates merges

An oracle-only job joins verify's needs. It runs only the two layout oracle
specs through the existing e2e workflow, routed by layout writer paths; a PR
outside the route skips it and verify treats the skip as a pass. The route is
widened to the terminal store, terminal pane, graph sync, frozen mirror and
compatibility folders while the layout-holder stack is open. The oracle specs
leave the advisory e2e job so a PR does not run them twice.

* ci: the layout oracle tests the merge commit and routes its harness and stack writers

Review fixes: run on the merge commit so a stale-base PR cannot pass on an old
main; route the oracle's own e2e harness and runtime client (a change there broke
main's oracle without running it), and the window-side layout writers the stack
edits; move the route into its own module.

* ci: route the remaining layout writers the stack edits to the layout oracle
2026-10-11 19:39:59 -04:00
OrcaWinandm4air df2f2a72de refactor(ipc): filesystem and repo handlers are local or runtime only (#27609)
* refactor(ipc): filesystem and repo handlers are local or runtime only

* test(ipc): drop two casts in the rewritten listing and import tests

* fix(providers): keep the default error name so IPC callers see the old text

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 15:41:56 -07:00
OrcaWinandm4air c9730df4c8 refactor(renderer): no rebound-settings owner pattern (#27607)
* refactor(renderer): no rebound-settings owner pattern

* chore: lower focus-read baseline for composer owner scalar

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 15:34:24 -07:00
Jinwoo Hong aa1eca1d11 chore(layout): delete the dev-only layout round-trip watch (#27597)
The layout oracle checks the saved profile's round trip at every settled step and the live layout's model rules on every published frame, which covers what this 1 s settle logger did.
2026-10-11 18:18:10 -04:00
OrcaWinandm4air cc04684acb refactor(ssh): SSH status copy lives in renderer/src/ssh and says what the build does (#27604)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 15:05:54 -07:00
OrcaWinandm4air 6dafde48e7 refactor(renderer): no client SSH operation arms in project creation or native chat (#27593)
* refactor(renderer): no client SSH operation arms in project creation or native chat

* fix(add-project): show the start step when the remote step loses its server

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 14:56:50 -07:00
Neil c180ba6338 [CI] Narrow daemon fixture checks and advance coordinator test clocks (#27592) 2026-10-11 14:42:38 -07:00
OrcaWinandm4air bd54fc7fa3 refactor(renderer): delete the direct-SSH authority and reconnect coordinator (#27587)
No ssh: git provider is registered in production, so the reconnect
coordinator's catalog and lineage reads always came back non-authoritative
and its worktree refresh never merged. Its only live effect was clearing an
unconverted target's stale PTY bindings on each connected push and on wake;
the state bridge now does that directly.

Deletes the coordinator, preparation, worktree refresh scheduler, host
hydration, rollout flag and their product telemetry event, the scoped
direct-SSH reconnect/hydration options, and the now caller-less
repos:listForExecutionHost and worktrees:listLineageForHost IPC handlers.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 14:41:17 -07:00
Brennan Benson fc1686efd6 fix: preserve module URLs in the headless server bundle (#26450) 2026-10-11 14:34:38 -07:00
Neil d65e9bed9f [CI] Improve test clocks and dependency fixtures (#27574) 2026-10-11 14:01:07 -07:00
OrcaWinandm4air f0b310b1b1 refactor(store): delete direct-SSH terminal ledgers (#27569)
Panes stopped spawning on unconverted ssh: rows in #27489, so the retry,
live-binding and history ledgers were written but never read. Delete them,
the retry and settle actions, and the detach transfer. The disconnect and
new-authority clears keep nulling stale ssh: PTY ids exactly as before.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 13:42:25 -07:00
Jinwoo Hong 9ad45591af refactor(layout): keep compatibility code in named folders behind one entry (#27556)
* refactor(layout): keep compatibility code in named folders behind one entry

Moves the old-client translators into src/shared/workspace-layout/old-client/
and the remote layout snapshot recorder and persistence into
src/main/remote-layout-snapshot/, each behind an index.ts. A new
check-compat-boundary-imports script, run by pnpm lint and the PR workflow,
fails when code outside a compatibility folder imports past its index or
when a file other than the folder's named importer imports it. Moves only;
no behaviour change.

* test: drop whole-repo scan from boundary check unit tests; CI step runs it

* fix(lint): list only existing compatibility folders; resolve renderer aliases in renderer files
2026-10-11 16:06:05 -04:00
OrcaWinandm4air 8731ca9672 refactor(rpc): delete host-side terminal source-range acks (#27546)
The host side of the terminal source-range ACK protocol had one producer: the
relay-fed SSH output intake, deleted in #27515. Since then nothing installs the
runtime's source-range hooks and nothing passes source ranges into PTY output,
so every terminal.multiplex subscribe that offers ackOutputSourceRanges is
already answered without it and uses the byte-window ACK.

Delete the ledger, the per-connection registry, the consumer hook surface on
the runtime, the stream-level reservation/commit/rollback plumbing in flow
control, initial snapshot and cleanup, the source-range ACK frame schema, and
the range slicing in output chunks, batching and replay. The subscribe schema
still accepts the ackOutputSourceRanges capability, and the client keeps its
range-ACK support for older hosts. A new golden test pins that an offering
subscribe gets the same reply and frames as a byte-ACK one.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 13:04:34 -07:00
Jinwoo HongandNeil e22fd9c901 feat(macos): show terminal-host Full Disk Access, tag stable-copy daemons, and give Helpers folder strings (#27354)
* fix(macos): preserve terminal privacy identity across app updates

* test(macos): make launchd fixtures portable across host platforms

* fix(macos): probe protected contents and close handles on denial

* fix(i18n): register terminal permission status labels

* fix(macos): fork the daemon when no stable-bundle job can claim the endpoint

A copy, signature, plist or deadline failure before bootstrap, a bootstrap
launchd refused with the job absent, a job whose daemon exited before
answering, and a foreign endpoint all threw out of the launcher. The app then
lost its persistent daemon and fell back to local PTYs, where main forks one.
These now fall through to the existing fork path, which also adopts a foreign
occupant normally instead of as a degraded endpoint. A timed-out bootstrap or
a job still running/unreadable stays fatal, so no second daemon races it.

* feat(telemetry): split daemon origin events by stable-copy launch method

daemon_adopted, daemon_pty_cwd_denied and daemon_pty_cwd_readable gain a
closed-enum launch_method (stable-copy / app-fork / unknown), read from the
spawner path the daemon recorded, so the update fix is measurable per daemon
even when an old forked daemon is adopted across updates. The reliability
gate is a test manifest with no runtime switch, so there is no gate state to
report; spawner_path_class reports the private copy as 'other' alongside
other non-/Applications installs.

* refactor(telemetry): report the stable copy as a spawner path class

The separate launch_method property duplicated what the recorded spawner
path already says. spawner_path_class gains `stable-copy`, classified from
the same path under the private runtime root, and launch_method, its enum
and classifier are removed from all three .strict() daemon origin events.
A deleted copy still reports `missing`.

* refactor(settings): gate terminal-host Full Disk Access on macOS once

The permissions handler already asks for the terminal-host status only on
macOS, so the status function's own platform check and the pane's
'unsupported' branch could never fire. The off-macOS guarantee is now
tested at the handler.

* fix(macos): keep the fork fallback inside the startup PTY gate

The stable launch could run until 55 s after the launch started, so a late
"unavailable" verdict left the fork fallback's own 10 s readiness wait to
finish after the 60 s gate had already moved the app to local PTYs.

The launcher now gives the stable attempt one handoff deadline: the gate
minus the fork's readiness timeout and the 5 s lease/adapter allowance
(45 s). Copy, signature check and plist conversion share one abort signal
that ends early enough for bootstrap and the job's own readiness wait to
meet that deadline; every command otherwise keeps a fixed timeout. An
unavailable verdict past the deadline is reported instead of forking a
daemon that cannot arrive in time. The per-step budget module is gone (its
deletion landed in the previous commit by a staging slip).

The launch body is now two blocks: preparation (plist, plutil, deadline
check) fails as unavailable after removing the copy and job file, and
bootstrap runs in its own try/finally that always deletes the job file.

Retirement is simpler and claims more orphans: one in-flight collection per
process instead of a per-root map and rotating 20-record scan, and the job
record (written before copying) no longer carries a bundle name because
lsof +D scans the whole runtime directory (measured equal cost, same
result on a live copy). A never-submitted copy is retired once its producer
has exited and its job is missing, so a bootstrap timeout or a crash
mid-copy no longer leaves a copy forever; the open-file check still guards
deletion. Collection now starts from the launcher after the attempt.

* docs(macos): ship the daemon launch rules, not the investigation

The signed investigation harness left the tree in the previous telemetry
commit by a staging slip; its results and pinned link stay in the PR. This
trims the reference doc to why the copy and launchd exist, the fallback
states and the cleanup rule, trims the reliability gate to what its
validator needs, and points AGENTS.md at the reference doc next to the
Windows relocation entry.

* fix(macos): hand off to the fork as soon as the stable job exits

A copied daemon refused at exec (for example by Gatekeeper) never answers,
so every fresh start paid the full 10 s readiness wait before the fork
fallback. The readiness loop now reads the job state every 500 ms and
abandons as soon as the job is stopped or missing; a running or
unreadable job is still waited out and never forked beside.

Also drops the dead forkEntryPath the stable launch never read (its
options type now omits it) and un-exports the handoff constant.

* fix(macos): keep daemon copies out of Spotlight and unregister retired ones

Each runtime copy is a full Orca.app, so Spotlight indexed it as an app
and LaunchServices kept a record for it that outlived the copy. A
registered copy claims orca: links and Markdown/CSV files, and becomes
their default handler whenever /Applications/Orca.app is not registered.

New copies go under runtime-*/app.noindex/, which Spotlight skips and which
stops the record LaunchServices made while the bundle was being copied.
Retirement now runs lsregister -u on every bundle in the copy (both the
app.noindex layout and the earlier runtime-*/Orca.app layout) once lsof
shows it unused, then deletes it. A running copy stays registered,
because Local Network access may be resolved through that record.

Collection and stable-copy telemetry match the runtime-* directory, so
copies made before this change are still adopted, classified and retired.

* docs(macos): record the LaunchServices trade-off and the rollback plan

The reference doc now explains why copies sit in a .noindex folder, why
only retired copies are unregistered, and how to turn the copy launch off:
make launchMacDaemonFromStableBundle return null, and keep the retirement
code until no copy-launched daemon can remain, because the old code never
deletes copies.

A test pins that rollback: with the stable launcher returning null, the
launcher forks and still runs the copy collection.

* fix(macos): keep daemon copies registered so Local Network can resolve them

The `.noindex` folder kept copies out of Spotlight and LaunchServices, but
Local Network access is resolved from the signing identifier through
LaunchServices to the executable's Mach-O UUID. After an update that changes
Electron only the copy carries the running daemon's UUID, so an unregistered
copy risks the same Local Network loss main has today. Copies go back to
`runtime-*/Orca.app`; retirement still unregisters each copy before deleting
it, so deleted copies leave no LaunchServices entry. The remaining trade-off:
while `/Applications/Orca.app` is missing, a running registered copy can be
picked for `orca:` links and documents.

* fix(macos): hide daemon copies from Spotlight and tie the job to Orca

Spotlight listed each runtime copy as a second Orca app. New copies go
back under runtime-*/app.noindex/Orca.app, which Spotlight skips.
Retirement and stable-copy telemetry match the runtime-* directory, so
copies in the earlier runtime-*/Orca.app layout still retire and classify
the same way.

Local Network access identifies the daemon by its code signature and
main-executable UUID, not by a LaunchServices record, so an unregistered
copy keeps it. The launchd job now sets AssociatedBundleIdentifiers to
com.stablyai.orca, which is how a job not installed through SMAppService
names the app it belongs to. Copies are never registered explicitly;
retirement still runs lsregister -u before deleting each one.

* feat(macos): package a signed terminal host helper that runs the daemon on the pinned Node

Contents/Helpers/Orca Terminal Host.app carries the pinned Node, the daemon's
out/main JS and this slice's node-pty, signed inside-out as com.stablyai.orca.
afterPack boots it through one PTY round trip, then fails the build on layout,
Info.plist, macOS floor (NODE_RUNTIME_DARWIN_MINIMUM_OS vs Node's minos),
architecture or signature drift.

* ci(macos): cache and prefetch the pinned Node before packaging

Packaging now fetches the darwin Node from nodejs.org, whose download has no
retry. Each mac workflow caches it with the electron-builder downloads, keyed on
the pin, and warms both darwin targets inside the existing retry wrapper.

* feat(macos): launch the daemon from a copy of the terminal host helper, not the whole app

The stable launch now clones Contents/Helpers/Orca Terminal Host.app (~124 MiB
instead of ~628 MiB) and runs its Node on its daemon entry, without
ELECTRON_RUN_AS_NODE. The copy must still match the running app's designated
requirement. A missing helper falls back to the fork, and macOS below the
helper's Node floor forks without copying.

* docs(macos): describe the terminal host helper, its floor and its identity

* fix(macos): bound the terminal host boot check by its deadline and always clean up

A daemon that stayed silent hung packaging past the 20 s deadline; one that closed the
connection left the hello unsettled so Node exited 0 without cleanup; a malformed line threw
uncaught. Every connect, hello and PTY wait now races the deadline, close/error/parse failures
reject, and the daemon and scratch dir are removed on every path.

* ci(macos): cache the pinned Node on its own key with no restore-keys fallback

Sharing the electron-builder cache let old Node archives accumulate through restore-keys.
Also moves release-mac-build's Electron cache comment back onto its step.

* fix(macos): reject a universal slice for the terminal host and pin its name in one test

packageMacTerminalHost turned an unknown arch into darwin-undefined; it now throws through the
shared mac arch mapping. A test asserts the packager and the desktop agree on the helper bundle
and executable names, replacing a Linux/Windows test that could not fail.

* fix(macos): pass the launchd adoption lease its options object after the main merge

* test(macos): accept a reset as the daemon closing the boot-check connection; keep only passing gate commands

* fix(daemon): bump the terminal daemon protocol to v45 so new macOS tabs start in the terminal host helper

* fix(macos): ship the daemon's required packages in the terminal host and boot it outside the build tree

* style(macos): use a template literal in the terminal host resolution check

* fix(macos): derive the terminal host's packages from the daemon's own module graph

* fix(macos): treat any non-literal daemon load as computed, follow directory loads, and keep nested dependencies

* refactor(macos): move terminal-host telemetry, Settings status and Helper folder strings to a follow-up

Keeps this change to the update-safe terminal host itself. The follow-up restores:
- the `stable-copy` spawner path class in daemon adoption telemetry;
- the per-terminal-host Full Disk Access row in Settings and its daemon RPC;
- writing folder usage descriptions into the app's Electron Helpers for the fork fallback.

The helper still takes its Desktop, Documents and Downloads descriptions from
`macos-folder-usage-descriptions.cjs`, so that constant stays.

* feat(macos): report terminal-host Full Disk Access, classify stable-copy daemons, and give Helpers folder strings

Restores what a32018836b moved out of the terminal host change:
- daemon adoption telemetry classifies a daemon spawned from the private copy as `stable-copy`;
- Settings shows the terminal hosts' own Full Disk Access verdict beside the app's, through a
  new `fullDiskAccessStatus` daemon request that older daemons answer as unknown;
- packaging writes the Desktop, Documents and Downloads descriptions into the app's Helper
  bundles, which still host terminals when the fork fallback runs.

* fix(i18n): restore en.json to this branch's base, not newer main

The previous commit took the file from a newer main, which pulled unrelated strings into this PR.

* refactor(macos): publish one terminal-host copy per helper build under a fixed launchd label

Name the copy after the helper's CDHash, reuse it when present, and
publish a new one by cloning into a staging dir, verifying it once
against the app's designated requirement and renaming it into place.
One launchd label per profile and protocol replaces per-launch labels,
so job.json, producer pids and per-label collection go away. Retirement
deletes any other copy lsof shows unused. The stable launcher returns
null for every fork fallback and logs its reason.

* fix(packaging): copy terminal-host dependencies from where Node resolves them

A nested package's own dependencies were never walked, so a hoisted
dependency of a nested package was left out of the helper. Resolve each
dependency through the node_modules lookup Node performs from its parent
and copy it to the same relative place, unless a copied package already
carries it.

* fix(packaging): fail release and CI mac builds that cannot boot a terminal-host slice

An arm64 runner without Rosetta skipped the x64 helper's PTY boot check
and shipped the slice untested. Release channels and CI now fail there;
local cross-arch builds still skip with a log line.

* docs(macos): describe the per-build terminal-host copy and its fallback reasons

* docs(macos): keep the codesign command on one line

* test(macos): type the launchd test state without an assertion

* docs(macos): name what the login-session flag gates in the stable launcher

* fix(macos): wait for launchd to drop a booted-out terminal job before reusing its label

* refactor(daemon): keep the health request types in their own module

types.ts hit the line limit once the Full Disk Access status request joined the union.

---------

Co-authored-by: Neil <neil@stably.ai>
2026-10-11 16:03:26 -04:00
Jinwoo Hong a0b0328f99 fix(ci): a removed layout writer no longer fails other PRs' ratchet check (#27557)
#27529 removed two main-process layout writers after the ratchet landed, so main's
baseline went stale and every PR failed the check. Prune the baseline and report a
shrunk count as a warning; only growth fails.
2026-10-11 15:38:44 -04:00
Jinwoo Hong dbd97f7d67 refactor(terminal): keep mobile content-fact caches in their producers (#27537)
The agent-status projection and mobile terminal theme kept their caches on
the shared graph state object. Each producer now owns its cache, so neither
imports the graph state or graph types; the graph still calls them as before.
2026-10-11 15:20:24 -04:00
Jinwoo Hong e969881be5 chore(ratchet): layout-writer ratchets for main and renderer (#27431)
* chore(ratchet): layout-writer ratchets for main and renderer

Two per-file ratchets that may only go down: main-process callers of the
Store's layout setters plus direct edits of saved session partitions, and
renderer writes of the window's layout and per-view selection fields
(including computed-key and spread writes, counted where the key or object
is built). The frozen-mirror writers are exempt. Wired next to the
focus-read ratchet in lint and the PR workflow.

* chore(ratchet): count only membership writes of editor and browser entries

A .map over the existing openFiles or browser tab list keeps its entries
and order, so it is a content update (draft, git status, URL) and is no
longer counted by the renderer layout-writer ratchet.

* chore(ratchet): ignore variable keys and pass-through shorthands

A variable key such as exitCodes[ptyId] names no field, so only string
keys count. A shorthand key counts only in an object handed to set,
setState or a Store writer; elsewhere it passes a value on.

* chore(ratchet): prune renderer baseline after main moved
2026-10-11 14:55:11 -04:00
Jinwoo HongandNeil 3f8d296b8d fix(macos): preserve terminal permissions across app updates with a small signed helper (#27021)
* fix(macos): preserve terminal privacy identity across app updates

* test(macos): make launchd fixtures portable across host platforms

* fix(macos): probe protected contents and close handles on denial

* fix(i18n): register terminal permission status labels

* fix(macos): fork the daemon when no stable-bundle job can claim the endpoint

A copy, signature, plist or deadline failure before bootstrap, a bootstrap
launchd refused with the job absent, a job whose daemon exited before
answering, and a foreign endpoint all threw out of the launcher. The app then
lost its persistent daemon and fell back to local PTYs, where main forks one.
These now fall through to the existing fork path, which also adopts a foreign
occupant normally instead of as a degraded endpoint. A timed-out bootstrap or
a job still running/unreadable stays fatal, so no second daemon races it.

* feat(telemetry): split daemon origin events by stable-copy launch method

daemon_adopted, daemon_pty_cwd_denied and daemon_pty_cwd_readable gain a
closed-enum launch_method (stable-copy / app-fork / unknown), read from the
spawner path the daemon recorded, so the update fix is measurable per daemon
even when an old forked daemon is adopted across updates. The reliability
gate is a test manifest with no runtime switch, so there is no gate state to
report; spawner_path_class reports the private copy as 'other' alongside
other non-/Applications installs.

* refactor(telemetry): report the stable copy as a spawner path class

The separate launch_method property duplicated what the recorded spawner
path already says. spawner_path_class gains `stable-copy`, classified from
the same path under the private runtime root, and launch_method, its enum
and classifier are removed from all three .strict() daemon origin events.
A deleted copy still reports `missing`.

* refactor(settings): gate terminal-host Full Disk Access on macOS once

The permissions handler already asks for the terminal-host status only on
macOS, so the status function's own platform check and the pane's
'unsupported' branch could never fire. The off-macOS guarantee is now
tested at the handler.

* fix(macos): keep the fork fallback inside the startup PTY gate

The stable launch could run until 55 s after the launch started, so a late
"unavailable" verdict left the fork fallback's own 10 s readiness wait to
finish after the 60 s gate had already moved the app to local PTYs.

The launcher now gives the stable attempt one handoff deadline: the gate
minus the fork's readiness timeout and the 5 s lease/adapter allowance
(45 s). Copy, signature check and plist conversion share one abort signal
that ends early enough for bootstrap and the job's own readiness wait to
meet that deadline; every command otherwise keeps a fixed timeout. An
unavailable verdict past the deadline is reported instead of forking a
daemon that cannot arrive in time. The per-step budget module is gone (its
deletion landed in the previous commit by a staging slip).

The launch body is now two blocks: preparation (plist, plutil, deadline
check) fails as unavailable after removing the copy and job file, and
bootstrap runs in its own try/finally that always deletes the job file.

Retirement is simpler and claims more orphans: one in-flight collection per
process instead of a per-root map and rotating 20-record scan, and the job
record (written before copying) no longer carries a bundle name because
lsof +D scans the whole runtime directory (measured equal cost, same
result on a live copy). A never-submitted copy is retired once its producer
has exited and its job is missing, so a bootstrap timeout or a crash
mid-copy no longer leaves a copy forever; the open-file check still guards
deletion. Collection now starts from the launcher after the attempt.

* docs(macos): ship the daemon launch rules, not the investigation

The signed investigation harness left the tree in the previous telemetry
commit by a staging slip; its results and pinned link stay in the PR. This
trims the reference doc to why the copy and launchd exist, the fallback
states and the cleanup rule, trims the reliability gate to what its
validator needs, and points AGENTS.md at the reference doc next to the
Windows relocation entry.

* fix(macos): hand off to the fork as soon as the stable job exits

A copied daemon refused at exec (for example by Gatekeeper) never answers,
so every fresh start paid the full 10 s readiness wait before the fork
fallback. The readiness loop now reads the job state every 500 ms and
abandons as soon as the job is stopped or missing; a running or
unreadable job is still waited out and never forked beside.

Also drops the dead forkEntryPath the stable launch never read (its
options type now omits it) and un-exports the handoff constant.

* fix(macos): keep daemon copies out of Spotlight and unregister retired ones

Each runtime copy is a full Orca.app, so Spotlight indexed it as an app
and LaunchServices kept a record for it that outlived the copy. A
registered copy claims orca: links and Markdown/CSV files, and becomes
their default handler whenever /Applications/Orca.app is not registered.

New copies go under runtime-*/app.noindex/, which Spotlight skips and which
stops the record LaunchServices made while the bundle was being copied.
Retirement now runs lsregister -u on every bundle in the copy (both the
app.noindex layout and the earlier runtime-*/Orca.app layout) once lsof
shows it unused, then deletes it. A running copy stays registered,
because Local Network access may be resolved through that record.

Collection and stable-copy telemetry match the runtime-* directory, so
copies made before this change are still adopted, classified and retired.

* docs(macos): record the LaunchServices trade-off and the rollback plan

The reference doc now explains why copies sit in a .noindex folder, why
only retired copies are unregistered, and how to turn the copy launch off:
make launchMacDaemonFromStableBundle return null, and keep the retirement
code until no copy-launched daemon can remain, because the old code never
deletes copies.

A test pins that rollback: with the stable launcher returning null, the
launcher forks and still runs the copy collection.

* fix(macos): keep daemon copies registered so Local Network can resolve them

The `.noindex` folder kept copies out of Spotlight and LaunchServices, but
Local Network access is resolved from the signing identifier through
LaunchServices to the executable's Mach-O UUID. After an update that changes
Electron only the copy carries the running daemon's UUID, so an unregistered
copy risks the same Local Network loss main has today. Copies go back to
`runtime-*/Orca.app`; retirement still unregisters each copy before deleting
it, so deleted copies leave no LaunchServices entry. The remaining trade-off:
while `/Applications/Orca.app` is missing, a running registered copy can be
picked for `orca:` links and documents.

* fix(macos): hide daemon copies from Spotlight and tie the job to Orca

Spotlight listed each runtime copy as a second Orca app. New copies go
back under runtime-*/app.noindex/Orca.app, which Spotlight skips.
Retirement and stable-copy telemetry match the runtime-* directory, so
copies in the earlier runtime-*/Orca.app layout still retire and classify
the same way.

Local Network access identifies the daemon by its code signature and
main-executable UUID, not by a LaunchServices record, so an unregistered
copy keeps it. The launchd job now sets AssociatedBundleIdentifiers to
com.stablyai.orca, which is how a job not installed through SMAppService
names the app it belongs to. Copies are never registered explicitly;
retirement still runs lsregister -u before deleting each one.

* feat(macos): package a signed terminal host helper that runs the daemon on the pinned Node

Contents/Helpers/Orca Terminal Host.app carries the pinned Node, the daemon's
out/main JS and this slice's node-pty, signed inside-out as com.stablyai.orca.
afterPack boots it through one PTY round trip, then fails the build on layout,
Info.plist, macOS floor (NODE_RUNTIME_DARWIN_MINIMUM_OS vs Node's minos),
architecture or signature drift.

* ci(macos): cache and prefetch the pinned Node before packaging

Packaging now fetches the darwin Node from nodejs.org, whose download has no
retry. Each mac workflow caches it with the electron-builder downloads, keyed on
the pin, and warms both darwin targets inside the existing retry wrapper.

* feat(macos): launch the daemon from a copy of the terminal host helper, not the whole app

The stable launch now clones Contents/Helpers/Orca Terminal Host.app (~124 MiB
instead of ~628 MiB) and runs its Node on its daemon entry, without
ELECTRON_RUN_AS_NODE. The copy must still match the running app's designated
requirement. A missing helper falls back to the fork, and macOS below the
helper's Node floor forks without copying.

* docs(macos): describe the terminal host helper, its floor and its identity

* fix(macos): bound the terminal host boot check by its deadline and always clean up

A daemon that stayed silent hung packaging past the 20 s deadline; one that closed the
connection left the hello unsettled so Node exited 0 without cleanup; a malformed line threw
uncaught. Every connect, hello and PTY wait now races the deadline, close/error/parse failures
reject, and the daemon and scratch dir are removed on every path.

* ci(macos): cache the pinned Node on its own key with no restore-keys fallback

Sharing the electron-builder cache let old Node archives accumulate through restore-keys.
Also moves release-mac-build's Electron cache comment back onto its step.

* fix(macos): reject a universal slice for the terminal host and pin its name in one test

packageMacTerminalHost turned an unknown arch into darwin-undefined; it now throws through the
shared mac arch mapping. A test asserts the packager and the desktop agree on the helper bundle
and executable names, replacing a Linux/Windows test that could not fail.

* fix(macos): pass the launchd adoption lease its options object after the main merge

* test(macos): accept a reset as the daemon closing the boot-check connection; keep only passing gate commands

* fix(daemon): bump the terminal daemon protocol to v45 so new macOS tabs start in the terminal host helper

* fix(macos): ship the daemon's required packages in the terminal host and boot it outside the build tree

* style(macos): use a template literal in the terminal host resolution check

* fix(macos): derive the terminal host's packages from the daemon's own module graph

* fix(macos): treat any non-literal daemon load as computed, follow directory loads, and keep nested dependencies

* refactor(macos): move terminal-host telemetry, Settings status and Helper folder strings to a follow-up

Keeps this change to the update-safe terminal host itself. The follow-up restores:
- the `stable-copy` spawner path class in daemon adoption telemetry;
- the per-terminal-host Full Disk Access row in Settings and its daemon RPC;
- writing folder usage descriptions into the app's Electron Helpers for the fork fallback.

The helper still takes its Desktop, Documents and Downloads descriptions from
`macos-folder-usage-descriptions.cjs`, so that constant stays.

* fix(i18n): restore en.json to this branch's base, not newer main

The previous commit took the file from a newer main, which pulled unrelated strings into this PR.

* refactor(macos): publish one terminal-host copy per helper build under a fixed launchd label

Name the copy after the helper's CDHash, reuse it when present, and
publish a new one by cloning into a staging dir, verifying it once
against the app's designated requirement and renaming it into place.
One launchd label per profile and protocol replaces per-launch labels,
so job.json, producer pids and per-label collection go away. Retirement
deletes any other copy lsof shows unused. The stable launcher returns
null for every fork fallback and logs its reason.

* fix(packaging): copy terminal-host dependencies from where Node resolves them

A nested package's own dependencies were never walked, so a hoisted
dependency of a nested package was left out of the helper. Resolve each
dependency through the node_modules lookup Node performs from its parent
and copy it to the same relative place, unless a copied package already
carries it.

* fix(packaging): fail release and CI mac builds that cannot boot a terminal-host slice

An arm64 runner without Rosetta skipped the x64 helper's PTY boot check
and shipped the slice untested. Release channels and CI now fail there;
local cross-arch builds still skip with a log line.

* docs(macos): describe the per-build terminal-host copy and its fallback reasons

* docs(macos): keep the codesign command on one line

* test(macos): type the launchd test state without an assertion

* docs(macos): name what the login-session flag gates in the stable launcher

* fix(macos): wait for launchd to drop a booted-out terminal job before reusing its label

---------

Co-authored-by: Neil <neil@stably.ai>
2026-10-11 14:54:36 -04:00
Neil e7da462dbf [CI] Run focused checks for Mobile CI tool changes (#27532) 2026-10-11 11:49:05 -07:00
OrcaWinandm4air 3359fd2bfc refactor(ipc): worktree handlers are local or runtime only (#27528)
* refactor(ipc): worktree handlers are local or runtime only

* refactor(runtime): explain the route witness on removal listing

* test(runtime): pin the SSH create refusal and drop the deleted branch's reliability gap

* test(runtime): drop a needless cast in the SSH create refusal test

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 11:48:57 -07:00
Neil 48d76638a3 [CI] Speed up Mobile test execution (#27521)
* [CI] Speed up Mobile test execution

* [CI] Check rebuild watch registrations directly
2026-10-11 11:22:31 -07:00
Brennan Benson 7dfa4d6e54 fix(native-chat): a new chat's model and effort pickers match their first frame before the agent starts (#27031)
* fix(native-chat): a new chat's effort pill keeps its first-frame value before the agent starts

A chat with no model pick runs the catalog's default model at that model's
default effort. The at-rest options answer now says so for every agent, not
only those whose live child reports the model's default, so the effort pill
no longer blanks and then jumps when the agent starts.

* fix(native-chat): read a chat's at-rest options for the folder it runs in

The at-rest options read asked the model catalog with no workspace, so it
always named the account's default model and effort, even in a repo whose
own agent config could pick another. The new chat's first frame, read for
that repo, names nothing there. The at-rest read now asks for the session's
own folder, so both frames agree on the model and the effort.

* fix(native-chat): scope the at-rest options read only for clients that take no model

A client that needs a model in every options answer (mobile today, older
desktops) refuses an answer naming none, and loses that read's commands with
it. Only a client advertising the optional-model capability gets the answer
for the chat's own folder; any other keeps today's account-default answer.

* test: run the at-rest workspace-scope RPC test in the Node SQLite project

* test: build catalog listings so the fixtures compile before and after main drops the tier map

* fix(native-chat): one at-rest rule — the chat's folder decides its default for every client

The folder-scoped catalog read now decides the default for every client. Where
it names one, the answer names that model and its effort. Where it names none,
a client that takes a model-less answer gets none, and one that needs a model
gets the account default model with no effort: exactly what it got before.

The reader is now required, and the first frame and the at-rest read share one
rule for which locations name a local folder.

* fix(native-chat): keep test callers of the host's options read untouched

Only in-process callers omit the reader at the host's entry, and they read
as the RPC gate treats an in-process caller. The shared read itself still
requires one. This leaves main's newer test call sites unconflicted.

* refactor: one native-local location check for Claude, Codex and the at-rest folder read
2026-10-11 10:46:48 -07:00
OrcaWinandm4air 0df25b7ac9 refactor(pty): delete relay-fed SSH output intake and projection threading (#27515)
Nothing in production feeds the SSH PTY output intake: its only data and exit
entry points were called from tests, and the SSH PTY provider that would have
fed it is gone. Delete the intake, its source-obligation ledger, model
admission, projection publication and source-ack plumbing, and strip the
projection ids and source-credit bookkeeping they threaded through the local
renderer delivery path (accept, pending, flush, payload, accounting, exit,
session). Local terminal delivery is unchanged.

Because the intake also installed the runtime's remote source-range hooks,
this desktop host now answers a terminal.subscribe that asks for
ackOutputSourceRanges the way every orcad host already does: without the
capability, so the client uses the byte-window ACK. No source ranges were
ever attached to local output.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 10:25:42 -07:00
OrcaWinandm4air 6a303be248 refactor(main): agent detection, automations, skills, AI vault and ephemeral VM drop SSH provider arms (#27511)
* refactor(main): agent detection, automations, AI vault and ephemeral VM drop SSH provider arms

* refactor(skills): refuse SSH skill destinations at the branch and delete the relay skill services

* test(preflight): clear the local-detection mock before the SSH refusal cases

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 09:54:46 -07:00
OrcaWinandm4air a4a96fee70 refactor(pty): delete the SSH PTY provider and its registry slot (#27499)
* refactor(pty): delete the SSH PTY provider and its registry slot

Nothing in production registers an SSH PTY provider, so the registry's SSH
map was always empty: every SSH lookup answered undefined or threw the
'No PTY provider for connection' error. Delete the provider stack, its
consumer-session and source-recovery contracts, the registry maps and the
getSshProvider dependency, keeping each caller's existing result for an
absent provider. The registry now dispatches only 'local'; any other host
throws PtyHostNotDispatchableError, which keeps the renderer-matched
message for SSH ids and is never read as a gone or exited PTY.

* test(pty): keep the no-provider SSH routing cases in local-only form

* test: reword a comment naming the deleted SSH PTY provider

* test: drop an import the rebase left unused

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 09:23:28 -07:00
OrcaWinandm4air 47b94ef64a fix(daemon): keep tweetnacl out of the relocated Windows daemon-host graph; guard daemon externals at build (#27504)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 09:04:55 -07:00
OrcaWinandm4air 9c59878fbe refactor(terminal): panes have two transports, local or remote runtime (#27489)
* refactor(terminal): panes have two transports, local or remote runtime

* fix(terminal): keep local-only startup gates off unconverted SSH panes

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 07:27:21 -07:00
OrcaWinandm4air 3835a42480 refactor(rpc): one dispatcher (#27486)
Fold the streaming dispatcher, the unary invocation helper and two
single-importer helpers into dispatcher.ts so request/response and
streaming-unary share one unary path. No behaviour change.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 07:16:30 -07:00
e9279b613e refactor(ssh): drop the legacy-relay bridge and the relay branch of the terminal gate (#27471)
The terminal gate's relay lister always resolved to null in production (no SSH PTY
provider is ever registered), so its relay and previous-relay branches, the legacy
relay route/router/routing, the previous-relay census and the once-connected
re-check could never run. The gate now takes only the host census; census-only
verdicts are pinned by a characterization test written before the change.

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-11 06:12:22 -07:00
OrcaWinandm4air c9a9ad33b8 test(e2e): one managed-host setup path and skip gate for the ssh-orcad specs (#27465)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 05:35:50 -07:00
OrcaWinandm4air bdc0921718 test(e2e): one posixShellQuote; docker-ssh-host fixture names (Phase 3.99 0.11b) (#27449)
* test(e2e): one posixShellQuote; docker-ssh-host fixture names

* test(e2e): leave the main-failing stall-recovery spec untouched

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 05:15:31 -07:00
061cb226e2 refactor(orcad): shared serve-option validation; no daemon barrel (#27443)
orcad now checks its flags with the same validator Electron serve and the
CLI use, so contradictory pairing flags fail with the same message instead
of one silently winning. The CLI launcher drops its duplicate recipe check
(the CLI handler already ran the shared validator).

Removes the daemon-init and cli/runtime/index re-export barrels and the
parsePtySessionId / OrcadInstanceLockError re-exports; callers and mocks
import the defining modules.

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:58:58 -07:00
OrcaWinandm4air 6ad1a670a3 refactor(rpc): delete the SSH-bridge caller scope (#27440)
Nothing mints an SSH-bridge credential since the relay client was removed
(#27214), so the 'ssh-bridge' caller kind, its host binders, result filter,
the CLI bridge-mode policy and the ORCA_SSH_BRIDGE_CREDENTIAL env read could
never run. The allowRemoteCliControl target field stays for older peers.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 03:08:01 -07:00
5651141700 chore: delete verified-unused modules and exports (#27438)
Removes seven modules that only their own tests import, dead orcad exports
and protocol constants, spells orcad's configuration exit code once, reuses
the shared errorMessage helper, and drops links to the deleted
docs/reference folder.

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:01:32 -07:00
OrcaWinandm4air 34d7884a52 chore(ratchet): one focus-read ratchet (#27426)
Fold the empty owner-routing baseline into the focus-read ratchet. The three
deleted focus-routing helpers stay banned as a forbidden-name list.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 02:06:40 -07:00
Neil c69f9d2f62 Add manual cleanup for worktree Electron storage (#27414)
* Add manual worktree storage cleanup command

* Validate cleanup exclusions and preserve failure diagnostics
2026-10-11 01:55:34 -07:00
OrcaWinandm4air 37277808b2 test(ssh): hostile-host cells state managed-orcad expectations only (#27419)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 01:48:01 -07:00
OrcaWinandm4air c5778f3567 ci: drop the relay Windows process-tree job from desktop packaging (#27412)
* ci: drop the relay Windows process-tree job from desktop packaging

* ci: refuse relay-era tags in a directly dispatched mac release build

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 01:32:14 -07:00
Neilandm4air 57452c681f Fix cold proxy authentication in the desktop HTTP client (#26957)
* fix(network): answer authenticated proxy challenges on cold desktop requests

* fix(network): destroy a stalled proxy-fetch body on cancel

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 01:12:48 -07:00
OrcaWinandm4air 6b747f8c2d test(e2e): delete helpers orphaned by relay deletion (#27411)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 01:10:44 -07:00
OrcaWinandm4air 0024735e82 fix(ssh): remove the relay-only remote workspace sync so reconnect never sticks on pulling (#27409)
* fix(ssh): remove the relay-only remote workspace sync so reconnect never sticks on pulling

* refactor(ssh): drop snapshot apply tokens and terminal finalization only the sync used

* test: drop leftover sync-status mock

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 00:56:48 -07:00
OrcaWinandm4air cc5c85fb7a ci: ship the orcad template in hourly and daily builds (#27407)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 00:19:28 -07:00
OrcaWinandm4air 68dc48a21c fix(packaging): unpack the orcad serve-selection entry so orca serve can run it (#27307) (#27404)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-11 00:19:25 -07:00