* Reduce native dependency installs to the host platform * Remove install policy documentation * Guard cross-arch packaging and scope release installs to the runner electron-builder only logs a warning for a missing extraResources source, so a host-only install silently shipped a foreign-arch slice without its natives — `pnpm build:mac` on Apple Silicon produced an x64 DMG with no sherpa-onnx-darwin-x64 and no @parcel/watcher-darwin-x64. The previous beforePack hook covered only win32. - Add assertPackagedNativeVariantsInstalled, an arch-aware check over the target's sherpa-onnx, @parcel/watcher, and (on Windows) node-gyp addons. beforePack now runs it for every platform, with remedies split: another architecture comes from install:release, the os:win32 addons need a Windows host. - Drop --os from the release installs. Every packaging job already runs on a runner whose OS matches its target, so only the macOS lanes need extra breadth, and only on CPU for their x64+arm64 config. Windows and Linux packaging return to a plain host-only install. - Add --frozen-lockfile to install:release so a bare run cannot rewrite the lockfile. - Restore the install policy reference doc and the CONTRIBUTING note, plus the rationale comments dropped from the runtime contract test. - Gate the packaging-closure assertions on whether the Windows addons are installed rather than on the host OS, so a cross-arch install exercises them off Windows too. - Make the workflow contract test read `run:` steps as well as retry-action commands, and enforce host-only scoping on the non-macOS packaging lanes. - Remove the unreferenced install measurement script; its numbers live in the policy doc. * Track the install policy doc and index it from AGENTS.md docs/** is ignored behind a per-file allow-list, so the new reference doc was only committed via git add -f and future edits would be skipped. Add it to the allow-list and give it an AGENTS.md entry like every other tracked reference doc, so the host-only install rule is discoverable before someone packages a second architecture. * Route Windows-lane removals through the retrying helper Adding these four specs to the PR Windows lane pulled them into the windows-lane-tree-removal-boundary ratchet, which failed on 20 raw recursive removals. On Windows a bare rmSync races a handle the OS has not released, throwing EPERM after the assertions already passed and reporting a green test as a lane failure. * Adapt the packaging guard to the vendored Windows registry addon main vendored windows-native-registry as the workspace package @orca/windows-registry (#20438). A workspace link resolves on every host, so including it in the installed-Windows-addons checks proved nothing. @vscode/windows-process-tree is the only os: win32 npm addon left, so it alone decides whether the win32 resource plan resolves.
7.5 KiB
Contributing to Orca
Thanks for contributing to Orca.
Before You Start
- Keep changes scoped to a clear user-facing improvement, bug fix, or refactor.
- Orca targets macOS, Linux, and Windows. Every change must stay compatible with all three platforms unless the code is explicitly guarded by a runtime platform check.
- For keyboard shortcuts, use runtime platform checks in renderer code and
CmdOrCtrlin Electron menu accelerators. - For shortcut labels, show
⌘and⇧on macOS, andCtrl+andShift+on Linux and Windows. - For file paths, use Node or Electron path utilities such as
path.join. - Orca must work against local repositories, remote servers, and SSH worktrees. Do not assume a process, file, credential, shell, or network path exists only on the local machine.
- Orca supports many CLI agents, integrations, and git providers. Keep generic behavior provider-neutral; guard integration-specific logic behind explicit checks.
- Keep changes well-engineered and performant: follow existing architecture, avoid unnecessary work in hot paths, clean up owned resources, and use concrete module names.
- For UI work, follow
docs/STYLEGUIDE.md, use the tokens and shadcn primitives it specifies, and verify polished behavior across platforms, light/dark mode, and SSH latency.
Local Setup
pnpm install
pnpm dev
Ordinary installs include native optional dependencies for the current OS and CPU only.
Before a cross-architecture build (including pnpm build:mac, which produces both x64 and
arm64 artifacts by default), run pnpm install:release to add the other CPU's variants.
See the install policy.
Branch Naming
Use a clear, descriptive branch name that reflects the change.
Good examples:
fix/ctrl-backspace-delete-wordfeat/shift-enter-newlinechore/update-contributor-guide
Avoid vague names like test, misc, or changes.
Before Opening a PR
Run the same checks that CI runs:
pnpm lint
pnpm typecheck
pnpm test
pnpm build
Add high-quality tests for behavior changes and bug fixes. Prefer tests that would actually catch a regression, not shallow coverage that only exercises the happy path.
If your change affects UI or interaction behavior, verify it on the platforms it could impact.
Type Declarations: Prefer .ts Over .d.ts
Project-owned type declarations belong in .ts files. .d.ts is reserved for ambient shims (e.g., env.d.ts, vite/client.d.ts). TypeScript's skipLibCheck: true setting applies globally, including to our own .d.ts files, which means any unresolved type reference in a .d.ts silently becomes any at its call sites. Write your types in .ts files so the compiler actually checks them.
CI enforces this for src/preload/ and src/shared/.
Pull Requests
Each pull request should follow .github/pull_request_template.md. In particular:
- open with an ELI5 of the change (plain language paragraph; the PR title is the one-liner)
- explain what changed and why, and stay focused on a single topic when possible
- for any UI or interaction change, attach before and after screenshots (or short videos); if there is no visual change, say
No visual changeand why - include high-quality tests when behavior changes or bug fixes warrant them
- include a brief code review summary from your AI coding agent that explicitly checks cross-platform compatibility, SSH/remote/local compatibility, supported agent and integration compatibility, performance risk, UI quality when applicable, and basic security risk
- mention any platform-specific, remote/SSH-specific, agent-specific, integration-specific, or git-provider-specific behavior and testing notes
- Include your X (Twitter) handle in the PR template Author section — we shout out contributors when we merge features on @orca_build.
Release Process
Version bumps, tags, and releases are maintainer-managed. Do not include release version changes in a normal contribution unless a maintainer asks for them.
Cutting a release (maintainers)
All releases are cut from the Cut Release GitHub Actions workflow. There is no local pnpm release:* script — running releases locally is too easy to get wrong (dirty tree, wrong branch, stale main).
To cut a release:
- Open Actions → Cut Release.
- Click Run workflow and pick:
- kind: one of
rc,patch,minor,major. - ref: the branch, tag, or SHA to build from. Defaults to
main.
- kind: one of
- Run it.
The workflow resolves the next version from GitHub Releases, bumps package.json, tags, pushes, and runs the multi-platform build + publish inline.
How the next version is chosen:
All stable kinds (patch, minor, major) are computed off the latest stable release, ignoring any RCs in between.
kind=rc+ last tag was stable (e.g.v1.3.14) →v1.3.15-rc.0.kind=rc+ active RC series (e.g.v1.3.15-rc.2) →v1.3.15-rc.3.kind=patch+ latest stablev1.3.14→v1.3.15(regardless of any intermediate RCs).kind=minor+ latest stablev1.3.14→v1.4.0.kind=major+ latest stablev1.3.14→v2.0.0.
Safety guarantees:
- Stable releases are refused if the new version isn't strictly greater than the latest published stable. This is the only rule
electron-updateractually needs — it compares semver within thelatestchannel, so a regressing stable is the one thing that breaks auto-update for fresh installs. - Complete RC draft releases created by the release workflow are published before cutting a new tag only when the draft tag was built from the current release ref. Stale drafts are skipped so fixes cut a fresh RC instead of exposing old artifacts.
- If the latest RC tag exists but is still draft-only or missing its GitHub Release, the workflow resumes that tag only when it was built from the current release ref. Otherwise the next RC number is cut.
- RC numbering also considers release commits on
main, so deleting a stale tag does not let a later cut reuse the same RC number. - Off-main releases (when
refis not the tip ofmain) only push the tag.mainis never mutated from a non-main ref, so you can safely release an older commit without polluting history. - When
refis the tip ofmain, the version-bump commit is fast-forwarded ontomainso localpackage.jsonstays in sync with what's shipped.
Common scenarios:
- Normal release:
kind=patch,ref=main. - "A bad commit just landed on main, release the commit before it":
kind=patch,ref=<good-sha>.mainis left alone; the tag points at the good SHA. Fix forward onmainafterward. - One-off RC for a feature branch:
kind=rc,ref=<branch-or-sha>. Produces an RC tag that does not touchmain. - Minor or major bump:
kind=minororkind=major.
The scheduled 2x/day RC cron in release-rc.yml is independent and continues to run automatically from main.
Release Channels
The public Homebrew cask tracks stable desktop releases:
brew install --cask stablyai/orca/orca
Release candidates use a separate cask token:
brew install --cask stablyai/orca/orca@rc
The two casks conflict because both install Orca.app. Switch channels with a
normal brew uninstall --cask followed by the install for the other channel.
Do not use --zap unless you intentionally want to remove local Orca state.