mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 17:17:38 +00:00
294fd2ac06cfff31e5a7271bcefab040ae31e0de
63
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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 |
||
|
|
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 |
||
|
|
232f6048e7 | Remove obsolete Hermes cron documentation and translations (#28877) | ||
|
|
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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
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 |
||
|
|
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> |
||
|
|
42be4c50d4 |
chore(settings): rename "Active Server" to "Default host for new projects" (#27286)
* chore(settings): rename "Active Server" to "Default host for new projects" The setting (still activeRuntimeEnvironmentId) now only picks the host for new projects with no source and the initial host of the Settings host picker, so the copy says that. Refusal and help text say existing projects stay on their own host, the provider-scope hints point at the Settings Host menu, and the Remote Orca Servers search entry keeps "active server" as a keyword. * fix(settings): credential hints point at the setting that still scopes them --------- Co-authored-by: m4air <m4air@Mac.localdomain> |
||
|
|
15717a4e53 |
Add CLI commands to manage and find workspace references (#26807)
* Add CLI commands to manage and find workspace references * Fix reference review findings: source-context twins, legacy link collapse, closed chats, old-host errors - Keep same-URL links with different source contexts separate; CLI add/remove no longer drops a twin - Restore merging a bare legacy link into its single matching URL link (no duplicate PR rows, no resurrection on older-client removal) - Carry absorbed data through collapse chains; resolve repoId conflicts deterministically - Identity: ignore www., case-insensitive GitHub/GitLab/Gitea paths (stored URL keeps case), no Jira match on git hosts; find accepts self-hosted issue URLs - reference find: skip closed native chats, require a session id for linked, include an explicitly named archived workspace, warm-cache fallback for --worktree - Selector parity: collapse same-host duplicate paths, issue: ignores unlinked rows - CLI: clear update-host error for hosts without reference.*, local flag checks before host probe, help text fixes * Fix CI: add reference rm alias for verb policy; expect linkedItems in worktree ps summary * Simplify reference CLI: share identifier/legacy-match helpers, drop redundant dedupe |
||
|
|
1578716eb0 |
revert(runtime): temporarily restore the previous host Node minimum (#26823)
This reverts commit
|
||
|
|
46460d49c7 |
feat(runtime): require Node 24 for servers and remote hosts (#26171)
* feat(runtime): default to bundled Node 24 and require modern hosts * Update SSH deployment expectations for Node 24 guidance * Expect Node 24 in Windows runtime installation guidance |
||
|
|
55eb48c137 |
Let automations pass extra agent arguments on each run (#26659)
* Let automations pass extra agent arguments on each run Automations could only use the host's default agent Arguments, so a per-automation choice such as a different model needed a settings change that affected every run. Automations can now save extra arguments that are appended to the host's defaults on each fresh run. Extras are allowlisted to model, effort, and Claude's --add-dir, and are refused for permission, config, prompt, and session options. - Add the field through the CLI (`automations create/edit --extra-agent-args`), the RPC contract, the automation store, and the editor's Advanced section, with validation at save and at launch. - Merge extras over the defaults by replacing a model or effort option the defaults already set, then re-tokenize to confirm the launch argv matches what was validated. - Gate writes behind a new runtime capability, and refuse to save or migrate extras to a host that would silently drop them. - Require a fresh session, since reused sessions cannot take new arguments. * Simplify automation argument validation and launch handling * improve the extra args display * fix translation * Validate automation extra args during ORCA migration Dormant automations imported from the migration manifest skipped the extra-args check. A disallowed flag, or Reuse combined with extra args, could persist and then fail every later run. The manifest parser now rejects those rows. Also move the automation runtime capability constants into `automation-runtime-capabilities.ts`. `protocol-version.ts` re-exports them, so existing imports keep working. * add more demo with effort |
||
|
|
6b43714c54 |
feat(agent-sessions): rename "Continue in New Session" to "Hand Off to Another Agent" (#26375)
* feat(session-history): resume a native chat's conversation in a new CLI session Agent Session History offered "Resume in New Chat" to move a terminal session into native chat, but nothing went the other way: once a native chat owned a conversation, its row only reopened the chat, and Orca refused any terminal resume of it so two programs never write one conversation. Rows a native chat owns (Claude, Codex) now offer "Resume in New CLI". It forks: the terminal runs `claude --resume <id> --fork-session` or `codex fork <id>`, so the CLI gets the full history under a new id and the chat is unchanged. The host's resume guard lets a Claude fork through, and the fork tab records no provider session, so a restart never re-enters the chat's conversation. "Resume in New Chat" is renamed "Resume in New Native Chat". * fix(session-history): size the Resume in New CLI tooltip to its text The tooltip balanced one wrapped string inside a box sized before balancing, leaving a gap beside its lines. It is now two block lines with no fixed width. * feat(agent-sessions): rename "Continue in New Session" to "Hand Off to Another Agent" Agent Session History rows now offer "Resume in New Native Chat", "Resume in New CLI" and "Continue in New Session…", which read as three versions of one action. Only the first two carry the same conversation; the third starts a new session, often with another agent, seeded with a summary or the transcript. Rename it everywhere it appears (history sidebar, terminal pane header and menu, native chat menu, the dialog title) and, in the history row menus, move it below "Copy Resume Command" behind a separator so the Resume items read as one group. * fix(session-history): run a CLI fork under the selected Codex account and tighten the fork guard - Resume in New CLI now asks the host for the same Codex account home plain Resume uses, so a fork no longer starts under whichever account's copy of the rollout sorted first. The preparation call carries an optional `fork` flag that skips only the owned-conversation refusal; plain resume still refuses. - An older paired host that refuses the fork now shows "Update Orca on the host that runs this chat to resume it in a new CLI." instead of a raw error code. - The host guard admits `--fork-session` only before a `--` terminator and never alongside `--session-id`, since either shape lets Claude write the owned conversation. - Tests for the click path, the menu item's eligibility, the fork home preparation, and the tightened guard. * fix(session-history): read a Codex rollout's identity from its first session record A fork of an older (non-paginated) Codex thread writes its own session record first and then copies the parent's history, the parent's session record included. The history scanner kept the last one it saw, so the fork's row took the parent's id, title, folder and branch: on a native chat's fork it looked like the chat itself, and Resume on it opened the chat instead of the fork. Codex itself treats the first session record as the thread's own and ignores later ones; the scanner now does the same, as Orca's duplicate-rollout check already did. * fix(session-history): set up status hooks in the Codex home a CLI fork keeps When Resume in New CLI can't move a Codex fork to the selected account (that account has no copy of the conversation yet, or the system default is selected), the fork runs in the account home the history row came from. A new Codex tab only gets Orca's status hooks in the selected account's home, and the fork carries no provider session, so nothing set up the hooks in that row home. In a home only native chat had used, the fork tab could show no working or idle status. The fork's home preparation now readies that home the same way a resumed session's home is readied (hook install or refresh, plus the daemon-socket guard). That code is moved into prepareCodexPinnedLaunchHome and shared by both paths. The fork tab still carries no provider session, so it never reopens the chat's conversation on restart. * fix(session-history): ready only a host-verified Codex home for a CLI fork The fork's hook setup ran in whatever Codex home the request named, so a paired client could have Orca write hook and config files into any directory. Plain Resume only readies a home it has verified: one this host lists for Codex sessions that actually holds the rollout. The fork now uses that same check, through a shared trustedCodexResumeHomes list, and readies the home only when the verified home is the one the fork will run in. With no Codex runtime home service it does nothing, as plain Resume does. A failed check or setup is logged and never stops the fork from launching. Tests cover the untrusted home, a missing runtime home service, a rollout on another host, a WSL home, a fork moved into the real home, and a failed setup. * fix(session-history): show the host-update message when the desktop wraps the fork refusal When the local preparation step for Resume in New CLI is refused, Electron hands the renderer the error as "Error invoking remote method '…': Error: agent_session_conflict". The fork's failure text matched only the bare code, so the toast showed that raw line instead of asking the user to update Orca on the host. It now unwraps the message with the shared IPC error helper before matching. * test(agent-session-history): cover Hand Off placement and separator; rename Codex docs heading * fix(agent-session-history): drop the ellipsis from the Hand Off to Another Agent label |
||
|
|
5cafefe726 |
Phase 3: every SSH host runs a managed Orca server (orcad), replacing the relay (#24863)
* Revert "revert: take the 26 Phase 3 (#16741 port) PRs back out of main (#24559)" This reverts commit |
||
|
+2 |
8e5080c132 |
Validate OpenCode worker model preferences on the execution host (#24624)
* feat(orchestration): support OpenCode worker model selection Allow supervised OpenCode workers to use per-launch model overrides through the existing launch-preference and receipt path. Preserve existing OpenCode agent arguments while replacing only model flags, and reject unsupported effort values explicitly. Keep Native Chat option exposure unchanged and update the worker CLI and orchestration guidance. * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(orchestration): gate OpenCode worker model preferences by host capability Co-authored-by: user141514 <user141514@users.noreply.github.com> * feat(opencode): probe launch capabilities on the execution host * feat(opencode): probe execution-host CLI capabilities * feat(opencode): probe launch capabilities on the execution host * feat(orchestration): resolve explicitly configured command aliases * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(orchestration): verify available OpenCode model on execution host * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * test(readiness): census recorded OpenCode composer boots * fix(opencode): reject redirected overlay parents before cleanup * fix(orcad): retain runtime cleanup when subscribing to hook settings * refactor(launch): extract OpenCode config and attachment authority * fix(opencode): retain host version selection across relay restarts * fix(opencode): pass run prompts as positional messages Preserve run flags and use the existing shell quoting and run-command detector to append the initial message after --, reusing an existing separator. TUI launches retain their version-selected prompt transport and draft behavior. Original run-order work: @coelho-doti (#13065, tracked in #17551). * fix(opencode): keep wrapped run tasks positional Recognize supported environment prefixes and PowerShell call operators without mistaking prompt arguments for executables. Keep environment and run separators separate, preserve the task text and exclude run commands from native submission. Source-parent: |
||
|
|
9207aef01d |
Add an optional shortcut to toggle child workspaces (#24165)
Adds a user-assignable shortcut for the existing child-workspace chip action. It stays unassigned by default on macOS, Linux and Windows. Final-source rendered checks cover Settings recording/reset, guards, scroll preservation and restart. Fixes #24163 Continues mmarabel’s original contribution in this PR. Issue #24163 has no sibling implementation PR. Existing bot findings are fixed, withdrawn or addressed in the PR review. Co-authored-by: mmarabel <166927047+mmarabel@users.noreply.github.com> |
||
|
|
2fc517c1c6 |
feat(cli): add --unread/--read to orca worktree set
Pass validated read/unread flags through the existing workspace metadata update. Contributor attribution correction: the earlier Ctrl+M squash message placed its related link after the co-author footer, so GitHub did not recognize all contributors. Preserve that credit here for https://github.com/stablyai/orca/pull/24100 and its related contribution https://github.com/stablyai/orca/pull/24143 . Related CLI link validation retained from https://github.com/stablyai/orca/pull/20036 . Co-authored-by: Raz Shlomo <12373339+razshlomo@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Zhichang Yu <yuzhichang@gmail.com> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> |
||
|
|
c1d403a47b |
feat(cli): link GitHub and GitLab items on worktree create and set
Expose and validate the existing workspace link fields, preserving omitted values and provider identity checks. Related: https://github.com/stablyai/orca/pull/22609 Co-authored-by: marco song <marco.song@mvlchain.io> Co-authored-by: SongMarco <20613630+SongMarco@users.noreply.github.com> Co-authored-by: Luca Critelli <lucacri@gmail.com> Co-authored-by: Neil <neil@stably.ai> |
||
|
|
6486624b44 |
docs: reference local orca.yaml and .worktreeinclude
Document the existing workspace configuration, include/copy rules and sharing behavior. Co-authored-by: Neil <neil@stably.ai> |
||
|
|
c792386cdc |
docs(terminal): explain local macOS/Linux shell startup files
Document the actual login/interactive shell startup-file order and existing shell setup behavior. Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> |
||
|
|
87f5a98a61 |
Reuse documentation search excerpts during result navigation (#24574)
Memoize the existing pure excerpt renderer by complete raw text for the current result array, retaining original rendering as a miss fallback. |
||
|
|
7539d19416 |
Skip impossible link and tag matches in docs search results (#24646)
* Skip impossible HTML matches when formatting docs search results After the existing link-removal phase, skip the unchanged HTML regex only when the current string has no closing delimiter. * Skip impossible link and tag matches in docs search results Skip the five unchanged link regexes when their protected-code input lacks ]; skip the unchanged HTML regex when its post-link input lacks >. |
||
|
|
d6d2795da5 |
chore(worktree): include create timing and spare outcome in the workspace create events (#24483)
* chore(worktree): include create timing and spare outcome in the workspace-created event The workspace_created and workspace_create_failed events gain optional, numbers-and-enums-only fields built from what the create already measured: total and per-phase durations, the prepared-checkout hit/miss and miss reason, the execution host (local/WSL/SSH), a worktree count bucket, how many other creates were in flight, whether the repo has a post-checkout hook (file existence only, probed after the create returns), and for a failure the phase it died in plus elapsed time. No new git process runs; consent and opt-out are unchanged. * fix(worktree): attribute failed_phase by error, label WSL-path repos, skip the hook check with telemetry off - failed_phase now names the outermost timed step the thrown error (or its cause) left, so a caught failure or a concurrent sibling step can no longer be misattributed; the old-relay SSH error keeps its cause so it still reads as git_worktree_add. - execution_host follows the same rule Git routing uses, so a \\wsl.localhost repo reads wsl. - The post-checkout hook check does not read the repo when telemetry is disabled. - Privacy page mentions the miss reason code and the failed step. * test(worktree): pin the old-relay SSH add error to git_worktree_add through its cause * fix(worktree): name the create event field sets for their role, and type the old-relay test's caught error * fix(worktree): send create events from runtime creates and record what the spare checkout did Runtime creates (CLI, agents, phone app, paired clients, orchestration, server automations) reuse prepared checkouts like the app's own creates, but recorded no timing and sent no events. Both entry points now start one shared sender (workspace-create-telemetry.ts), so every create sends exactly one event with the same fields, plus create_entry_point (app | runtime). Spare-checkout fields: - concurrent_preparations: peak prepared-checkout builds and background discards running during the create, excluding the one it used; the window closes before the create's own re-arm starts. - prepared_checkout_claim / prepared_checkout_discard phases, so on a miss git_worktree_add minus the prepared_checkout_* phases is the plain checkout. - prepared_checkout_reset (none | base_moved | retargeted) replaces the retargeted flag; prepared_checkout_origin (prefetch | rearm) on hits. - workspace_create_failed carries the spare outcome and its wait. - repo_index_size_bucket from one stat of .git/index in the existing post-create probe (telemetry on, local/WSL only, 2 s cap). * fix(worktree): add spare build and idle time, the re-arm prefetch origin, and a tracked-file count - prepared_checkout_build_ms / prepared_checkout_idle_ms on hits: from arming the spare to ready, and how long it sat ready before the claim (0 when the create waited). readyAt is recorded in the pool's existing ready handler. - prepared_checkout_origin gains rearm_then_prefetch: an automatic re-arm that the dialog prefetch then asked for too, so rearm means the re-arm alone. - repo_file_count_bucket replaces the index byte size: the entry count from the 12-byte index header, which is the same in every index version; left out for a split or sparse index. - The shared sender never lets a failed send change the create's result or error; it logs instead and still ends the create's concurrency membership. - Tests pin the runtime SSH create's timing hand-off and the throwing-send cases on both entry points. * fix(worktree): leave out the file count under any sparse checkout and time spare builds monotonically - The repo probe also reads .git/config.worktree, where git sparse-checkout --sparse-index writes index.sparse, and omits the file count whenever sparse checkout or a sparse index is on in either file, with Git's boolean spellings. core.hooksPath there is honoured too. - prepared_checkout_build_ms / _idle_ms use performance.now(), like every other duration; the build is timed from its own start (buildStartedAt). - The origin field comment names all three values. * fix(worktree): keep the spare's build time on its first build and count worktrees by lock reason - prepared_checkout_build_ms runs from the first build's start (including any wait for the base fetch it is built on) to its first ready; a later tip refresh no longer restarts it, though it still counts as new preparation work. prepared_checkout_idle_ms runs from the latest ready (build or refresh) to the claim. - The worktree count reads each .git/worktrees entry's locked file and leaves out entries whose lock reason names an Orca preparation, the way the listing does, instead of subtracting this process's spares. That covers spares from other processes, crash leftovers and spares being discarded, and cannot run one low while a spare's admin dir does not exist yet. It has its own 1.5 s cap inside the probe. |
||
|
|
76b1a90ff6 |
chore(deps): update reviewed dependencies across Orca (#24561)
* chore(deps): update reviewed desktop dependencies and tooling * chore(deps): update compatible mobile packages and Fastlane * chore(deps): update cloud transports and enforce release age * chore(deps): patch documentation dependencies and record review * chore: remove dependency review reports * test(linear): smoke-load resolved SDK through CommonJS loader * fix(deps): keep native rebuilds from reinstalling addon dependencies * fix(native): invoke installed node-gyp directly for Node rebuilds * test(cloud): exclude observer probes from row-lock timing budget * test(mobile): preserve the CSS writer receiver in viewport spy * test(native): remove obsolete batch-shim fixture exception * Stream native rebuild output through the process wrapper |
||
|
|
53fd2dea0b |
feat(ssh): relay runtime fallback ladder, telemetry and host runtime setting (#24133)
* feat(ssh): complete the relay runtime fallback ladder (D6 rungs B slot, C, D) Rung C runs the relay on the host's Node >= 18 with Orca's prebuilt N-API addons and no npm (addon-only probe mode). Rung B is a data-driven slot chosen only when a compat runtime is listed. Rung D fails the connect with a classified reason carried as a TerminalUnavailableCause. The ladder steps down only on classified refusals; unanswered probes throw. The rung decision is persisted per host keyed by (glibc, runtime hash, Orca major), and ssh_remote_runtime_resolved reports it once per host per session. * feat(settings): SSH host runtime choice (Auto | Orca-managed Node | Host Node) * docs(telemetry): describe ssh_remote_runtime_resolved * fix(ssh): let a passing rung C disprove a remembered noexec; allow glibc-less compat runtimes A remembered rung A noexec was re-persisted even after rung C self-tested addons from the same ~/.orca-remote tree, so rung A stayed skipped until the key changed. Rung B's evaluator also could never match a musl compat runtime. * test(ssh): import node:fs once in the host-node addon test --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain> |
||
|
|
a4606ccae3 |
fix(cli): orca file open no longer moves your view unless you pass --focus (#24244)
* docs(cli): file open/diff/open-changed say they switch the user's view and are for user requests only Refs #9944 * fix(cli): file open/diff/open-changed leave the user's view alone unless --focus `orca file open`, `file diff` and `file open-changed` always switched the desktop to the target worktree, selected the tab and revealed it in the sidebar. An agent skill that opens its answer pulled the user out of whatever they were typing in (#9944), and a phone opening a file moved the desktop too. The commands now add the tab in its worktree without changing anything on screen, including when that worktree is the one being viewed: the new tab is added to the tab bar but the active tab, tab type and focus stay put. In a worktree the user is not viewing, the tab becomes that worktree's selection so it is in front when they go there. `--focus` keeps today's behavior. files.open / files.openDiff take an optional `navigation` target (the existing RUNTIME_NAVIGATION_TARGETS vocabulary); the CLI sends 'all' for --focus, like `worktree create --activate`, and nothing otherwise. The renderer moves the host view only when the target reaches the host; a missing field (phones, older CLIs) leaves it still. Editor opens for a worktree other than the on-screen one no longer write the global activeFileId/activeTabType. Refs #9944 * test(cli): justify the window and runtime stubs in the file-open notification test * fix(cli): keep phone file opens switching the desktop; the CLI asks for 'caller' Phone opens send no `navigation` field, and the phone's diff-review "Open in session" relies on the desktop selecting the diff it opened. A missing field now keeps the original switch exactly; the CLI says what it wants instead: 'caller' (no host move) by default and 'all' for --focus. Older CLIs, which send nothing, keep switching as they always have. Refs #9944 * fix(cli): background file opens select the tab without counting as a visit A CLI open into a worktree the user is not viewing selected the new tab with the same activation a user click uses, which stamps lastFocusedAt and the group's recency list. The worktree jump palette sorts recent tabs by that time, so every agent `orca file open` into another worktree jumped to the top of the user's recent tabs. Editor opens now take a selection mode: 'focus' (default, unchanged), 'background' (select within its worktree without recording focus or recency) and 'none' (add only). createUnifiedTab and activateTab gain recordFocus:false for the background case. Also: tests for reopening an already-open file or diff without --focus, a comment that file opens move only the host window ('all' acts as 'host'), root help lines back under 100 columns, and an accurate remote test title. Refs #9944 * fix(tabs): a background-selected tab still joins its group's tab history recordFocus:false skipped both the focus-time stamp and the group's recentTabIds append while still making the tab the group's active tab. Ctrl+Tab looks the active tab up in that history, so after a background CLI open it did nothing (or went to the wrong tab) once the user switched to that worktree, and hydrate kept the broken history across a restart. Only the focus-time stamp is skipped now; the jump palette's recent rows sort by that alone, so the palette fix stands. Refs #9944 * fix(cli): file open/diff/open-changed --focus help says it brings the user to the file The three commands borrowed the shared --focus line written for terminal create ("Reveal the created terminal session in Orca"). They now use the per-command flag help table; terminal create's line is unchanged. Refs #9944 |
||
|
|
ccdb324b63 |
Add CodeBuddy as a built-in coding agent (#23740)
* feat(agents): integrate CodeBuddy launch, status and session history * docs: record CodeBuddy lifecycle verification * fix(codebuddy): backfill scoped history and negotiate remote resume * test(cli): include CodeBuddy in known search agents |
||
|
|
400e4e7957 |
feat(agents): add Freebuff launch and sidebar status support (#23567)
Add Freebuff launch support and execution-host status reporting for the sidebar, including running, question, blocked, and settled states. Validate against captured CLI transcripts and real rendered sidebar evidence. Cross-referenced community implementations #17065, #20839, and the Freebuff portion of #18790. Preserve their agent/catalog/mobile/documentation coverage and add canonical status publication and regression tests. Co-authored-by: Harkaran Brar <18134082+harkaranbrar7@users.noreply.github.com> Co-authored-by: Prarambha369 <98906077+Prarambha369@users.noreply.github.com> Co-authored-by: Lesley Murfin <260182349+LesleyMurfin@users.noreply.github.com> |
||
|
|
45f3512a33 |
feat(agents): add first-class DeepSeek Harness (dsh) support (#22468)
* feat(agents): add first-class DeepSeek Harness (dsh) support Register DSH as a supervised Orca agent: catalog entry and detection for its dsh-tui profile, status/question hooks through DeepSeek's own Claude-Code hook bridge, composer-ready prompt delivery, session resume, headless Source Control AI, and title identity that no longer collides with Gemini's. * fix(dsh): reach Orca through DSH's credential scrub and stop reading its title as Gemini DSH runs command hooks through its own shell executor, which drops every env var whose name contains KEY, TOKEN, SECRET or PASSWORD — taking ORCA_PANE_KEY and ORCA_AGENT_LAUNCH_TOKEN with it, so every hook exited without posting. Mirror both onto scrub-safe aliases at spawn and restore them at the top of the DSH hook script. Its title collided too: DSH rests on the same glyph Gemini works on, so a resting DSH pane was relabelled Gemini CLI and reported working forever. Defer both the Gemini classifier and the title status detector on DSH's whale, in the base module both copies of that classifier read. * test(mobile): repin the session-route closure for the DSH agent icon * fix(dsh): address review — never splice user rows, cover remote panes, keep the diff off argv - findManagedDshPatchRegion paired an orphan start marker with a later block's end, so a truncated write made install/remove delete the user's own rows. Pair each end with the nearest preceding start; regression test fails without the fix. - The relay PTY env builder never applied the scrub-safe aliases, so remote DSH status silently never appeared even with the remote hook installed. - Source Control AI sent the whole diff on argv; send it over stdin with DSH's '-' marker. - dsh-tui/dst already chose the interactive profile, so a workspace folder named 'web' or 'plugin' no longer marks a live agent pane non-interactive. - Isolate USERPROFILE as well as HOME so a Windows run cannot edit the real home. - Drop the duplicate README badge and revert an incidental doc reformat. * refactor(dsh): share the managed-hooks reader and tighten the new modules Reuse before reimplementing: readManagedDshHookEvents was a near-verbatim copy of Muse's, with byte-identical private helpers. Both now call one readManagedHookEventsFromJson. Also: one readTextOrAbsent instead of two spellings of the same read (dropping an existsSync TOCTOU), one status() builder instead of four inline literals, rmSync(force) instead of exists-then-unlink, and a redundant empty-string guard before JSON.parse. The patch-file transforms lose their index juggling for a predicate plus a filter. * fix(dsh): refuse a flow-style patch file, keep its mode, and stop the relay inheriting a pane - applyManagedDshPatch matched only an exact `[]`, so `[] # keep empty` or a non-empty flow sequence got a block entry appended after it — invalid YAML that would leave DSH unable to load the user's own patch layer either. It now strips the token from an empty sequence (keeping a trailing comment) and returns null for a non-empty one; install reports that and changes nothing. - The patch rewrite dropped an owner-only file to the umask default (CWE-732); pass preserveMode. - The relay PTY env never dropped inherited pane identity the way the local and daemon builders do, so a spawn that specified none could inherit the relay's own and every agent's hook would report against that pane. * fix(dsh): keep the flow-style refusal in every status read, and scope the mode test to POSIX A refused patch file carries no managed region, so getStatus() fell through to a bare not_installed with detail null — the actionable 'rewrite it as a block sequence' message only ever reached the one-shot install() return. Export the predicate and check it first, behind one shared message constant. The owner-only mode assertion cannot hold on Windows, where chmod only toggles the read-only attribute and mode & 0o777 reads 0o666 for any writable file. * docs(readme): restore the DeepSeek Harness badge lost in the rebase * test(mobile): repin the session-route closure to the measured 4221 Measured, not derived: 4220 without the DSH icon entry, 4221 with it. Two of the three modules above main's 4218 pin are not this change's — they arrived with the mobile work after #22570 and were never repinned; the changelog records that split explicitly. * fix(dsh): settle tui-idle on the agent's own hook, so supervised workers see it ready Reported by a tester on the adhoc build: `terminal wait --for tui-idle` ran to its 90s timeout against an already-ready DSH composer, so a supervised worker never sees the agent as ready. Every existing tier reads the title, and DSH deliberately carries no title status: its rest prefix is Gemini's working glyph, so the detector reports none. A fresh first-party `done` is better evidence than any title anyway — it is the agent's own account of its own turn, and normalizeDshEvent drops subagent events, so it is the lead's. Scoped to DSH: for agents whose hooks report child turns, a mid-turn `done` is the #6011 class this file prevents. * test(daemon): record the DSH transcript's true-colour I2 divergences Adding the dsh-tui capture to __fixtures__ enrolled it in the serialize replay sweep, where it reports 10 I2 divergences and failed the unlisted-transcript default of 0. Every one is the same shape — visible-grid row=0, a 24-bit background the round trip does not restore to default — which is DSH's whale intro painting whole rows of true colour. Verified as an upstream limitation rather than a regression by replaying against the previous build (build-serialize-addon-at-ref.mjs --ref origin/main): I1 and I3 both hold. * fix(dsh): return the new tui-idle verdict from the first-party done lane Main refactored isTuiIdleSatisfied into evaluateTuiIdle, which returns a verdict rather than a boolean. The DSH lane still returned `true`; it is tier-1 positive evidence, so it returns READY_STRONG like the title/body lane above it. Re-verified the regression test still fails without the lane. * test(relay): pin the scrub-safe pane-identity aliases on the relay spawn path The relay builds a remote pane's env itself, so the alias mirroring there had no test: removing the call left every suite green while remote DSH status silently vanished. Both cases fail without it. * docs(dsh): point the hook service at the integration reference The reference doc had no inbound link from anywhere in the repo. |
||
|
|
ef987e42d7 |
feat(analytics): persist local usage session identities (#18759)
Co-authored-by: Neil <neil@stably.ai> |
||
|
|
f5f537ef14 |
Revert "Support mouse Back/Forward buttons in shortcuts (#23287)" (#23350)
This reverts commit
|
||
|
|
a86fae0889 |
Support mouse Back/Forward buttons in shortcuts (#23287)
* feat: support mouse Back and Forward shortcut bindings * fix: ignore duplicate mouse shortcut presses until release |
||
|
|
90801e2deb |
feat(agents): add first-class ZCode harness (#22464)
* feat(agents): add first-class ZCode harness Add ZCode (Z.ai's `zcode` CLI) as a supervised Orca agent: managed lifecycle hooks on local, SSH and Windows hosts; status, question and approval reporting; synthetic status titles; session resume; orchestration worker launch options; and desktop + mobile agent-picker registration. Written against the newly open-sourced `zai-org/ZCode` (agent CLI 0.16.9), not against a remembered screen: - ZCode's hook runner writes a Claude-compatible stdin alias set, so it routes through the existing Claude-compatible vendor path while keeping its own identity in the sidebar. - `PermissionRequest` fires only once the approval card is on screen and racing the user's answer, so it is proof the pane is blocked, not an auto-approval. - ZCode's clarification tool is literally `AskUserQuestion` with Claude's questions/options shape, so Orca's question card renders it unchanged. - ZCode's `hooks.enabled` defaults to false, which is why configured hooks were reported as never firing; the installer sets it. - ZCode renames its own process to `zcode-cli`, so the expected foreground process cannot be the launch command or dispatch refuses the pane. - ZCode emits no OSC title in any state and repaints its ASCII banner forever, so readiness comes from Orca's synthetic hook title and launch drafts wait on the composer box rather than on a quiet render window. Three files crossed their max-lines limit, so each is split along a real seam: command-line entrypoint parsing out of agent process recognition, skill classification out of skill root discovery, and registry coverage out of the remote hook installer tests. Refs #10564 * fix(zcode): drop the session-option catalog and pin the orchestration contract ZCode's CLI exposes no `--model` flag at all, and the session-option launch path refuses to apply any option until a model id is chosen. A catalog therefore could not deliver `--mode` per worker, and would have accepted `--model` only to drop it silently. Take opencode's position instead: no catalog, so `worker-start --model` is refused with a clear message and ZCode launches with the model from its own config. `--mode` stays reachable through agent args, which is also how the yolo default is applied. Add a contract test covering the parts that make ZCode a usable worker: dispatchable foreground process, stdin prompt delivery, the prompt staying out of the launch command, and the composer-gated draft paste. * refactor(zcode): reuse shared helpers and cut the harness down No behaviour change; every ZCode test still passes. - Use installer-utils' own `hookDefinitionHasManagedCommand` instead of re-walking a hook definition by hand, which also drops a local string reader. - Share one `readZCodeEventMap` instead of keeping the same narrowing in both hook-settings and hook-config-json. - Collapse five identical error returns into one `zcodeHookError` builder, and return early from the status branches instead of assigning through `let`. - Split the event-to-status decision out of `normalizeZCodeEvent` into a pure `readZCodeTurn`, so the normalizer reads as decide-then-build and stops computing the tool name for events that never look at it. - Take a script file name in `readManagedZCodeHookEvents` like its siblings, which removes a `Parameters<typeof …>` indirection at the call site. - Drop the unused `ZCodeHookEvent` export and inline a single-use path helper. - Correct a stale comment: ZCode's loader is a strict `JSON.parse`, so the in-place edit preserves key order and indentation, not comments. * fix(zcode): address review — keep unmanaged event keys, correct comment, de-dupe README - `removeZCodeManagedHooks` deleted any event key whose list ended up empty, so an unrelated `"Notification": []` the user wrote was removed as collateral whenever a managed hook elsewhere made the write happen. Only touch an event Orca actually owned something in; covered by a new regression test. - The `isNewTurnEvent` comment claimed UserPromptSubmit was ZCode's only turn boundary while the expression below it also returned true for SessionStart. Say what the code does: SessionStart lands the idle boundary, UserPromptSubmit is the turn boundary (the Codex/Claude shape). - ZCode appeared twice in the README's single agent-badge block; keep the local-icon entry the link checker validates and drop the favicon duplicate. * docs(zcode): call out that the desktop bundle's CLI cannot open a session From live testing on #22464: pointing `zcode` at the desktop app's bundled `glm/zcode.cjs` installs Orca's hooks fine but then fails with `Cannot find package '@zcode/tui'`, so the pane never opens a session. The symptom reads as a broken harness when the CLI simply has no TUI. Say which build to use and how to check before reporting a problem. Reported-by: JWu527 |
||
|
|
7a4f080086 |
revert: #18790 (orchestration incarnation reap fallback and bundled Freebuff agent) (#22601)
This reverts commit
|
||
|
|
52a1e2875b |
feat(orchestration): accept Muse model and effort for supervised workers (#22383)
* feat(orchestration): accept Muse model and effort for supervised workers `worker-start --agent muse` already launched, but `--model` was refused because Muse had no session-option catalog. Add one that maps worker preferences to `muse --model <id>` and `--reasoning-effort <level>`; it seeds no models, so native-chat surfaces show no picker. opencode stays without `--model`: the opencode 2 TUI (now shipped as `opencode`) rejects the flag, so the refusal now tells callers to rely on the agent's own config. Help, skill guide, and docs list valid `--agent` ids and the agents that accept `--model`. Refs #19823 * test(mobile): repin session route closure for the Muse option catalog |
||
|
|
ebed0964a2 |
feat(agents): add first-class Muse Code harness (#22216)
* feat(agents): add first-class Muse Code harness Add Muse as a supervised Orca agent across desktop, mobile, session history, source control, local hooks, SSH, WSL, and native Windows. Preserve user settings, support Muse 1.3 hook environment allowlists, and recognize versioned foreground processes. Include question, waiting, completion, resume, and readiness coverage. Co-authored-by: homesh-dev <300847526+homesh-dev@users.noreply.github.com> Co-authored-by: jeffhuen <32542276+jeffhuen@users.noreply.github.com> Co-authored-by: John Cusack <johncusackccm@gmail.com> Co-authored-by: Adrien De oliveira <75085839+adriendeoliveira@users.noreply.github.com> * test(agents): cover Muse remote hook registration * test(agents): cover Muse hook and source-control contracts * test(agents): exclude Muse hook metadata from script mode check * test(agents): keep Muse skill picker coverage stable * test(ai-vault): include Muse in every-agent fixture * test(mobile): repin Muse agent icon closure * fix(muse): detect questions and approvals from structured Muse signals Muse 1.3 fires no hook for request_user_input, so a pending question left the pane "working". Its internal reminder subagents also post hooks with their own session ids (even after Stop), which surfaced "tool failed" rows and flipped finished panes back to working. - Read pending questions from Muse's session log (user_input_prompt_requested/settled) via the existing transcript poll, now generalized from Codex subagents to Muse on main and relay. - Drop child-session hooks (SubagentStart ids, or turn_id === session_id). - Treat Notification permission_prompt as the approval wait; PermissionRequest also fires for auto-approved calls, so it only caches the approval card. - Ignore Notification copy as the prompt; poll replays are not new prompts or turn boundaries. - Allowlist USERPROFILE so Windows cmd AutoRun doesn't fail every hook. * perf(muse): parse only question events from the session log Most Muse session-log lines are large model/tool records. Filter raw lines by the user_input_prompt_ marker before JSON.parse via an optional readJsonlCursor line filter. * fix(muse): unwrap batched log records and scope questions to the live turn Review follow-ups: question events inside retained_frame batches were skipped, and a question left open by a crash or interrupt stayed pending for the pane's life. Share the history scanner's retained_frame unwrapper, and only report a pending question whose run_id matches the hook turn_id. * refactor(muse): drop type assertion in retained_frame unwrap * fix(agent-hooks): satisfy exhaustive-switch lint in transcript poll policy --------- Co-authored-by: Adrien De oliveira <75085839+adriendeoliveira@users.noreply.github.com> |
||
|
|
0677271709 |
fix(orchestration): reap leaked worker terminals via process-incarnation fallback — stops an unbounded PTY/process leak on Remote Server (OOM / cgroup PID exhaustion) (#18790)
* fix(orchestration): remint live handle from process incarnation on worker release When a durable terminal handle goes stale (rendererGraphEpoch fence), inspectWorkerTerminal re-mints a live handle via resolveTerminalHandleByProcessIncarnation + matchesProcessIncarnation so release/stop/read act on the still-running PTY instead of reporting missing and leaking the agent process tree. - keep main shared host-scope re-exports; add matchesProcessIncarnation - wire observation.terminalHandle through control/stop/release - rebuild release-completion on main structured paths - on missing/unattached + provably exited: settleDead fence first, then same-incarnation settleWorker fall back (archive may block settleDead mid-request); settle before recovery defer * fix(orchestration): derive SSH host scope from the reminted handle; reuse fresh-request recovery guidance for structured workers Addresses two open CodeRabbit review comments on PR #18790. inspectWorkerTerminal read the dispatch authority with the stale durable terminalHandle, so after a remint the lookup resolved nowhere and currentHostScope was always undefined — an SSH worker with no liveness verdict and no persisted host_scope got classified from terminal.connected instead of unverifiable. It now reads the same effectiveHandle every other observation in the function uses. stopStructuredWorkerForRelease told the caller to repeat the release with the same --retry-request, which only replays the stale release_unknown receipt and made a structured-worker close failure permanently unretryable. It now sources releaseUnknownRecovery from worker-release-completion so the fresh-request-ID guidance lives in one place. Pre-commit lint-staged (oxlint + oxfmt) run manually: clean. * test(orchestration): exercise incarnation recovery through runtime paths * test(orchestration): pin the incarnation read scenario to the reminted terminal The read scenario only asserted that the call resolved, so it documented nothing about which handle the read reached. Assert that the handle readTerminal received resolves to the registered pane and incarnation, so the scenario proves the read went through the reminted terminal instead of passing on the incarnation fence's throw. * refactor(orchestration): drop redundant incarnation prefix check; require liveTerminalHandle * feat: add freebuff as a first-class TUI agent (#42) <!-- orca-pr-loc --> <!-- Programmatic LoC summary. Do not edit by hand; rewritten on every commit. --> | | Files | Added | Deleted | Net | | :--- | ---: | ---: | ---: | ---: | | Test | 0 | 0 | 0 | 0 | | Prod | 28 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$37 | 0 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$37 | <!-- /orca-pr-loc --> ## ELI5 Add Freebuff (`freebuff`) as a recognized first-class TUI coding agent in Orca alongside Codebuff and other supported agents. ## What Changed - Registered `freebuff` across shared TUI agent definitions, configuration catalogs, display names, and telemetry schemas. - Added agent icons, favicons, status mappings, and mobile asset references for Freebuff. - Added localization strings across supported language packs (`en`, `es`, `fr`, `ja`, `ko`, `zh`) and updated locale translation policy. - Documented Freebuff CLI in README agent table (`npm i -g freebuff`). ## Why Freebuff is a CLI coding agent twin of Codebuff (`npm i -g freebuff`). Adding it to the catalog enables users to launch worktrees, run automated sessions, and pick Freebuff directly within Orca. ## Linked Issue N/A ## Visual Proof `N/A` - Catalog registration and metadata definition for CLI agent launch; UI rendering uses existing TUI agent picker and status components. ## Testing - Verified TypeScript contracts, schemas, and catalog configurations. - Tested CLI detection / agent picker integration locally on Linux (`worktree create --agent freebuff`). ## AI Disclosure Assisted by AI coding tooling. ## Checklist - [x] This PR is small and focused - [x] I explained what changed and why (including ELI5) - [x] Before/after screenshots or videos attached for UI changes, or `N/A` with reason - [x] Self-reviewed for correctness, security, and performance - [x] Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A) --------- Co-authored-by: Lesley Murfin <lesley@revivebusiness.ca> * test(orchestration): erase method overloads in worker reap fixtures * test: document worker fixture type boundaries * test: simplify worker fixture typing --------- Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> Co-authored-by: svc-orca[bot] <313947298+svc-orca[bot]@users.noreply.github.com> Co-authored-by: m4air <m4air@Mac.localdomain> |
||
|
|
dcee2c5df3 | fix(deps): update vulnerable transitive packages (#21652) | ||
|
|
aee98ccaa0 |
fix(browser): make the browser identity one process-wide choice (#13822) (#20767)
* feat(browser): process-wide browser identity, chosen before ready
Electron resolves worker identity from a single process-global default, so two
coherent identities cannot coexist in one process. This makes clean/native one
app-wide decision read before `ready`, instead of a per-profile one that leaves
documents on one identity and every worker request on the other.
Both identities are load-bearing, measured across four origins at five reps:
the cleaned identity clears an embedded Turnstile widget and WhatsApp's browser
check where native is refused; native clears a full-page Cloudflare interstitial
that the cleaned identity never clears.
Base commit only: removing the per-profile field, its settings surface, and the
migration notice follow.
* test(browser): cover cross-context UA wire identity
* refactor(browser): make user agent identity app-wide
* test(browser): repair process identity wire fixture
* Fix browser identity startup migration failures
* WIP: rescue in-flight reduced-design work from a dead worker
Worker ctx_cb5b1262d7fe stopped ~2h ago mid-implementation (last heartbeat
2026-09-14T22:48:06Z) leaving this uncommitted. Committed unverified to make it
recoverable; not reviewed, not necessarily green.
* fix(browser): repair the rescued identity work so it typechecks
Finishes the interrupted edits in
|
||
|
|
16ac9018db |
docs: remove unavailable diff shortcuts (#20974)
Co-authored-by: m4air <m4air@Mac.localdomain> |
||
|
|
e187c82678 | Revert mobile push rollout pending delivery investigation (#20040) | ||
|
|
d33354cfd2 |
feat(mobile): receive native push notifications from paired desktops (#19951)
* feat(mobile): deliver native push notifications from paired desktops * fix(mobile): retry push capability probes * fix(mobile): cancel retired push capability probes * fix(mobile): ignore stale push reconciliations * fix(mobile): type capability probe at its boundary * fix(notifications): route mobile push taps to the originating pane * Require explicit mobile push-service consent on upgrade |
||
|
|
fb85f88d64 |
fix(browser): restore the Chrome-shaped browser identity (STA-7147) (#19927)
* fix(browser): restore the Chrome-shaped browser identity (STA-7147) #18749 replaced every browser partition's Chrome-shaped UA with Electron's stock one, so since v1.4.198 the embedded browser announces itself on every non-Google host as: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Orca/1.4.198 Chrome/150.0.7871.224 Electron/43.4.1 Safari/537.36 No browser sends that. Sites that re-check the identity holding a session reject it: users report being signed out of x.com, LinkedIn and "most websites," and at least one was signed out of LinkedIn in their own Chrome and met LinkedIn's "suspicious activity" SMS check -- server-side revocation, which reaches beyond our app. The repo already documented the mechanism in browser-google-auth-ua.ts: copied-in cookies "sent under a UA that doesn't match a real first-party browser get flagged by anti-fraud." That is why the Google auth-host switch exists; #18749 kept it for accounts.google.com and handed every other host an Electron identity. Restore the pre-#18749 session identity: strip the Electron and app tokens, and rewrite sec-ch-ua to match. Nothing in the cookie-import write path changed -- it never did; cookies were always written correctly and servers were refusing them. Deliberately KEPT from #18749, all independent of the UA: - anti-detection.ts stays deleted. Its premises were measured false on Electron 43 and its overrides are themselves published bot signatures. - No Runtime.enable into cross-origin iframes (the documented Cloudflare CDP tell). - No unconditional CDP debugger attach on every browsing guest. Known tradeoff, measured: this re-opens #13822. On the unmerged predecessor branch brennan/sta-3905-cloudflare-ua, commit 9f0a4772fe recorded the stock UA clearing dash.cloudflare.com 5/5 while every rewritten variant failed 12/12, and noted that adding client hints does not rescue it. So Cloudflare-gated sites will show verification failures again until a coherent-identity fix lands. That is a bounded, in-app annoyance; session revocation damages users' real accounts. A CDP Emulation.setUserAgentOverride with full userAgentMetadata -- which drives navigator.userAgentData as well as the headers, and was never tested -- is the candidate that could satisfy both, and is being measured separately. Tests: the real-Electron wire-identity test now asserts the stripped identity on ordinary hosts and Firefox on Google auth hosts. Ablation-verified: neutering cleanElectronUserAgent turns it red on the Electron-token assertion. Its fixture also gained an app name -- without one the raw UA carried no app token, so the Orca/x.y.z half of the cleaner was never exercised. * fix(browser): finish the identity revert in the files CI caught browser-session-registry.persistence.test.ts still asserted #18749's behaviour ("keeps the stock UA", "keeps the engine UA"), so the shipped code and its test disagreed. Caught by CI shard 4/8, not locally: I reverted four test files and went to typecheck without re-running the browser suite. Also restores the accurate wording that #18749 generalised away, now that the behaviour it described is back: - browser-google-auth-ua.ts: names the Electron/Chrome-shaped UA again as what anti-fraud flags, which is the reason the auth-host switch exists at all. - docs/browser/profiles.mdx: documents the cleaned Chrome UA default and the --no-ua-spoof escape hatch, which is real again. - tests/tools/google-signin-ua-probe.cjs: comments name the live handler. Deliberately left at #18749's version, because those changes stay correct with anti-detection.ts deleted: - browser-manager-viewport.ts: its comment no longer cites the retired addScriptToEvaluateOnNewDocument injection. - browser-webauthn-profile-delete.test.ts: its added webRequest mock is REQUIRED by the restored setupClientHintsOverride, so reverting it would break the test. * fix(browser): keep restored UA hints browser-owned --------- Co-authored-by: Merge Sim <sim@local> |
||
|
|
4b1b7178ad |
fix(orchestration): scope @ group addresses to the sender's Run (#19783)
* fix(orchestration): scope @ group addresses to the sender's Run `@all`, `@idle`, and the agent-name groups (`@claude`, `@codex`, ...) resolved against every terminal on the host. A coordinator meaning "my three reviewers" reached 126 agents across every open project, twice in one day, and every unrelated agent burned a turn discarding mail that was never for it. Every group except `@worktree:<id>` now means the live Dispatches of the sender's own Run, each addressed as `dispatch:<id>` so delivery is durable even when the worker terminal is not attached yet. A sender bound to no Run is refused with `invalid_argument` naming `run:<id>` / `dispatch:<id>`; there is no host-wide fallback and the host's terminals are never enumerated for it. `@idle` and the agent-name groups filter within that set by the same terminal status and host-resolved identity as before. `ask --to @group` returns the same code and points at the owning Run mailbox. Federated Dispatches read relayed control mail rather than a local mailbox, so a Run-scoped fan-out skips them with a `recipient_unreachable` warning naming the direct `dispatch:<id>` address. Group addresses are resolved host-side, so no RPC or stream shape changes; an older CLI sending `@all` to a new host gets the Run-scoped meaning. Claude-Session: run-scoped-group-addresses * fix(orchestration): revalidate legacy takeover before the recipient verdict A legacy coordinator taken over while `listTerminals` was in flight reported `runtime_error` instead of `legacy_read_only`: Run scoping made "no live Dispatch in this Run" the first thing the group send could fail on, and that threw before the takeover check ran. Takeover is a precondition, not a commit-time detail — the sender must be told it is read-only whatever else is wrong with its recipient set. Revalidation moves to immediately after the only `await` in the path. Everything below it is synchronous, so the commit-time window it used to guard is unchanged; only the error paths now see it. The legacy partition test gave `term_current_worker` no Dispatch, so under Run scoping it is correctly not a recipient. It now holds a real current-contract Dispatch in the same adopted Run, which is what the test is named for: one `legacy_direct` and one `current_delivery` recipient in one fan-out. Claude-Session: run-scoped-group-addresses * fix(orchestration): address the Run a nested coordinator created, not its parent A nested coordinator is both a worker of its parent Run and the coordinator of the Run it created. `resolveMessageRun` answers with the parent, correctly, because that is where its own `worker_done` belongs — but audience is a different question. Scoping `@all` to that Run sent a nested coordinator's "shared context" to the siblings it was started beside instead of the workers it started, and reported success, so it never learned its sub-workers heard nothing. Before Run scoping the host-wide fan-out reached the sub-workers by accident; this turned an over-broad delivery into a wrong-audience one, the exact failure class the change exists to remove. Group audience now resolves off the Run the sender coordinates, falling back to its Dispatch's Run. A leaf worker coordinates nothing and is unaffected. This is a separate question from `routing.run`, not a second answer to the same one, so `resolveMessageRun` keeps its meaning for point-to-point mail. Also: when every live Dispatch in a Run is federated, the fan-out skipped them all and threw a bare `Error` that discarded the warnings naming those remote workers and how to address each one. The sender was told "no recipients" while three remote workers existed. That throw now carries a code and the skip explanations. Claude-Session: run-scoped-group-addresses * docs(orchestration): say that no group address reaches a coordinator A coordinator is not a Dispatch, so Run-scoped groups never include one. That follows from the rule, but nothing said it, and the old host-wide meaning did include the coordinator — a worker sending `@all` to raise a blocker would be heard by its siblings and by nobody who can act. The guide, the CLI note, and the docs page now say to use `run:<id>` for that, and that a worker which created its own Run addresses that Run's workers. Also restores the `@cursor` case dropped when the group tests moved: a Claude pane titled "Fix the text cursor blink" must not receive Cursor's mail. That hazard was recorded from real titles and `@droid` alone did not cover it. Claude-Session: run-scoped-group-addresses * fix(orchestration): preserve group audience and mailbox identity * fix(orchestration): validate group scope before dispatch routing * fix(orchestration): preserve pane identity and exclude coordinator dispatches |
||
|
|
a4e5106e14 |
chore(docs): patch brace expansion resource exhaustion fixes (#19382)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local> |
||
|
|
9fed61e5c2 |
Persist agents sidebar search visibility as pairing-local preference (#19313)
* Persist agents sidebar search field visibility as pairing-local preferen - Add `agentsShowSearch` to workspace UI state with default on - Include in pairing-local fields so preference syncs across clients - Convert search from menu action to checkbox menu item for explicit toggle - Update activity thread options menu to reflect checkbox state - Add localization strings across all supported languages - Update RPC schemas and preference persistence layer - Includes readiness validation reports confirming feature is clean * rm review * fix documentation |
||
|
|
d53cbed43f |
revert: hold mobile push feature for user testing (#19203)
Reverts
|
||
|
|
3160b54c69 |
feat: real background push notifications for the mobile app (#8129) (#18554)
* feat(cloud): add the mobile push gateway and its contract package (#8129) A small open-source service that holds the APNs key and FCM credentials and sends background push to paired phones on the desktop's behalf. Hosts authenticate with a box challenge and HMAC proof on their pairing key, the same shape the relay uses, so signed-in and accountless desktops share one path. Tokens are stored; alert text is held only for the coalescing window. The contract doc in docs/reference is the source of truth for every wire shape. The interop test runs the real desktop answerer against a real gateway-issued challenge so transcript drift fails in CI. * feat(push): register phones and send background push from the desktop (#8129) Adds the notifications.remote-push.v1 capability, the registerPush and unregisterPush RPCs on the mobile allowlist, a gateway client with a cached session and 401 re-auth, a durable unregister outbox, and a dispatcher that offers every mobile notification to the gateway after the socket fan-out. The dispatcher is fire-and-forget with one retry and drops registrations the gateway reports dead. Puts agentState on the mobile frame and fixes the #4375 wording so a working agent is never announced as finished. The relay host-proof code moves onto a shared envelope module with no behaviour change. * feat(mobile): background push registration, receive, and settings (#8129) Fetches the native APNs or FCM token, registers it with every paired host that advertises the capability, and re-registers on token change. Foreground pushes are suppressed inside handleNotification against the same seen set the socket path uses, so nothing shows twice. Taps route by host fingerprint. One Background notifications switch, off by default, with the disclaimer and needs-input / finished sub-switches; hidden until a paired desktop is new enough. Adds google-services.json and the expo-notifications plugin. * chore(cloud): Terraform and deploy workflow for the push gateway (#8129) Declares the Cloud Run service, runtime account, secrets, and orca_push database behind push_gateway_enabled, true only in production. The deploy workflow is gated like the relay's, deploys with no traffic, probes /ready and a validate-only FCM send, then shifts traffic. It runs as the shared production deploy account because the Cloud SQL rollout lease grant is foundation-owned; its extra authority is three bindings on the push service. docs/push-gateway.md carries the import commands for the resources created by hand and the APNs key rotation procedure. * docs: describe background notifications on the phone (#8129) * docs: check in the mobile push contract (#8129) Seven committed files cite it as the source of truth for every wire shape; docs/reference is allowlisted per file, so add the entry. * test(push): replay one checked-in host-proof vector on both sides (#8129) Cloud Verify installs only the cloud workspace, so the gateway suite cannot import the desktop answerer. Replace the cross-workspace import with a fixed challenge vector generated from the contract package; the gateway fixture and the desktop answerer each replay it and must produce the same HMAC. A transcript drift on either side now fails in that side's own suite. * fix(cloud): open the push gateway with invoker_iam_disabled, not an allUsers binding (#8129) The production domain-restricted-sharing policy rejects an allUsers run.invoker member, which the runbook anticipated. Opt the service out of invoker IAM the way the relay director already does; the host proof is the authentication either way. * docs(cloud): the push.onorca.dev record exists and is hand-managed (#8129) * fix(push): close review findings in the gateway (#8129) - Quota reservation takes a per-host advisory lock; READ COMMITTED admitted a whole burst past the cap (80/80 without, 60/80 with, against Postgres 16). - Challenge issuance no longer writes push_hosts; the row lands on proof verification. Stale hosts prune after 30 days. Per-IP token bucket on the two unauthenticated routes. - Streaming body limit via hono bodyLimit; a chunked body bypassed the Content-Length check. - registrationIds deduped in the schema; per-host device cap of 64; list bounded to its schema. - Gateway-side challenge TTL is the specified 10 s, not 40 s. - APNs stream settles on close as well as end/error. * fix(push): close review findings in the desktop client (#8129) - A gateway registration the registry cannot persist is enqueued for delete instead of leaking a live token. - Unregister outbox re-reads pending per pass, honours enqueues during a drain, and retries with backoff instead of waiting for the next launch. - Dispatcher batches registrations by 20 rather than starving the rest. - 401 compare-and-clear; a 401 after re-auth is unreachable; refused handshakes and 429s are cached briefly instead of re-handshaking per event. - Service is stopped on quit. * fix(mobile): close review findings in push registration and receive (#8129) - Consent generation guards a register that finishes after the switch went off; the host is re-queued for unregister instead of recorded live. - Foreground pushes seed the watermark before adopting the epoch, so a push on a never-connected session cannot wipe a valid watermark. - aps-environment follows the build via app.config.js; the iOS release workflow sets it to production. A bare plugin entry wrote development. - Pushes the OS showed while closed are marked seen before catch-up replay. - Token null result is not cached; failed capability probes are retried and never block an unregister; coalesced summaries are shown but not marked. - Unresolvable fingerprint routes nowhere and is suppressed in foreground. - Android channel ensured at boot; capability hook diffs clients by identity. * fix(cloud): harden the push deploy workflow and size the gateway to the budget (#8129) - Roll traffic back on a failed post-shift check; delete a candidate that never took traffic; retry the origin probe and the FCM probe. - Assert Terraform-owned scaling instead of mutating it from the workflow. - Build before taking the Cloud SQL rollout lease. - Declare the database pool in Terraform (2 per instance, max 2 instances) and add the gateway to the connection budget; the previous default put the shared instance 65 connections over its ceiling. - State plainly that the shared deploy identity's relay authority is inherited. * fix(push): read the runtime from shared state at push startup (#8129) Threading the runtime through launchDesktopMode put the launch module one line over the 300-line lint budget after the rebase. * fix(push): key the unauthenticated rate limit on the hop Cloud Run wrote (#8129) Cloud Run appends the connecting peer to x-forwarded-for; the limiter read the left-most value, which the caller controls, so a forged first hop earned a fresh bucket per request. * fix(push): close the final security review findings in the gateway and infra (#8129) - app.onError logs only the error name and answers a bare 500; hono's default handler printed the whole error, and a pg error carries the row in detail - a second per-IP bucket (240/min) runs ahead of the bearer lookup on every authenticated route, so forged bearers cannot spend the two-connection pool - one live session per host: minting deletes the host's earlier row - device-less hosts are pruned after 1 h, not 30 d; any keypair mints one free - notificationId is printable ASCII, since it becomes the APNs collapse header - the impersonated FCM probe token is masked in the workflow log - prevent_destroy on the Apple secrets and the orca_push database * fix(push): close the final security review findings in the desktop client (#8129) - fetch never follows a redirect: a 307 would replay the host proof and the phone's token to whatever origin the redirect named - registerPush params are strict and the paired identity is spread last - a per-device bucket (10/min) bounds a phone looping registerPush, which costs a gateway write and a synchronous registry write each time * fix(mobile): close the final security review findings in push receive (#8129) - a push with no epoch can no longer claim a seq-derived dedup key, in the foreground or from the tray; a forged seq:N could otherwise swallow the real bell at that seq - a provider-delivered push with no host catalog, or no fingerprint at all, stays unrouted instead of falling back to the hostId its raw data carries * docs(push): record the ip buckets, session and host retention, and the token-ownership limit (#8129) * fix(push): apply the schema on an untimed pool and retry statement-timeout aborts (#8129) Ports the relay's #18722 pattern to the gateway: DDL runs on a one-connection pool with statement_timeout 0 that is closed before the serving pool opens, and SQLSTATE 57014 joins the bounded transaction retry path. * fix: harden mobile push delivery and deployment recovery * feat: align mobile notification preferences with desktop delivery * fix: accept variable-length APNs device tokens * fix: deduplicate native APNs and background socket notifications |
||
|
|
6fcd82918d |
Update mobile 0.0.48 Android download links (#19117)
* Update mobile 0.0.48 Android download links * Update the mobile docs page APK link to 0.0.48 The docs page the READMEs link to still pointed at 0.0.46, two releases stale. --------- Co-authored-by: Merge Sim <sim@local> |