From 59515beb7089c4f451ca42b8a0c628ea44ac6ab0 Mon Sep 17 00:00:00 2001
From: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
Date: Fri, 28 Aug 2026 00:55:45 -0700
Subject: [PATCH 1/3] fix(release): recover immutable patch validation gates
(#16984)
* fix(release): recover immutable patch validation gates
* test(e2e): locate wrapped terminal file links
* test(e2e): keep sibling file links on one terminal row
---
.github/workflows/release-cut.yml | 32 +++++++-
.../release-e2e-dispatch-contract.test.mjs | 11 +++
.../skill-sharing-release-workflow.test.mjs | 24 ++++++
.../skills/skill-freshness-inventory.test.ts | 6 +-
.../skill-provider-runtime-roots.test.ts | 34 ++++----
.../golden-source-control-open-diff.spec.ts | 2 +-
tests/e2e/golden-terminal-file-link.spec.ts | 82 ++++++++++++++-----
7 files changed, 152 insertions(+), 39 deletions(-)
diff --git a/.github/workflows/release-cut.yml b/.github/workflows/release-cut.yml
index c035080a203..5d81a8b7ae3 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,23 @@ 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: 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/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..4b963ae38f3 100644
--- a/config/scripts/skill-sharing-release-workflow.test.mjs
+++ b/config/scripts/skill-sharing-release-workflow.test.mjs
@@ -44,6 +44,30 @@ 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('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/src/main/skills/skill-freshness-inventory.test.ts b/src/main/skills/skill-freshness-inventory.test.ts
index 04e778c42dc..5073827081c 100644
--- a/src/main/skills/skill-freshness-inventory.test.ts
+++ b/src/main/skills/skill-freshness-inventory.test.ts
@@ -157,7 +157,11 @@ async function writeSkillLockHash(homeDir: string, skillFolderHash: string): Pro
}
afterEach(async () => {
- await Promise.all(temporaryDirectories.splice(0).map((root) => rm(root, { recursive: true })))
+ await Promise.all(
+ temporaryDirectories
+ .splice(0)
+ .map((root) => rm(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }))
+ )
})
describe('read-only skill freshness inventory', () => {
diff --git a/src/main/skills/skill-provider-runtime-roots.test.ts b/src/main/skills/skill-provider-runtime-roots.test.ts
index f933d4b2ff0..43298e0a738 100644
--- a/src/main/skills/skill-provider-runtime-roots.test.ts
+++ b/src/main/skills/skill-provider-runtime-roots.test.ts
@@ -1,4 +1,4 @@
-import { join } from 'node:path'
+import { join, resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
import {
resolveDefaultHermesSkillsRoot,
@@ -10,14 +10,16 @@ import {
describe('skill provider runtime roots', () => {
it('maps Claude and Grok config homes to their global skill roots', () => {
+ const claudeRoot = resolve('/srv/claude')
+ const grokRoot = resolve('/srv/grok')
expect(
resolveEnvironmentSkillProviderRoots({
- CLAUDE_CONFIG_DIR: join('/srv', 'claude'),
- GROK_HOME: join('/srv', 'grok')
+ CLAUDE_CONFIG_DIR: claudeRoot,
+ GROK_HOME: grokRoot
})
).toEqual({
- claude: join('/srv', 'claude', 'skills'),
- grok: join('/srv', 'grok', 'skills')
+ claude: join(claudeRoot, 'skills'),
+ grok: join(grokRoot, 'skills')
})
})
@@ -27,14 +29,16 @@ describe('skill provider runtime roots', () => {
GROK_HOME: '../grok'
})
expect(roots).toEqual({})
- expect(withClaudeSkillProviderRoot(roots, join('/managed', 'claude'))).toEqual({
- claude: join('/managed', 'claude', 'skills')
+ const managedClaudeRoot = resolve('/managed/claude')
+ expect(withClaudeSkillProviderRoot(roots, managedClaudeRoot)).toEqual({
+ claude: join(managedClaudeRoot, 'skills')
})
})
it('maps a relocated HERMES_HOME to its skill root and ignores relative ones', () => {
- expect(resolveEnvironmentHermesSkillsRoot({ HERMES_HOME: join('/srv', 'hermes') })).toBe(
- join('/srv', 'hermes', 'skills')
+ const hermesRoot = resolve('/srv/hermes')
+ expect(resolveEnvironmentHermesSkillsRoot({ HERMES_HOME: hermesRoot })).toBe(
+ join(hermesRoot, 'skills')
)
expect(resolveEnvironmentHermesSkillsRoot({ HERMES_HOME: '../hermes' })).toBeNull()
expect(resolveEnvironmentHermesSkillsRoot({})).toBeNull()
@@ -52,13 +56,14 @@ describe('skill provider runtime roots', () => {
})
it('defaults the Hermes skills root under LOCALAPPDATA on Windows', () => {
+ const localAppData = resolve('/local')
const resolved = resolveDefaultHermesSkillsRoot({
homeDir: join('/users', 'alice'),
platform: 'win32',
- env: { LOCALAPPDATA: join('/local') },
- directoryExists: (candidate) => candidate === join('/local', 'hermes')
+ env: { LOCALAPPDATA: localAppData },
+ directoryExists: (candidate) => candidate === join(localAppData, 'hermes')
})
- expect(resolved).toBe(join('/local', 'hermes', 'skills'))
+ expect(resolved).toBe(join(localAppData, 'hermes', 'skills'))
})
it('keeps a pre-LOCALAPPDATA Windows dotfolder install discoverable', () => {
@@ -72,13 +77,14 @@ describe('skill provider runtime roots', () => {
})
it('prefers the LOCALAPPDATA tree on Windows when both layouts exist', () => {
+ const localAppData = resolve('/local')
const resolved = resolveDefaultHermesSkillsRoot({
homeDir: join('/users', 'alice'),
platform: 'win32',
- env: { LOCALAPPDATA: join('/local') },
+ env: { LOCALAPPDATA: localAppData },
directoryExists: () => true
})
- expect(resolved).toBe(join('/local', 'hermes', 'skills'))
+ expect(resolved).toBe(join(localAppData, 'hermes', 'skills'))
})
it('falls back to the dotfolder when Windows exposes no usable LOCALAPPDATA', () => {
diff --git a/tests/e2e/golden-source-control-open-diff.spec.ts b/tests/e2e/golden-source-control-open-diff.spec.ts
index 1c7f2735889..2b58b1a3934 100644
--- a/tests/e2e/golden-source-control-open-diff.spec.ts
+++ b/tests/e2e/golden-source-control-open-diff.spec.ts
@@ -43,7 +43,7 @@ test('@golden opens an unstaged file diff from Source Control', async ({
).toBeVisible()
await expect(orcaPage.locator('.editor-header-path').first()).toHaveAttribute(
'title',
- `${realpathSync(path.join(fixture.worktreePath, GOLDEN_CHANGED_PATH))} (diff)`
+ `${realpathSync(path.join(fixture.worktreePath, GOLDEN_CHANGED_PATH)).replaceAll('\\', '/')} (diff)`
)
const probe = orcaPage.getByRole('button', { name: /Source Control/ })
diff --git a/tests/e2e/golden-terminal-file-link.spec.ts b/tests/e2e/golden-terminal-file-link.spec.ts
index 35e6b20959a..a5d940c4cb5 100644
--- a/tests/e2e/golden-terminal-file-link.spec.ts
+++ b/tests/e2e/golden-terminal-file-link.spec.ts
@@ -18,6 +18,11 @@ type LinkClientPoint = { x: number; y: number }
const LINK_SCAN_CHAR_LIMIT = 12_000
+function canonicalFileIdentity(value: string): string {
+ const normalized = path.resolve(value).replaceAll('\\', '/')
+ return process.platform === 'win32' ? normalized.toLowerCase() : normalized
+}
+
async function locateLink(page: Page, needle: string): Promise {
return page.evaluate((needle) => {
const state = window.__store?.getState()
@@ -34,11 +39,19 @@ async function locateLink(page: Page, needle: string): Promise
return null
}
const buffer = pane.terminal.buffer.active
- for (let row = 0; row < pane.terminal.rows; row += 1) {
- const line = buffer.getLine(buffer.viewportY + row)
- const col = line?.translateToString(true).indexOf(needle) ?? -1
- if (col >= 0) {
- return { col: col + Math.floor(needle.length / 2), row, tabId }
+ // Preserve fixed-width cells so paths split across xterm rows stay searchable.
+ const visibleCells = Array.from({ length: pane.terminal.rows }, (_, row) =>
+ (buffer.getLine(buffer.viewportY + row)?.translateToString(false) ?? '').padEnd(
+ pane.terminal.cols
+ )
+ ).join('')
+ const start = visibleCells.indexOf(needle)
+ if (start !== -1) {
+ const center = start + Math.floor(needle.length / 2)
+ return {
+ col: center % pane.terminal.cols,
+ row: Math.floor(center / pane.terminal.cols),
+ tabId
}
}
return null
@@ -162,14 +175,13 @@ test('opens a terminal file link and observes an external edit @golden', async (
await expect(explorerRow).toHaveAttribute('data-selected', 'true', { timeout: 10_000 })
await expect
.poll(
- () =>
- orcaPage.evaluate(
- (expectedPath) => window.__monacoEditorE2E?.filePath === expectedPath,
- filePath
+ async () =>
+ canonicalFileIdentity(
+ (await orcaPage.evaluate(() => window.__monacoEditorE2E?.filePath)) ?? ''
),
{ timeout: 20_000, message: 'Monaco opened a different file identity' }
)
- .toBe(true)
+ .toBe(canonicalFileIdentity(filePath))
writeFileSync(filePath, `${original.trimEnd()}\n\n${changedMarker}\n`)
await expect
@@ -196,14 +208,18 @@ test('reuses a terminal file link already open in a sibling workspace @golden',
test.setTimeout(180_000)
await waitForSessionReady(orcaPage)
const sourceWorktreeId = await waitForActiveWorktree(orcaPage)
- const sibling = await orcaPage.evaluate((sourceId) => {
+ const worktrees = await orcaPage.evaluate((sourceId) => {
const state = window.__store?.getState()
- return (
- Object.values(state?.worktreesByRepo ?? {})
- .flat()
- .find((worktree) => worktree.id !== sourceId) ?? null
- )
+ const entries = Object.values(state?.worktreesByRepo ?? {}).flat()
+ return {
+ source: entries.find((worktree) => worktree.id === sourceId) ?? null,
+ sibling: entries.find((worktree) => worktree.id !== sourceId) ?? null
+ }
}, sourceWorktreeId)
+ const { source, sibling } = worktrees
+ if (!source) {
+ throw new Error('source worktree fixture unavailable')
+ }
if (!sibling) {
throw new Error('sibling worktree fixture unavailable')
}
@@ -230,7 +246,24 @@ test('reuses a terminal file link already open in a sibling workspace @golden',
await ensureTerminalVisible(orcaPage)
await waitForActiveTerminalManager(orcaPage, 30_000)
- const ptyId = await waitForActivePanePtyId(orcaPage)
+ await orcaPage.evaluate(() => {
+ const state = window.__store?.getState()
+ state?.setSidebarOpen(false)
+ state?.setRightSidebarOpen(false)
+ })
+ await expect
+ .poll(
+ () =>
+ orcaPage.evaluate(() => {
+ const state = window.__store?.getState()
+ const tabId = state?.activeTabId
+ const manager = tabId ? window.__paneManagers?.get(tabId) : null
+ return manager?.getActivePane?.()?.terminal.cols ?? 0
+ }),
+ { message: 'terminal did not expand after closing the sidebars' }
+ )
+ .toBeGreaterThan(120)
+ const ptyId = await waitForActivePanePtyId(orcaPage, 30_000)
await waitForPtyShellEcho(orcaPage, ptyId, 15_000)
const printedPath = process.platform === 'win32' ? filePath.replaceAll('\\', '/') : filePath
const command = nodeTerminalCommand(['-e', `console.log(${JSON.stringify(printedPath)})`])
@@ -261,13 +294,18 @@ test('reuses a terminal file link already open in a sibling workspace @golden',
await expect(editorHeader).toContainText('package.json', { timeout: 20_000 })
await expect
.poll(
- () =>
- orcaPage.evaluate(() => ({
- filePath: window.__monacoEditorE2E?.filePath ?? null,
+ async () => {
+ const rendered = await orcaPage.evaluate(() => ({
+ filePath: window.__monacoEditorE2E?.filePath ?? '',
activeWorktreeId: window.__store?.getState()?.activeWorktreeId ?? null
- })),
+ }))
+ return {
+ filePath: canonicalFileIdentity(rendered.filePath),
+ activeWorktreeId: rendered.activeWorktreeId
+ }
+ },
{ timeout: 20_000, message: 'sibling workspace never rendered the linked file' }
)
- .toEqual({ filePath, activeWorktreeId: sibling.id })
+ .toEqual({ filePath: canonicalFileIdentity(filePath), activeWorktreeId: sibling.id })
await expect(orcaPage.getByText('Loading...', { exact: true })).toHaveCount(0)
})
From c4b39295c1e480a3733aee71e8db799b2347ce78 Mon Sep 17 00:00:00 2001
From: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Date: Fri, 28 Aug 2026 00:59:21 -0700
Subject: [PATCH 2/3] style: format codebase (#16935)
* style: format codebase
* style: format codebase
* refactor: extract skill install dialog footer and content
Extract footer and content sections from SkillInstallDialog and
SkillInstallManagementDialog into separate components for improved
maintainability and clarity of component responsibilities.
---
.github/CONTRIBUTING.md | 1 -
.github/workflows/daily-mac-build.yml | 1 -
.github/workflows/hourly-mac-build.yml | 1 -
.github/workflows/pullfrog.yml | 3 +-
AGENTS.md | 7 +-
README.md | 1 +
config/reliability-gates.jsonc | 8 +-
config/scripts/build-orcad-prebuilds.mjs | 16 +-
config/scripts/build-orcad-prebuilds.test.mjs | 8 +-
config/scripts/node-pty-job-ownership.cjs | 6 +-
docs/STYLEGUIDE.md | 28 +--
docs/reference/headless-linux-server.md | 2 +-
docs/reference/linux-glibc-compatibility.md | 10 +-
docs/reference/orcad-operations.md | 39 ++--
docs/reference/remote-wire-compatibility.md | 4 +-
docs/reference/ssh-host-key-verification.md | 37 ++--
docs/reference/windows-process-enumeration.md | 29 +--
docs/reference/windows-setup-shell.md | 2 +-
docs/reference/worktree-scan-fingerprint.md | 62 +++---
docs/reference/wsl-command-execution.md | 2 +-
docs/reference/wsl-runner-verification.md | 30 +--
docs/reference/xterm-patch-regeneration.md | 2 +-
skill-guides/orca-emulator-android.md | 28 +--
skill-guides/orca-emulator.md | 32 +--
skill-guides/orca-per-workspace-env.md | 24 ++-
src/cli/bundled-skill-guides.ts | 6 +-
...ubprocess-foreground-degraded-scan.test.ts | 21 +-
src/main/orcad/native-host-abi.ts | 8 +-
src/main/orcad/node-pty-prebuilt-slot.ts | 11 +-
src/main/ssh/build-toolchain-diagnosis.ts | 1 -
src/main/ssh/orcad-activation-record.ts | 4 +-
src/main/ssh/orcad-remote-deploy.test.ts | 4 +-
src/main/ssh/orcad-remote-deploy.ts | 29 ++-
src/main/ssh/orcad-remote-gc.test.ts | 4 +-
src/main/ssh/orcad-remote-launch.ts | 9 +-
src/main/ssh/orcad-remote-rollback.test.ts | 5 +-
src/main/ssh/orcad-remote-rollback.ts | 10 +-
...-remote-shell-commands.integration.test.ts | 6 +-
src/main/ssh/remote-install-gc.ts | 5 +-
src/main/ssh/ssh-relay-versioned-install.ts | 6 +-
.../rich-markdown-tab-key-handler.test.ts | 1 -
.../skills/SkillBundleInstallFlow.tsx | 19 +-
.../components/skills/SkillInstallDialog.tsx | 117 ++++-------
.../skills/SkillInstallDialogFooter.tsx | 81 ++++++++
.../skills/SkillInstallManagementDialog.tsx | 173 ++++++++--------
.../SkillInstallManagementDialogContent.tsx | 151 ++++++++++++++
tests/e2e/fixtures/terminal-emoji-table.md | 196 +++++++++---------
tests/e2e/ssh-config-host-picker.PLAN.md | 114 +++++-----
tests/tools/daemon-relocation-spike/README.md | 10 +-
.../repro-watcher-crash-7547/fixed-child.cjs | 33 ++-
tests/tools/repro-watcher-crash-7547/run.cjs | 4 +-
tests/tools/win-update-e2e/README.md | 36 ++--
52 files changed, 842 insertions(+), 605 deletions(-)
create mode 100644 src/renderer/src/components/skills/SkillInstallDialogFooter.tsx
create mode 100644 src/renderer/src/components/skills/SkillInstallManagementDialogContent.tsx
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/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..77e9d6e79ed 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",
@@ -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/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 `