diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index c95cd52dda4..491d0cac794 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -112,7 +112,6 @@ All stable kinds (`patch`, `minor`, `major`) are computed off the latest _stable
The scheduled 2x/day RC cron in [`release-rc.yml`](../../actions/workflows/release-rc.yml) is independent and continues to run automatically from `main`.
-
## Release Channels
The public Homebrew cask tracks stable desktop releases:
diff --git a/.github/workflows/daily-mac-build.yml b/.github/workflows/daily-mac-build.yml
index e445045e67c..2ef3baed2fd 100644
--- a/.github/workflows/daily-mac-build.yml
+++ b/.github/workflows/daily-mac-build.yml
@@ -308,7 +308,6 @@ jobs:
echo "tag=$TAG" >>"$GITHUB_OUTPUT"
echo "notes_file=$notes_file" >>"$GITHUB_OUTPUT"
-
- name: Publish daily macOS artifacts
if: steps.freshness.outputs.should_build == 'true'
uses: nick-fields/retry@v4
diff --git a/.github/workflows/hourly-mac-build.yml b/.github/workflows/hourly-mac-build.yml
index 16e2f05579c..e072b0f9a10 100644
--- a/.github/workflows/hourly-mac-build.yml
+++ b/.github/workflows/hourly-mac-build.yml
@@ -290,7 +290,6 @@ jobs:
including back to Stable, works in-app from there."
echo "tag=$TAG" >>"$GITHUB_OUTPUT"
-
- name: Publish hourly macOS artifacts
if: steps.freshness.outputs.should_build == 'true'
uses: nick-fields/retry@v4
diff --git a/.github/workflows/pullfrog.yml b/.github/workflows/pullfrog.yml
index 19401170c0e..d5030252f88 100644
--- a/.github/workflows/pullfrog.yml
+++ b/.github/workflows/pullfrog.yml
@@ -34,8 +34,7 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- GOOGLE_GENERATIVE_AI_API_KEY:
- ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
+ GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
diff --git a/.github/workflows/release-cut.yml b/.github/workflows/release-cut.yml
index c035080a203..af0fe9b45ba 100644
--- a/.github/workflows/release-cut.yml
+++ b/.github/workflows/release-cut.yml
@@ -844,6 +844,16 @@ jobs:
with:
ref: refs/tags/${{ needs.cut.outputs.tag }}
+ - name: Restore golden test harness from the workflow ref
+ shell: bash
+ env:
+ WORKFLOW_SHA: ${{ github.workflow_sha }}
+ run: |
+ git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"
+ git checkout "$WORKFLOW_SHA" -- \
+ tests/e2e/golden-source-control-open-diff.spec.ts \
+ tests/e2e/golden-terminal-file-link.spec.ts
+
- name: Install native build tools
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y build-essential python3 xvfb
@@ -946,6 +956,16 @@ jobs:
with:
ref: refs/tags/${{ needs.cut.outputs.tag }}
+ - name: Restore skill-sharing test harness from the workflow ref
+ shell: bash
+ env:
+ WORKFLOW_SHA: ${{ github.workflow_sha }}
+ run: |
+ git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"
+ git checkout "$WORKFLOW_SHA" -- \
+ src/main/skills/skill-freshness-inventory.test.ts \
+ src/main/skills/skill-provider-runtime-roots.test.ts
+
- uses: ./.github/actions/install-node-dependencies
with:
native-runtime: node
@@ -978,13 +998,26 @@ jobs:
steps:
- name: Install Ubuntu 20.04 prerequisites
- run: apt-get update && apt-get install -y build-essential ca-certificates git python3
+ run: apt-get update && apt-get install -y build-essential ca-certificates git python3 unzip
- name: Checkout
uses: actions/checkout@v6
with:
ref: refs/tags/${{ needs.cut.outputs.tag }}
+ - name: Trust the checked-out workspace in the job container
+ run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
+
+ - name: Restore skill-sharing test harness from the workflow ref
+ shell: bash
+ env:
+ WORKFLOW_SHA: ${{ github.workflow_sha }}
+ run: |
+ git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"
+ git checkout "$WORKFLOW_SHA" -- \
+ src/main/skills/skill-freshness-inventory.test.ts \
+ src/main/skills/skill-provider-runtime-roots.test.ts
+
- uses: ./.github/actions/install-node-dependencies
with:
native-runtime: node
diff --git a/AGENTS.md b/AGENTS.md
index 307c975d219..1fbce202438 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -7,13 +7,15 @@ All UI work — layout, color, typography, spacing, component selection, UX beha
Use the `$electron` skill and Playwright CDP for rendered Orca UI checks. Do not use computer-use for Orca UI validation.
# Style
+
## Reuse Before Reimplementing
Before writing new logic at any scale — a function, component, IPC channel, state store, or whole subsystem/flow — check whether an existing implementation already does the job (or nearly does). Extend or generalize it instead of building a parallel version; only write from scratch when nothing fits. Keep the check proportionate: a quick search for trivial code, a real one before building anything substantial.
## Concise/Brief Non-obvious Comments ONLY
- * DO NOT: be verbose, explain the obvious, walk through the code ("WHY not HOW")
- * BE CONCISE. 1 LINE if possible
+
+- DO NOT: be verbose, explain the obvious, walk through the code ("WHY not HOW")
+- BE CONCISE. 1 LINE if possible
## Lint Rules: Do Not Disable Max Lines
@@ -32,6 +34,7 @@ Never use vague names like `helpers`, `utils`, `common`, `misc`, or `shared-stuf
- **Lint**: `oxlint`, or `pnpm run check:code-quality:changed` for changed files (full `pnpm lint` is slow); format with `pnpm format`
# Considerations
+
## Worktree Safety
Always use the primary working directory (the worktree) for all file reads and edits. Never follow absolute paths from subagent results that point to the main repo.
diff --git a/README.md b/README.md
index 8de0ff8d2b9..82dfdbaa5c9 100644
--- a/README.md
+++ b/README.md
@@ -262,6 +262,7 @@ Want to contribute or run locally? See our [CONTRIBUTING.md](.github/CONTRIBUTIN
## Signed Builds
+
Windows code signing sponored/provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org).
## License
diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc
index 02bd0b02bc2..ce712d1c01b 100644
--- a/config/reliability-gates.jsonc
+++ b/config/reliability-gates.jsonc
@@ -2148,9 +2148,7 @@
},
{
"file": "src/cli/runtime/serve-signal-exit-diagnostic.test.ts",
- "assertions": [
- "late update handoff failure cannot rearm termination after child exit"
- ]
+ "assertions": ["late update handoff failure cannot rearm termination after child exit"]
},
{
"file": "src/main/serve-update-handoff.test.ts",
@@ -3335,7 +3333,7 @@
"durationSeconds": 1.5,
"summary": "175/175 at the relocated paths on the unified tool authority, replacing the 2026-08-27 record of the same command at 174/174. That run killed twelve of fourteen mutants as sole deltas — dropping the document branch from the one authority door, removing either browsing-registration refusal or the mint-side refusal that is its converse, deleting the registration notification or widening it to the worktree-wide and any-tab waits, disposing revoked state by grant instead of by page, dropping the hosting-renderer or destroyed-contents check, rebuilding the renderer tool target from the grant, and deleting the teardown identity check under a re-mint — and reported two as ill-posed rather than as kills. The relocation changed no file it names except their directory."
},
-{
+ {
"date": "2026-08-27",
"runner": "local",
"platform": "macos",
@@ -3380,7 +3378,7 @@
"durationSeconds": 0.17,
"summary": "22/22 on the candidate that stops a previewed document writing into this desktop's Downloads folder. The hole was read out of the shipping path, not guessed: the preview partition took the shared browser partition policies whole, including will-download, and a preview guest joins no browser-page registry, so handleGuestWillDownload resolved no owner context, routeBrowserClientDownload answered local for a non-client-hosted contents, and the item got a reserved Downloads name with no prompt and no tab to attribute it to. Downloads are now the one policy the preview partition does not inherit. Red-green with each mutant as the sole delta: making the installer ignore the deny option routes the preview partition's download to the router again, and making the preview protocol installer stop asking for the deny leaves the option unset. The absence half is paired with a presence precondition in the same run — an ordinary browsing partition installed beside the preview one in one test still reaches the download router, so a deny that fenced everything, or a download path that had been removed entirely, would fail rather than pass quietly."
},
-{
+ {
"date": "2026-08-27",
"runner": "local",
"platform": "macos",
@@ -3443,7 +3441,7 @@
"durationSeconds": 0.36,
"summary": "The four surfaces the trusted-click route is built from passed 63/63: the preload's click policy over a real document, including an untrusted dispatched click, an untrusted middle click, an SVG animated href resolved against the document so a relative, rooted or fragment SVG link behaves exactly like the identical HTML anchor, fragment and percent-encoded fragment targets and a trusted middle click; the guest policy's deny-only sinks, its refusal of a navigation that arrives before a document has bound the guest to a grant, and its report gate for an unfocused guest, an unregistered sender, a missing or revoked grant and non-web URLs; will-attach-webview pinning the preview preload in both directions; and the click channel handing main its own sender without a trusted-renderer check."
},
-{
+ {
"date": "2026-08-26",
"runner": "local",
"platform": "macos",
@@ -3470,7 +3468,7 @@
"durationSeconds": 66,
"summary": "The journey passed 3/3 again under --repeat-each=3 on the candidate that clears grants on every fresh shell document and gates the mint channel on the trusted renderer, so neither change disturbs a live preview: the document still rendered, both browser counts held at baseline, and the target=_blank press still routed out as an Orca browser tab."
},
-{
+ {
"date": "2026-08-26",
"runner": "local",
"platform": "macos",
@@ -16840,9 +16838,7 @@
},
{
"file": "src/main/browser/agent-browser-bridge-tab-routing.test.ts",
- "assertions": [
- "closing a tab retires the exact named agent-browser session"
- ]
+ "assertions": ["closing a tab retires the exact named agent-browser session"]
},
{
"file": "src/main/startup/serve-signal-handlers.test.ts",
diff --git a/config/scripts/build-orcad-prebuilds.mjs b/config/scripts/build-orcad-prebuilds.mjs
index 679625b9f6d..efbafbe9a1b 100644
--- a/config/scripts/build-orcad-prebuilds.mjs
+++ b/config/scripts/build-orcad-prebuilds.mjs
@@ -132,12 +132,16 @@ function compileNodePty(dir) {
return built
}
console.log('[orcad-prebuilds] compiling node-pty from patched source ...')
- const result = spawnSync(process.platform === 'win32' ? 'npx.cmd' : 'npx', ['node-gyp', 'rebuild'], {
- cwd: dir,
- stdio: 'inherit',
- env: process.env,
- windowsHide: true
- })
+ const result = spawnSync(
+ process.platform === 'win32' ? 'npx.cmd' : 'npx',
+ ['node-gyp', 'rebuild'],
+ {
+ cwd: dir,
+ stdio: 'inherit',
+ env: process.env,
+ windowsHide: true
+ }
+ )
if (result.status !== 0) {
throw new Error(`[orcad-prebuilds] node-gyp rebuild failed (status ${result.status})`)
}
diff --git a/config/scripts/build-orcad-prebuilds.test.mjs b/config/scripts/build-orcad-prebuilds.test.mjs
index 84c0e83c18f..c91c7e6cc9d 100644
--- a/config/scripts/build-orcad-prebuilds.test.mjs
+++ b/config/scripts/build-orcad-prebuilds.test.mjs
@@ -11,7 +11,8 @@ import {
slotName
} from './build-orcad-prebuilds.mjs'
-const PATCHED_BINDING_GYP = "'ldflags': ['-Wl,--no-as-needed,-l:libutil.so.1,-l:libpthread.so.0,--as-needed']"
+const PATCHED_BINDING_GYP =
+ "'ldflags': ['-Wl,--no-as-needed,-l:libutil.so.1,-l:libpthread.so.0,--as-needed']"
const PATCHED_PTY_CC = '__asm__(".symver openpty,openpty@" ORCA_GLIBC_COMPAT_VERSION);'
const dirs = []
@@ -107,8 +108,9 @@ describe('mergeManifest', () => {
it('does not duplicate a slot rebuilt twice', () => {
const once = mergeManifest(null, { slot: 'darwin-arm64', version: '1.1.0', nodeAbi: '127' })
- expect(mergeManifest(once, { slot: 'darwin-arm64', version: '1.1.0', nodeAbi: '127' }).slots)
- .toEqual(['darwin-arm64'])
+ expect(
+ mergeManifest(once, { slot: 'darwin-arm64', version: '1.1.0', nodeAbi: '127' }).slots
+ ).toEqual(['darwin-arm64'])
})
})
diff --git a/config/scripts/node-pty-job-ownership.cjs b/config/scripts/node-pty-job-ownership.cjs
index 35884c1414a..5ad578fd74a 100644
--- a/config/scripts/node-pty-job-ownership.cjs
+++ b/config/scripts/node-pty-job-ownership.cjs
@@ -1,10 +1,6 @@
'use strict'
-const NODE_PTY_JOB_EXPORTS = [
- 'listJobProcessIds',
- 'terminateJob',
- 'assignCurrentProcessToJob'
-]
+const NODE_PTY_JOB_EXPORTS = ['listJobProcessIds', 'terminateJob', 'assignCurrentProcessToJob']
function assertNodePtyJobOwnership({ nativeName, native, platform = process.platform }) {
if (platform !== 'win32' || nativeName !== 'conpty') {
diff --git a/config/scripts/release-e2e-dispatch-contract.test.mjs b/config/scripts/release-e2e-dispatch-contract.test.mjs
index 18fe76c4c44..d48c7b3fa30 100644
--- a/config/scripts/release-e2e-dispatch-contract.test.mjs
+++ b/config/scripts/release-e2e-dispatch-contract.test.mjs
@@ -10,6 +10,17 @@ const releaseWorkflow = parse(
const e2eWorkflow = parse(readFileSync(join(projectDir, '.github/workflows/e2e.yml'), 'utf8'))
describe('release E2E dispatch contract', () => {
+ it('validates immutable tags with the current golden test harness', () => {
+ const restoreStep = releaseWorkflow.jobs['terminal-rendering-golden'].steps.find(
+ (step) => step.name === 'Restore golden test harness from the workflow ref'
+ )
+
+ expect(restoreStep.env.WORKFLOW_SHA).toBe('${{ github.workflow_sha }}')
+ expect(restoreStep.run).toContain('git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"')
+ expect(restoreStep.run).toContain('golden-source-control-open-diff.spec.ts')
+ expect(restoreStep.run).toContain('golden-terminal-file-link.spec.ts')
+ })
+
it('dispatches tag-scoped E2E only after publication', () => {
const dispatchJob = releaseWorkflow.jobs['post-release-e2e']
const dispatchStep = dispatchJob.steps.find((step) => step.name === 'Dispatch tag-scoped E2E')
diff --git a/config/scripts/skill-sharing-release-workflow.test.mjs b/config/scripts/skill-sharing-release-workflow.test.mjs
index d2b6adcf7d4..b6611a1aa18 100644
--- a/config/scripts/skill-sharing-release-workflow.test.mjs
+++ b/config/scripts/skill-sharing-release-workflow.test.mjs
@@ -44,6 +44,48 @@ describe('skill-sharing release workflow', () => {
expect(command).toContain('src/shared/skill-bundle-install-contract.test.ts')
})
+ it('installs the archive tool required by Electron on the Linux floor', () => {
+ const linux = workflow.jobs['skill-sharing-linux-floor-release-gate']
+ const prerequisites = stepNamed(linux, 'Install Ubuntu 20.04 prerequisites')
+
+ expect(prerequisites.run).toMatch(/apt-get install[^\n]*\bunzip\b/)
+ })
+
+ it('trusts only the checked-out workspace before container git operations', () => {
+ const linux = workflow.jobs['skill-sharing-linux-floor-release-gate']
+ const trustWorkspace = stepNamed(linux, 'Trust the checked-out workspace in the job container')
+ const restoreHarness = stepNamed(
+ linux,
+ 'Restore skill-sharing test harness from the workflow ref'
+ )
+ const safeDirectoryCommands = linux.steps
+ .filter((step) => typeof step.run === 'string' && step.run.includes('safe.directory'))
+ .map((step) => step.run)
+
+ expect(trustWorkspace.run).toBe('git config --global --add safe.directory "$GITHUB_WORKSPACE"')
+ expect(linux.steps.indexOf(trustWorkspace)).toBeLessThan(linux.steps.indexOf(restoreHarness))
+ expect(safeDirectoryCommands).toEqual([
+ 'git config --global --add safe.directory "$GITHUB_WORKSPACE"'
+ ])
+ })
+
+ it('validates immutable tags with the current skill-sharing test harness', () => {
+ for (const jobName of [
+ 'skill-sharing-release-gate',
+ 'skill-sharing-linux-floor-release-gate'
+ ]) {
+ const restore = stepNamed(
+ workflow.jobs[jobName],
+ 'Restore skill-sharing test harness from the workflow ref'
+ )
+
+ expect(restore.env.WORKFLOW_SHA).toBe('${{ github.workflow_sha }}')
+ expect(restore.run).toContain('git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"')
+ expect(restore.run).toContain('skill-freshness-inventory.test.ts')
+ expect(restore.run).toContain('skill-provider-runtime-roots.test.ts')
+ }
+ })
+
it('archives bounded machine-readable evidence from every platform', () => {
for (const jobName of [
'skill-sharing-release-gate',
diff --git a/docs/STYLEGUIDE.md b/docs/STYLEGUIDE.md
index 06be8eda659..e21aaa89228 100644
--- a/docs/STYLEGUIDE.md
+++ b/docs/STYLEGUIDE.md
@@ -137,20 +137,20 @@ Browse `src/renderer/src/components/ui/` for the full list. Most wrap a Radix UI
When a control has multiple plausible primitives, use this fork:
-| You want… | Reach for | Don't use |
-| ------------------------------------------------------------ | -------------------------------------------------------------------- | ------------------------------------- |
-| Hover-only label on an icon-only button | `Tooltip` | `HoverCard` (too heavy), title attr |
-| Hover preview of richer content (avatar + summary) | `HoverCard` | `Tooltip` (no rich content) |
-| Click-revealed menu with actions | `DropdownMenu` | `Popover` with hand-rolled list |
-| Right-click contextual actions | `ContextMenu` | `DropdownMenu` (different invocation) |
-| Click-revealed surface with arbitrary content (form, picker) | `Popover` | `Dialog` (it traps focus and dims) |
-| Modal that demands a decision before you continue | `Dialog` | `Popover`, inline overlay |
-| Drawer / panel sliding in from an edge | `Sheet` | `Dialog` centered |
-| Single choice from a known list | `Select` | Custom listbox |
-| Single choice with search / fuzzy filtering | `Command` inside `Popover` | `Select` (no search) |
-| Multi-select with search | `repo-multi-combobox` (mirror its pattern) | Roll a new one |
-| Transient confirmation ("Saved", "Copied") | `sonner` toast | `Dialog`, inline banner |
-| Persistent inline status ("3 errors") | inline text + `Badge` | toast (toasts disappear) |
+| You want… | Reach for | Don't use |
+| ------------------------------------------------------------ | ------------------------------------------ | ------------------------------------- |
+| Hover-only label on an icon-only button | `Tooltip` | `HoverCard` (too heavy), title attr |
+| Hover preview of richer content (avatar + summary) | `HoverCard` | `Tooltip` (no rich content) |
+| Click-revealed menu with actions | `DropdownMenu` | `Popover` with hand-rolled list |
+| Right-click contextual actions | `ContextMenu` | `DropdownMenu` (different invocation) |
+| Click-revealed surface with arbitrary content (form, picker) | `Popover` | `Dialog` (it traps focus and dims) |
+| Modal that demands a decision before you continue | `Dialog` | `Popover`, inline overlay |
+| Drawer / panel sliding in from an edge | `Sheet` | `Dialog` centered |
+| Single choice from a known list | `Select` | Custom listbox |
+| Single choice with search / fuzzy filtering | `Command` inside `Popover` | `Select` (no search) |
+| Multi-select with search | `repo-multi-combobox` (mirror its pattern) | Roll a new one |
+| Transient confirmation ("Saved", "Copied") | `sonner` toast | `Dialog`, inline banner |
+| Persistent inline status ("3 errors") | inline text + `Badge` | toast (toasts disappear) |
If you find yourself styling around a primitive (`` to act like a `