Commit Graph
1004 Commits
Author SHA1 Message Date
Neil ceb2a6c6d9 docs: add test anti-pattern reference (#31277)
* docs: add test anti-pattern reference

* docs: note real-time test waits

* docs: qualify redundant test guidance

* docs: fix agent guide formatting
2026-10-20 17:32:06 -07:00
Neil ec44a502d5 docs: clarify first-class platform, remote, and mobile priorities (#31265) 2026-10-20 16:50:03 -07:00
Neil bc6b2dd84c docs: load Git guidance on demand [skip ci] 2026-10-20 15:21:57 -07:00
Brennan Benson 67a12c264c fix(native-chat): a chat is named from its first message at once, so a failed name generation no longer leaves 'Codex Chat' (#30392)
* fix(native-chat): name a chat from its first message at once; the generated name replaces it

A native chat's one stored name was written only by a best-effort, one-shot
generation, so any failure left every surface on the 'Codex Chat' placeholder.
The first prompt now names the chat when its first turn starts, and the
generated name replaces it only while the field still holds that seed.

* fix(native-chat): the chat names setting says a chat shows its first message until it is named
2026-10-20 13:02:41 -07:00
NeilandClaude 0ee13f831d fix(ssh): say "Orca on <host>" instead of "managed server" in the UI (#31099)
* fix(ssh): say where Orca runs instead of "managed server" in the UI

Users read "managed server" as hosting run by someone else, so they declined
moving their SSH hosts. Every user-facing string now says "Orca on <host>" or
"this host's Orca server", in all six locales; Settings > "Orca on your SSH
hosts" and the setup line say the code and files stay where they are and only
Orca's list of projects, tabs and terminals moves to the host. CLI command names,
logs and identifiers are unchanged.

Fixes #30880

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

* fix(ssh): reassure only when something moves; name the host's label in its row

Review follow-ups: the reassurance shows only while Orca sets itself up or
moves a host, not on every reconnect; the converting line no longer repeats it;
the row names the SSH host's current label; the section description and the
Move anyway dialog stop repeating themselves; translate the Restart dialog's
buttons; drop "managed" from the remaining raw causes and the external
automation refusal.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-20 04:18:08 -07:00
Jinjing 52eea6dd12 docs: update WeChat QR code for group 13 (#31052) 2026-10-20 00:59:21 -07:00
Neil acc6354363 Shrink feature tour animations without changing pixels or timing (#31012)
* Shrink feature tour animations without changing pixels or timing

* Update README media links for lossless animation assets
2026-10-19 22:11:56 -07:00
Jinjing f14475caa6 fix(browser): label popups from committed document origins (#30540)
* fix(browser): label popup chrome from committed documents

* fix(browser): keep opaque popup documents neutral

* test(browser): prepare real popup identity validation

* test(browser): apply background policy in popup probes

* test(browser): fix popup title and view-lifetime checks

* fix(browser): ignore subframe failures in popup chrome

* rm draft docs

* fix(browser): finish popup probe teardown after signal exit

* test(browser): use typed popup probe window access

* fix(browser): prevent automatic popup title updates

* commit

* fix test
2026-10-19 16:13:54 -07:00
Neil b95845f4aa Revert "docs(editor): design for one editor buffer per file (#30851)" (#30875)
This reverts commit 575d3b2cf6.
2026-10-19 14:07:38 -07:00
Neil 575d3b2cf6 docs(editor): design for one editor buffer per file (#30851)
* docs(editor): design for one editor buffer per file

* docs(editor): address buffer design review (alt version ids, identity, interim adapter, phase 1 split)

* docs(editor): round-2 review: behaviour-preserving phase 1, reload progress, identity rules

* docs(editor): round-3 review: state-only 1a, sharing before version dirty, pending flush, exact-case identity

* docs(editor): round-4 review: OpenFile.id key in 1a, dirty+dirty joins, fenced adapter commits

* docs(editor): define interim surfacing of a fenced stale commit

* docs(editor): round-5 review: OpenFile mirror in 1a, consolidate shared-model records, keep toast for unconverted views

* docs(editor): round-6 review: 1a record lifecycle and invariant, view-installed fence base, mobile rollback, host continuity
2026-10-19 14:01:32 -07:00
NeilandClaude 22b23203c9 style: format the 10 files on main that oxfmt --check reports (#30828)
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-19 11:58:30 -07:00
Neil 59a9da22a0 refactor(pane-layout): retire the unread intent tag; renamedLeafIds is the one layout delta (#30734)
No host ever read intent: 'gesture'. The client stops sending it, the params
schema strips it from older clients, and docs/reference records the rule that a
snapshot never carries intent.
2026-10-19 08:01:07 -07:00
Kelvin Amoaba 162e07cf97 fix(browser): refuse agent clicks while the user is mid-IME composition (#30358) 2026-10-19 11:45:29 +00:00
Neil 25e53f4b0c fix(security): put every trust decision on a host-owned token surface (#30710)
* fix(security): put every trust dialog on a host-owned token surface

Plugin themes write CSS tokens on the document root, and dialogs portal to
body, so any trust surface without plugin-security-chrome inherits them; a
theme could hide what is being approved. The orca.yaml hook trust dialog,
notebook run confirmation, plugin install, remove and rollback dialogs were
missing it. DialogContent gains surface="security", which applies the
host-owned tokens, and a scrollable prop for the plugin dialogs' existing
viewport-height scrolling; every trust dialog uses the surface and a test
lists them. The style guide says when to use each.

* fix(security): keep inline trust decisions on the host-owned surface

The agent command approval card (Allow/Deny) and the browser certificate
override sit outside a dialog, so plugin theme tokens still reached them.
A SecuritySurface primitive puts its child on the same host-owned token set
as DialogContent surface="security"; both use it, and the security surface
test now lists inline trust surfaces as well as dialogs.
2026-10-19 04:21:16 -07:00
Neil d893cf5548 chore(docs): move site runtime and Node types to 24 (#30615) 2026-10-19 00:28:53 -07:00
Neil b331710b31 build: move cloud and docs/site to pnpm 12 (#30600)
The root moved to pnpm 12 in #17156 but these two isolated workspaces were
left on pnpm 10, so CI and deploys carried a second pnpm and pnpm/action-setup.

- Pin the root's integrity-checked pnpm 12.14.0 and regenerate both
  lockfiles (only the pnpm 12 package-manager document is added; the
  dependency graph is unchanged).
- Move settings pnpm 12 ignores out of .npmrc and package.json#pnpm into
  each pnpm-workspace.yaml; onlyBuiltDependencies becomes allowBuilds, and
  cloud keeps esbuild's script skipped as pnpm 10 did. package-manager-strict
  is gone in pnpm 12, whose own version pinning supersedes it.
- docs/site drops --ignore-workspace: under pnpm 12 it skips the workspace
  file, losing the overrides and failing the frozen install. vercel.json now
  pins install/build so a stale dashboard command cannot reintroduce it.
- Cloud and docs workflows use pnpm/setup@v2 like the root; the relay
  unit-test step uses the root's pnpm instead of npx pnpm@10.
2026-10-18 23:51:04 -07:00
Jinjing 81730c0b3d Track usage of closing tabs to left and right (#30557)
* Add telemetry for directional tab close requests

Measure how often people use Close Tabs To The Left and Right, without recording tab titles, paths, or workspace identifiers.

- Sample a stable 10% of installs by hashing the install ID, so membership survives restarts. The app-open event carries the sampled flag so the group can be analysed.
- Cap each direction to one event per app session, tracked in main, so repeated clicks or extra windows cannot inflate volume.
- Count the request before the close flow runs, so cancelled save prompts still count.
- Route both directions through one helper that counts eligible unpinned tabs in visible order.

* Count settings opt-in sessions in tab-close sampling denominator

Enabling telemetry from settings now fires `app_opened` for that session, not only when the opt-in came from the pending banner. Before, settings opt-ins never emitted `app_opened`, so those sessions were missing from the adoption denominator for directional tab close events.

- `trackAppOpenedOnce` now marks the session as tracked only when `track()` accepts the event. An opt-out or environment consent override no longer uses up the session's denominator.
- Tests cover sampling for settings opt-in and the `DO_NOT_TRACK` override.
2026-10-18 21:29:29 -07:00
Jinjing 5ee118a908 fix(source-control): clear unavailable branch line totals (#30475) 2026-10-18 20:44:00 -07:00
Neilandstevelliu 347d0e46a1 feat(cli): set the title of one terminal pane (#30485)
* feat(cli): set the title of one terminal pane

Adds `orca terminal set-pane-title --terminal <handle> --title <text>`; `--title ""`
clears it. The runtime resolves the live handle to its saved leaf and asks the
desktop window to name that pane through a new optional notifier hook
(`ui:setPaneTitle`). Mounted panes apply it through the same local setter the GUI
uses; parked panes get it in the saved layout their next mount reads. The tab's
own name is never touched.

Rebuilt on current main from #24755.

Co-authored-by: stevelliu <stevelliu@tencent.com>

* fix(renderer): a main-owned layout takes a CLI pane title before the window shows it

* fix(renderer): a CLI pane title reaches a never-mounted tab with a rootless layout

---------

Co-authored-by: stevelliu <stevelliu@tencent.com>
2026-10-18 19:48:36 -07:00
4940654793 fix(cli): --host and --project accept the names host list and project list print (#30438)
* Accept host aliases and infer the host for a single-setup project

`orca worktree create --project scalp-it` failed with "Project is not set
up on the selected host" even though the project has exactly one ready
setup, and `--host trader-local` was rejected as an invalid value even
though `orca host list` prints that name. Three separate causes:

- `--project` was matched against the stored `projectId` only, which is a
  provider-scoped string (`github:owner/repo`). The display name shown by
  `orca project list` never matched, so the lookup found nothing and the
  failure was reported as a missing host.
- With no `--host`, the host fallback existed but was unreachable, because
  the project lookup above had already filtered to zero candidates.
- `parseExecutionHostId` accepts only `local`, `ssh:<id>` and
  `runtime:<id>`, so a bare alias could not parse at all. `ssh:<label>`
  already resolved labels; only the unprefixed spelling was missing.

Now:

- `--project` takes the project id or the display name, resolving through
  `project.list` and falling back to the setup's own display name for
  hosts that predate that method. Two projects sharing a name are refused
  rather than guessed.
- `--host` is only required when the project is set up on more than one
  host. A single setup is used directly; an ambiguous one fails with every
  host and the flag to select it.
- `--host <alias>` resolves against both axes: paired servers by name
  before routing, SSH targets by label once a client exists. An alias that
  names a machine on both is refused with the prefixed flag for each.

Errors now echo the flag the caller typed instead of an `ssh:` spelling
they did not use, and carry the hosts to retry with in `nextSteps`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refuse a host alias that collides with duplicated SSH labels

assertAliasNamesOneHost asked findSshTargetByName whether the alias also
named an SSH target, but that function returns undefined for a label two
targets share — deliberately, so an ambiguous label never resolves. Read
as a boolean it says "no SSH target by that name", so an alias naming one
paired server and two same-labelled SSH targets looked conflict-free and
resolved to the server.

The opposite direction was already covered: a unique SSH target against
two servers sharing a name fails through assertEnvironmentNameUnambiguous.
Fall back to ambiguousSshTargets so both axes refuse, and list every
colliding target in nextSteps rather than only the first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Only fall back to setup display names on a server without project.list

findProjectsByName caught every error from project.list and returned an
empty list, so a network failure, a permission error, or a genuine server
fault was indistinguishable from "no project by that name" — and the
caller was then told `Project is not set up on the selected host` for a
project that exists and is set up.

Narrow the catch to method_not_found, the only code that means the weaker
fallback is warranted, matching callProjectHostSetup and listSshTargets in
the same layer. The function now returns null for that version gap and an
empty array for a real miss, so the two cases stay distinguishable at the
call site.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refuse a legacy display-name match that spans two projects

The pre-project.list fallback matches ProjectHostSetup.displayName, which
is the repo's folder name rather than the project's name, so two projects
holding repos with the same folder name both match. selectSetupOnHost
would then have taken the first candidate — targeting a project the caller
never named.

Reject when the matched setups span more than one projectId and name each
one, the same rule the project.list path already applies to duplicate
display names. A single project with several setups is unaffected; the
host selection below still decides between them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Spell the --host placeholder as <host> in the project setup usage lines

The worktree create usage was updated to <host> when aliases became
valid, but the four project setup-* lines kept <host-id> in both the
command specs and the root help text they mirror. Those commands accept
an alias too, so the narrower placeholder hid it from anyone reading help.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Document host names and the optional --host in the CLI docs

The published CLI reference described `--host` as taking only `local`,
`ssh:<target-id>` or `runtime:<environment-id>`, and the automations page
showed `--host <hostId>` as required alongside `--project`. Both now
understate what the commands accept, which is how the original report
started: `orca host list` prints a name, the docs never said you could
type it, so the generated id looked mandatory.

Spell out that `--host` takes the bare name from `host list` on either
axis, that a name resolves only when unique and is otherwise refused with
the prefixed flag for each candidate, and that `--host` is unnecessary
when the project has a single setup. Also note `--project` accepts the
display name from `orca project list`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Name the runtime host id as the paired-server tie-breaker in the docs

The host-selection page told readers to fall back to ids when a name is
ambiguous but only ever showed `--environment <server-name>` for paired
servers — and that selector is exactly the one that cannot separate two
servers sharing a name. Spell out the pair the resolver actually emits in
its nextSteps: `--host ssh:<target-id>` and `--host runtime:<environment-id>`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Spell the automations create usage as --project <id-or-name> [--host <host>]

`automations create` resolves --project and --host through the same
alias-capable resolver as `worktree create`, and its own notes already say
--project takes a display name and --host takes a bare host name. The usage
line still read `--project <id> [--host <id>]`, the last spot left on the old
spelling (flagged by CodeRabbit after the main merge).

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

* Give the fake runtime client cast in the host alias tests its SAFETY note

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

* fix(cli): accept every name host list and project list print, everywhere --project/--host is taken

Extends the alias work to the commands it did not reach and the names it
missed:

- `project setups --project <display name>` filtered by projectId only.
- `project setup-existing-folder|setup-clone|setup-create --project <name>`
  now send the project id that name resolves to (pass-through for ids and
  for servers without project.list).
- `--host "this machine"` (the local row's name) resolves to local, and is
  refused if an SSH target or paired server shares it.
- One pair of wrapping quotes is ignored, since cmd.exe passes single
  quotes through literally.
- With --environment/--pairing-code, a bare --host name is a machine the
  routed server reaches, not a different locally paired server.
- An unknown project is reported as a project miss, not a host miss.

Co-authored-by: Younghwan Chae <chyohw97@gmail.com>

* fix(cli): keep exact project ids over names, and refuse an unverifiable host name

An exact --project id whose only setup is not ready no longer falls through
to a project whose display name equals that id. A bare --host name that
matches a paired server now routes there only once this machine's SSH
targets were actually read, and under --environment/--pairing-code a bare
name always means a machine the routed server reaches.

Co-authored-by: Younghwan Chae <chyohw97@gmail.com>

---------

Co-authored-by: younghwan <chyohw97@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-18 15:22:37 -07:00
Neil 68808db38a chore(docs): replace ESLint with Oxlint (#30180) 2026-10-17 21:51:31 -07:00
Neil 33e6785fe2 fix(deps): update vulnerable dependencies and prune stale overrides (#30143) 2026-10-17 19:01:40 -07:00
Jinwoo Hong 90c1c0ac50 feat(mobile): draw the host Accounts screen from the desktop's page (#30020)
* fix(mobile): wall hosts that cannot serve the page instead of opening native screens

* refactor(mobile): drop the native-route state and the shell fallback prop; unknown routes say unavailable

* test(mobile): read the nullable page route refusal in its policy test

* refactor(mobile): every build is the OTA shell; drop the native/OTA build switch

The owner retired the native-screen fallback with no emergency native build, so
EXPO_PUBLIC_MOBILE_SHELL, mobileShellBuildKind, shellSwitchDecision, the Metro
cache-key suffix and both release workflows' shell input go. Every host route
mounts the shell; a route naming no screen the shell could open gets the
existing refusal screen instead of a native screen.

Claude-Session: https://claude.ai/code/session_6cea92f6

* refactor(mobile): delete native screens the OTA shell no longer reaches

With every build the OTA shell, these native siblings run nowhere: the
native-executed closure (index.js plus every non-web route) does not reach
them, and the page resolves their .web siblings. Each .web sibling takes the
plain name, its web-overrides entry goes, and the native-only rich Markdown
editor and Mermaid WebView generators and their outputs go with them.

Kept: native siblings the node test suite still renders shared screens
through (terminal WebView, browser frame path, clipboard, dictation, media
picker, live input, snapshot budget, input styles).

Claude-Session: https://claude.ai/code/session_6cea92f6

* test(mobile): drop the phone-preview comparison the deleted native sibling held

Claude-Session: https://claude.ai/code/session_6cea92f6

* refactor(mobile): drop the dead web route, flag-era comments and the one-value shell kind

The host route files no longer switch, so their comments say what they do now:
a route naming no screen shows the unavailable screen. app/h/[hostId]/web.tsx
duplicated index.tsx and nothing linked to it, so it and its stack entry go
(the bundle sweep is re-measured: 77 scripts at 15 routes). Diagnostics print
the bridge protocol on its own instead of a shell kind that has one value.

Claude-Session: https://claude.ai/code/session_6cea92f6

* refactor(mobile): one host for the rich editor, plain Text, and drop two unused native deps

MobileSelectableText was react-native's Text, so callers use Text. The rich
Markdown editor's host-facing seams (messages, URL prompt, keyboard inset) are
required now that the page is its only host; the WebView defaults go. Comments
that described deleted native components are rewritten, and
expo-image-manipulator and react-native-uitextview leave package.json and the
lockfile.

Claude-Session: https://claude.ai/code/session_6cea92f6

* feat(mobile): draw the host Accounts screen from the desktop's page

Accounts was the last host screen the shell still drew natively, so its
changes needed a phone build. It is now a page route like Tasks: the
screen moves to src/accounts/MobileAccountsScreen.tsx, accounts.web.tsx
renders it on the page, and accounts.tsx mounts the shell for it.

What React Native Web needed: Alert.alert is a no-op there, so the
reset confirmation, its outcome and a failed account switch are
ConfirmModal drawers (ConfirmModal can now drop Cancel for a notice);
Back goes through the route handoff, which pops the shell's stack; and
the reset idempotency key is built from getRandomBytes, since
randomUUID needs a secure context the iOS custom scheme is not.

edit.tsx edits the phone's own pairing and never renders on the page,
so the route manifest leaves it out and the page's host stack does not
declare it. The script sweep is re-measured for the 14-route tree.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(accounts): answer a same-offer Codex reset retry with its recorded outcome; mobile mirrors the desktop

The desktop keeps no client journal for a reset credit: the host's ledger
owns the attempt. A remote client that lost a reply and retried the same
offer under a new key was refused with "already attempted" (or "unknown
outcome" while the provider call was unresolved), which is why the phone
carried its own durable journal to replay the old key.

The coordinator now answers a request for an offer an earlier key already
claimed as that attempt: the settled outcome, the running attempt, or a
resume of the pending one under its original key. A different offer for
the account is still refused while an outcome is unknown, so nothing can
spend twice. The reply shape is the one a same-key replay always had, so
installed clients with their journal read it unchanged.

With that, the Accounts page sends a fresh key per attempt like the
desktop and keeps nothing on the phone: the AsyncStorage journal, its
client singleflight and the retry-record warnings are deleted, and the
journal-resume recording goes with them.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(accounts): resume an account's unresolved Codex reset when the retry names a newer offer

Review follow-ups:
- Host: after an unknown provider outcome the usage refresh moves the
  offer, so a retry names a newer one. The coordinator now answers it as
  the account's unresolved attempt (resumed under its own key and scope),
  as the desktop's consumeCurrent does, instead of refusing forever. One
  ledger lookup finds own key, offer claimant, then unresolved attempt.
- Mobile: a reply is matched on target, account and account revision,
  not the offer, so the resumed attempt's scope is accepted.
- The key is minted inside requestCodexResetCredit from randomV4Uuid, the
  session helper moved to src/platform/random-v4-uuid.ts.
- RefreshControl goes; the header refresh stays. ConfirmModal's
  onConfirm is optional for an OK-only notice.
- Stale journal comments and the mobile docs line are corrected.
- The edit.tsx page exclusion is dropped from this PR; the script sweep
  is re-measured for 15 routes.
- Root oxlint: escape the apostrophe; zod v4 strictObject.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): secure UUID fallback from expo-crypto; pin reset retry routing

- randomV4Uuid never falls back to Math.random: without crypto.randomUUID
  it builds the v4 UUID from ExpoCrypto.getRandomBytes, as the old reset
  key did. Tests get Node's secure bytes for expo-crypto from the setup
  file, since the native module has no Node build.
- Host tests: a new offer after a settled attempt spends again rather
  than replaying, and a retry naming a newer offer joins a resumed
  attempt in flight (one provider call, original key).

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* chore: restore main's bytes for files the merge's pre-commit format touched

The merge commit's lint-staged run reformatted 27 files this PR does not
change. Committed without the hook so they match origin/main exactly.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* test(mobile): stand in for expo-crypto with a Node alias, not a setup-file mock

Anti-slop forbids module mocking outside test files. The vitest config
now aliases expo-crypto to a faithful Node implementation of the names
shared code reaches; a test file's own mock still wins.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* docs(mobile): match the bridged-parity comments to the measured 795-golden tally

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
2026-10-17 03:11:24 -07:00
Neil f8089c787b fix(orcad): keep the integration credential key only in the owner-only key file (#29859)
* fix(orcad): keep the integration credential key only in the owner-only key file

Managed servers no longer create, read or wait on the macOS login Keychain or
a Secret Service keyring for their credential master key. A record an hourly
build pointed at the keyring is migrated once: the key is copied into the key
file when it reads back without UI within 5s, otherwise a new key file is
started and old credentials show the usual reconnect error. Removes the
locked-Keychain status fields, retry, the integrationCredentials.moveKeyToFile
RPC and the Settings notice.

* fix(orcad): serialize the keyring-record migration so concurrent starts agree on one key

* docs(orcad): note the migration lock

* fix(orcad): publish the migration lock with its PID and bound every wait

* refactor(orcad): reuse the file transaction lock for the keyring-record migration
2026-10-16 15:53:30 -07:00
Jinjing 005f06bbc7 Run automated workspace setup in a dedicated Setup tab (#29819)
* Run automated workspace setup in a dedicated tab

* Preserve native-chat setup route coverage after placement retirement

* Preserve Setup tab design and independent review evidence

* Classify activation test fixtures consistently for routing checks

* Sync runtime English catalog after removing setup preferences

* Update listener savings model after retiring setup action
2026-10-16 14:05:50 -07:00
Jinjing 7f9b51cf5c Fix background native-chat setup terminal seeding (#29810) 2026-10-16 12:38:17 -07:00
OrcaWinandOrcaWin f9d16b1b09 test: load headless ownership regressions once (#29613)
* test: route legacy relay database fixtures through Node

* test: require process exit after daemon cleanup loses contact

* test: load headless ownership regressions in one suite

* test: capture serve recipe cleanup evidence

* test: use typed cleanup diagnostic error fields

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-16 04:19:47 -07:00
Neil 839f553dee fix(orcad): explain a locked macOS Keychain to the user and recover Linear/Jira without a restart (#29608)
* fix(orcad): tell the user when a locked macOS Keychain hides Linear and Jira, and recover without a restart

A managed macOS host reached only over SSH keeps its login Keychain locked
after a reboot, so the server's credential key failed closed and the app
asked the user to reconnect a token that was fine. Exit 36 from
security find-generic-password (errSecInteractionNotAllowed) is now a
'locked' lookup: the server logs it once, retries the Keychain on each
credential use and before each Linear/Jira status read, and status carries
an optional credentialErrorReason: 'keychain_locked' that the app shows in
place of the generic text. Once unlocked, Settings offers a one-click move
of the same key into the owner-only key file.

* fix(orcad): keep retrying a locked Keychain after a timeout, fence the key move to the host that asked, report the lock only for credentials that need the key

* fix(settings): offer the file-storage switch to a paired browser's implicit server too

* fix(settings): route the Keychain notice and key move by the host that reported the status; sweep stale key-record staging; say the moved key is not machine-bound

* fix(orcad): sweep only this machine's key-record staging, so a shared home's other hosts keep theirs
2026-10-16 04:09:33 -07:00
OrcaWinandOrcaWin b3dfd54827 perf(build): skip unnecessary work and reclaim Vite caches (#29479)
* perf(build): remove unnecessary development and config work

* feat(dev): reclaim inactive worktree Vite caches

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-16 00:56:30 -07:00
Neil 52419be3a5 feat(linux): opt-in per-terminal memory and swap limits for the terminal host (#29413)
ORCA_TERMINAL_MEMORY_MAX and ORCA_TERMINAL_MEMORY_SWAP_MAX set MemoryMax and
MemorySwapMax on each terminal's systemd user scope. Off by default, applied only
after the probe scope shows the kernel enforcing them, and dropped (logged) where
the host cannot, so terminal scopes never turn off because of them.

Refs STA-3430
2026-10-15 23:18:21 -07:00
Neil 3074852b7c fix(orcad): seal integration credentials on the headless server instead of storing them in plaintext (#29412)
* fix(orcad): seal integration credentials on the headless server instead of storing them in plaintext

The Node SecretStore always reported encryption unavailable, so every
credential writer on orcad fell back to plaintext. orcad now seals with
AES-256-GCM using a host-owned master key kept in the OS keyring (macOS
Keychain, Linux Secret Service) when reachable at first start, else in a
0600 profile file bound to the machine ID. A key that cannot load fails
closed instead of downgrading. Existing plaintext credentials are sealed
on startup without loss.

* docs: describe how the headless server seals credentials and its limits

* fix(orcad): unique credential staging files, no keyring items for temp profiles, isolate startup test

* fix(orcad): keep the credential key with the credentials, one record per machine

* fix(orcad): never re-key over an unreadable record, serialize first-start key creation, refuse an unrestricted key file

* fix(orcad): verify a key record's Windows ACL and wait out a concurrent first start's keyring write

* fix(orcad): keep a keyring claim and fail closed when its store result is uncertain

* fix(credentials): restrict the staged file's Windows ACL before it replaces a credential

* fix(orcad): a temporary profile never creates a key in, or re-seals, the real credential home

* ci: baseline the two single-file credential ACL restrictions

* fix(credentials): stage Windows credentials born restricted and verify the key record asynchronously; document rollback

* test(bitbucket): inject the write failure into the Windows staging writer too
2026-10-15 23:18:05 -07:00
Neil a37c70dd4c fix(daemon): replace a retired macOS terminal service job that blocks new terminals (#29361) (#29395) 2026-10-15 23:16:59 -07:00
Neil 904b6f2b32 fix(ssh): flag a macOS host whose managed server outlived its launching SSH session (#29371)
* fix(ssh): flag a macOS host whose managed server outlived its launching SSH session

macOS Local Network privacy pins a nohup-launched orcad to the sshd-session
that started it; once that session ends, its terminals lose LAN access (#25934).
A macOS launch now records that session, a connect reports it when it proved
exited, and the host status offers a restart when no terminals are running.

* fix(ssh): retire the idle terminal daemon on a launch-session restart

* fix(ssh): keep the fence on an unsettled restart stop, and report a restart that can't hold its session

* fix(ssh): carry the launch session forward while the terminal daemon survives; never redial for the check

* chore(i18n): add the launch-session warning and restart strings to the English catalog
2026-10-15 23:14:45 -07:00
Neil ac015cd3b2 Fix terminal daemon restart leaving older Codex conversations locked (#29216)
* Recover retired macOS daemon trees during terminal restart

* fix(daemon): never let retired-job recovery failure block restart

A wedged retired job (unkillable descendant, launchctl timeout, recycled
root) previously aborted every untargeted Restart Terminal Daemon, leaving
no way to replace the current daemon short of a reboot. Log the failure
and continue with the ordinary restart instead.
2026-10-15 18:08:22 -07:00
Neil 45862c2b40 Fix terminal daemon restart leaving macOS service registered (#29130) 2026-10-15 03:41:43 -07:00
Neil a7edea45b1 Detect stalled terminal daemon I/O and offer restart review (#29087)
* Detect stalled terminal daemon I/O and offer restart review

* test: update terminal notice store mock for shared navigation
2026-10-15 02:36:46 -07:00
Neil cbc357f547 fix(browser): agent typing into a cross-site frame no longer borrows your keyboard (#29000)
* fix(browser): agent typing into a cross-site frame no longer borrows the user's focus

Keys and text for a focused cross-site iframe went through the focus-borrowing
fallback, because widget input reaches only the guest's own renderer. They now
go to that frame's own CDP target session, found by following the page's focus
through frame elements, which reaches the frame without touching the user's
focus. The proxy keeps those Orca-owned sessions' events from the agent's client.

* fix(browser): retry frame focus emulation after a failed enable

* fix(browser): retry a failed frame focus-emulation enable before sending input
2026-10-14 23:30:13 -07:00
Kelvin Amoaba c056cfc140 feat(native-chat): add a "New" line above unseen messages (#28333) 2026-10-15 00:55:06 +00:00
Jinjing 232f6048e7 Remove obsolete Hermes cron documentation and translations (#28877) 2026-10-14 16:29:28 -07:00
Neil 7244bf3e6f Reclaim idle worktree space automatically on dev startup (#28864)
* Run safe worktree cleanup on dev and add interactive pnpm reclaim

* Rename storage cleanup command to reclaim-space

* Keep real stream constructors in transcript dependency tests

* Detach cleanup output and align historical cache previews
2026-10-14 15:47:02 -07:00
NeilandJerome Würf cf119167a5 fix(jira): support scoped Cloud API tokens (#28604)
Support scoped Jira Cloud API tokens through the configured gateway while keeping self-hosted routing, redirects, diagnostics, and selected-host capabilities bounded.

Co-authored-by: Jerome Würf <oss@scharom.de>
2026-10-14 03:11:32 -07:00
NeilandNikita Maketryuk b428def8f1 feat(cli): open files at a requested line and column (#28240)
Accept positive safe-integer line and column flags through the existing file-open path. Reject invalid or incomplete positions before changing the editor. Bind deferred reveals to the requested workspace and tab, including floating panels, and clamp oversized positions without moving another editor or stealing late focus.

Co-authored-by: Nikita Maketryuk <n.maketryuk@lince.studio>
2026-10-14 00:36:57 -07:00
Neil b5c568e9fb fix(browser): agent bringToFront and activateTarget no longer take the user's focus (#28452)
Adds docs/reference/agent-browser-focus-isolation.md: measured input routing for
<webview> guests and the plan for #20595.
2026-10-14 00:18:40 -07:00
Jinjing 83ddc89596 docs: update WeChat group 12 QR code [skip ci] (#28639) 2026-10-14 00:14:57 -07:00
Neil 3f81541188 Support restarting Windows Orca as administrator (#28073)
* feat(windows): add administrator PowerShell terminal setting

* fix(settings): localize administrator terminal search keywords

* fix(windows): restrict elevated terminal host to Orca's runtime and requesting account

* fix(windows): harden administrator terminal routing, inventory and restore

* fix(build): build the Windows agent hook when electron-builder packages Windows

* fix(build): build the packaged Windows agent hook for the target architecture

* fix(windows): accept the development terminal runtime and test real elevation in CI

* feat(windows): show administrator status and restart instructions

* fix(settings): localize administrator mode search keywords

* test(settings): isolate the desktop permission section in shell picker tests

* Add Windows administrator restart and simplify Terminal settings

* Keep administrator restart silent and settings actions within narrow panes

* Keep Windows shell choices and permission guides usable at minimum width

* Prevent later restarts from replaying administrator terminal reset

* Fix CI route resolution and transient Windows fixture cleanup
2026-10-13 18:06:05 -07:00
github-actions[bot] e439e3850f Update README downloads badge 2026-10-13 12:44:20 +00:00
OrcaWinandm4air 38a4958cad feat(linux): run the AppImage terminal daemon off the mount, on the extracted copy's bundled Node (#28214)
On a validated AppImage the desktop's daemon launch first runs <generation>/resources/node-runtime/bin/node
on the generation's daemon-entry.js when the extracted copy for the file at $APPIMAGE is complete, carries
the bundled Node and the entry, and is the running release. It then falls back to the AppImage's own mount
and the current mount, logging every fallback. The copy rung records $APPIMAGE/<entry> like the own-mount
rung, so either daemon is adopted. Generation leases recognize the bundled Node. macOS, Windows, deb and
rpm never reach it.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-13 04:34:25 -07:00
Neil 7246a0e269 Fix delayed agent launches such as sleep 30 && claude (#28205)
* fix(terminal): preserve preparation and discovery for delayed agent launches

* refactor(agents): centralize launch intent recognition

* refactor(agents): keep launch intent in one module apart from process recognition

Move recognizeAgentLaunchCommand next to the sleep-prefix scanner so the strict
process-table matcher is untouched, name the module away from the agent-launch
funnel files, share one executable-name normalizer, and colocate the
preparation tests with their modules.
2026-10-13 01:55:18 -07:00
Jinwoo Hong 5a77f068b6 Link the Android APK through a stable URL and bump it on release (#28143)
* Link the Android APK through a stable URL and bump it on release

READMEs, the docs site, and the desktop app now link
https://www.onorca.dev/download/android, which the marketing site
redirects to the current APK, so none of them need a per-release edit.
A published Android release opens a PR on the marketing site that bumps
its one ANDROID_RELEASE_VERSION constant; a failed bump is reported in
the job summary and does not fail the release.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* Skip the APK download bump for OTA-shell test builds

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* Bump the APK download for every published Android release

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
2026-10-12 23:00:27 -04:00
Jinwoo Hong 20e4221ba7 docs(readme): point the Android APK links at 0.0.55 (#28134)
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
2026-10-12 21:21:46 -04:00