diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 45a3d12c2d8..ec8aec1d130 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -276,6 +276,12 @@ jobs: HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: node .github/scripts/check-root-directory-entries.mjs "$BASE_SHA" "$HEAD_SHA" + # Why here: the READMEs embed media owned by docs/site and resources/onboarding, + # and the classifier skips static_analysis for docs-only diffs. This job runs + # on every PR and needs no install. + - name: Check README local links + run: node config/scripts/check-readme-local-links.mjs + typecheck: needs: [code_paths] if: needs.code_paths.outputs.typecheck == 'true' diff --git a/README.md b/README.md index 7e3540c80f1..aeb8f355450 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Fan one prompt across five agents, each in its own isolated git worktree — com - Parallel worktree orchestration + Parallel worktree orchestration @@ -68,7 +68,7 @@ Ghostty-class terminals with WebGL rendering, infinite splits, and scrollback th - Terminal splits + Terminal splits @@ -82,7 +82,7 @@ Click any UI element in a real Chromium window to send its HTML, CSS, and a crop - Embedded browser and Design Mode + Embedded browser and Design Mode @@ -96,7 +96,7 @@ Browse PRs, issues, and project boards in-app — open a worktree from any task - GitHub and Linear task workflows in Orca + GitHub and Linear task workflows in Orca @@ -110,7 +110,7 @@ Run agents on a beefy remote box with full file editing, git, and terminals — - Remote worktrees over SSH + Remote worktrees over SSH @@ -124,7 +124,7 @@ Drop comments on any diff line and ship them back to the agent — review, edit, - Annotate AI-generated diffs + Annotate AI-generated diffs @@ -138,7 +138,7 @@ VS Code's editor with autosave everywhere — drag files or images straight into - Drag files and images into an agent prompt + Drag files and images into an agent prompt @@ -152,7 +152,7 @@ Agents drive Orca too — script every workflow with `orca worktree create`, `sn - Script Orca from the CLI + Script Orca from the CLI diff --git a/config/scripts/check-readme-local-links.mjs b/config/scripts/check-readme-local-links.mjs new file mode 100644 index 00000000000..723d7e3ccce --- /dev/null +++ b/config/scripts/check-readme-local-links.mjs @@ -0,0 +1,102 @@ +import { execFileSync } from 'node:child_process' +import { readdirSync, readFileSync } from 'node:fs' +import path from 'node:path' +import process from 'node:process' +import { pathToFileURL } from 'node:url' + +// Why: the READMEs embed media from trees other jobs own (docs-site public media, +// generated feature-wall tiles), and the docs-only classifier skips the whole CI +// matrix for one of them. GitHub renders only committed files, so this checks the +// git index rather than the working tree. +const TRANSLATED_README_DIR = path.join('docs', 'readme') +const EXTERNAL_TARGET = /^(?:[a-z][a-z0-9+.-]*:|#|\/\/)/i +const HTML_ATTRIBUTE = /\b(?:src|srcset|href)\s*=\s*(?:"([^"]*)"|'([^']*)')/g +const MARKDOWN_LINK = /!?\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g + +function readmeFiles(root) { + const translated = readdirSync(path.join(root, TRANSLATED_README_DIR)) + .filter((name) => name.endsWith('.md')) + .sort() + .map((name) => path.posix.join('docs', 'readme', name)) + return ['README.md', ...translated] +} + +// Why only the referenced paths: a full `git ls-files` of this repo overflows the +// default child buffer; asking about a few dozen pathspecs stays bounded. +function trackedFiles(root, candidates) { + if (candidates.length === 0) { + return new Set() + } + const stdout = execFileSync( + 'git', + ['--literal-pathspecs', 'ls-files', '-z', '--', ...candidates], + { cwd: root, encoding: 'utf8' } + ) + return new Set(stdout.split('\0').filter(Boolean)) +} + +function* localTargets(markdown) { + for (const match of markdown.matchAll(HTML_ATTRIBUTE)) { + // Why: srcset is a candidate list ("a.gif 1x, b.gif 2x"); each entry starts with a URL. + for (const candidate of (match[1] ?? match[2]).split(',')) { + const target = candidate.trim().split(/\s+/)[0] + if (target) { + yield target + } + } + } + for (const match of markdown.matchAll(MARKDOWN_LINK)) { + yield match[1].replace(/^<|>$/g, '') + } +} + +function resolveTarget(readme, target) { + const bare = target.split(/[?#]/)[0] + if (!bare) { + return null + } + const resolved = path.posix.normalize( + path.posix.join(path.posix.dirname(readme), decodeURIComponent(bare)) + ) + return resolved.startsWith('../') ? null : resolved +} + +function collectLinks(root) { + const links = [] + for (const readme of readmeFiles(root)) { + const markdown = readFileSync(path.join(root, readme), 'utf8') + for (const target of new Set(localTargets(markdown))) { + if (EXTERNAL_TARGET.test(target)) { + continue + } + links.push({ readme, target, resolved: resolveTarget(readme, target) }) + } + } + return links +} + +export function findBrokenReadmeLinks(root) { + const links = collectLinks(root) + const candidates = [...new Set(links.map((link) => link.resolved).filter(Boolean))] + const tracked = trackedFiles(root, candidates) + return links.filter(({ resolved }) => resolved === null || !tracked.has(resolved)) +} + +export function main(root = process.cwd()) { + const broken = findBrokenReadmeLinks(root) + if (broken.length > 0) { + console.error(`README local link check failed with ${broken.length} broken link(s):`) + for (const { readme, target, resolved } of broken) { + console.error( + `- ${readme}: ${target} -> ${resolved ?? 'outside the repository'} is not tracked` + ) + } + return 1 + } + console.log('README local link check passed.') + return 0 +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + process.exit(main()) +} diff --git a/config/scripts/check-readme-local-links.test.mjs b/config/scripts/check-readme-local-links.test.mjs new file mode 100644 index 00000000000..2f7cfc76c92 --- /dev/null +++ b/config/scripts/check-readme-local-links.test.mjs @@ -0,0 +1,156 @@ +import { execFileSync } from 'node:child_process' +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { parse } from 'yaml' +import { findBrokenReadmeLinks, main } from './check-readme-local-links.mjs' + +const projectDir = path.resolve(import.meta.dirname, '../..') +const tempDirs = [] + +function git(cwd, args) { + return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim() +} + +function writeFiles(root, files) { + for (const [relativePath, contents] of Object.entries(files)) { + const target = path.join(root, relativePath) + mkdirSync(path.dirname(target), { recursive: true }) + writeFileSync(target, contents) + } +} + +function makeFixture(files, { untracked = {} } = {}) { + const root = mkdtempSync(path.join(tmpdir(), 'orca-readme-links-')) + tempDirs.push(root) + git(root, ['init', '--quiet']) + git(root, ['config', 'user.email', 'readme-links-test@example.com']) + git(root, ['config', 'user.name', 'README Links Test']) + writeFiles(root, files) + git(root, ['add', '-A']) + git(root, ['commit', '--quiet', '-m', 'fixture']) + writeFiles(root, untracked) + return root +} + +const validReadmes = { + 'README.md': [ + '', + '', + '日本語', + "", + '', + '[Contributing](.github/CONTRIBUTING.md) [Docs](https://example.com/docs) [Top](#top)', + '![hero](docs/assets/hero%20image.jpg "Hero")' + ].join('\n'), + 'docs/readme/README.ja.md': [ + '', + '', + 'English self', + '[LICENSE](../../LICENSE)' + ].join('\n'), + 'resources/build/icon.png': 'png', + 'resources/onboarding/feature-wall/tile-01.poster.jpg': 'jpg', + 'docs/site/public/docs/tab-split.gif': 'gif', + 'docs/assets/hero image.jpg': 'jpg', + '.github/CONTRIBUTING.md': 'contributing', + LICENSE: 'mit' +} + +afterEach(() => { + vi.restoreAllMocks() + while (tempDirs.length > 0) { + rmSync(tempDirs.pop(), { force: true, recursive: true }) + } +}) + +describe('README local link check', () => { + it('accepts the checked-in READMEs', () => { + vi.spyOn(console, 'log').mockImplementation(() => {}) + expect(main(projectDir)).toBe(0) + }) + + it('accepts local links in every supported shape', () => { + expect(findBrokenReadmeLinks(makeFixture(validReadmes))).toEqual([]) + }) + + it('reports a deleted media file for the root and translated READMEs', () => { + const { 'docs/site/public/docs/tab-split.gif': _gif, ...files } = validReadmes + vi.spyOn(console, 'error').mockImplementation(() => {}) + const root = makeFixture(files) + + expect(findBrokenReadmeLinks(root)).toEqual([ + { + readme: 'README.md', + target: 'docs/site/public/docs/tab-split.gif', + resolved: 'docs/site/public/docs/tab-split.gif' + }, + { + readme: 'docs/readme/README.ja.md', + target: '../site/public/docs/tab-split.gif', + resolved: 'docs/site/public/docs/tab-split.gif' + } + ]) + expect(main(root)).toBe(1) + expect(console.error).toHaveBeenCalledWith( + expect.stringContaining('README.md: docs/site/public/docs/tab-split.gif') + ) + }) + + // Why: GitHub renders the commit, so a file that only exists on disk is broken. + it('reports a referenced file that exists on disk but is not tracked', () => { + const { 'resources/build/icon.png': icon, ...files } = validReadmes + const root = makeFixture(files, { untracked: { 'resources/build/icon.png': icon } }) + + expect(findBrokenReadmeLinks(root).map((link) => link.resolved)).toEqual([ + 'resources/build/icon.png', + 'resources/build/icon.png' + ]) + }) + + it('reports a link that escapes the repository', () => { + const root = makeFixture({ + ...validReadmes, + 'docs/readme/README.ja.md': '' + }) + + expect(findBrokenReadmeLinks(root)).toEqual([ + { readme: 'docs/readme/README.ja.md', target: '../../../outside.png', resolved: null } + ]) + }) + + // Why: a single-quoted attribute is valid HTML and GitHub renders it, so a parser + // that only reads double quotes would pass a README with a broken image. + it('reports a missing target in a single-quoted attribute', () => { + const files = { + ...validReadmes, + 'README.md': `${validReadmes['README.md']}\n` + } + + expect(findBrokenReadmeLinks(makeFixture(files))).toEqual([ + { + readme: 'README.md', + target: 'docs/assets/missing.gif', + resolved: 'docs/assets/missing.gif' + } + ]) + }) + + // Why the ungated job: static_analysis is skipped for docs-only diffs, which is + // exactly the kind of PR that deletes a docs-site GIF the README embeds. + it('runs on every PR through the ungated guard job and in the lint script', () => { + const { scripts } = JSON.parse(readFileSync(path.join(projectDir, 'package.json'), 'utf8')) + const workflow = parse(readFileSync(path.join(projectDir, '.github/workflows/pr.yml'), 'utf8')) + const guardJob = workflow.jobs.root_directory_guard + const step = guardJob.steps.find((candidate) => candidate.name === 'Check README local links') + + expect(guardJob.if).toBeUndefined() + expect(guardJob.needs).toBeUndefined() + expect(step.run).toBe('node config/scripts/check-readme-local-links.mjs') + expect(scripts['check:readme-local-links']).toBe( + 'node config/scripts/check-readme-local-links.mjs' + ) + expect(scripts.lint).toContain('pnpm run check:readme-local-links') + }) +}) diff --git a/config/scripts/vendor-feature-wall-assets.mjs b/config/scripts/vendor-feature-wall-assets.mjs index 7c5b8946508..b1e9b061f8f 100644 --- a/config/scripts/vendor-feature-wall-assets.mjs +++ b/config/scripts/vendor-feature-wall-assets.mjs @@ -20,8 +20,8 @@ const TILES = [ { id: 'tile-01', sourceRoot: ROOT, - gifRelativePath: 'docs/assets/feature-wall/parallel-worktrees.gif', - posterRelativePath: 'docs/assets/feature-wall/parallel-worktrees.jpg' + gifRelativePath: 'docs/site/public/docs/tab-split.gif', + posterRelativePath: 'docs/site/public/docs/posters/tab-split.jpg' }, { id: 'tile-02', diff --git a/docs/assets/agent-statuses.gif b/docs/assets/agent-statuses.gif deleted file mode 100644 index 26d98356197..00000000000 Binary files a/docs/assets/agent-statuses.gif and /dev/null differ diff --git a/docs/assets/annotate-ai-diff.gif b/docs/assets/annotate-ai-diff.gif deleted file mode 100644 index 015d63c849b..00000000000 Binary files a/docs/assets/annotate-ai-diff.gif and /dev/null differ diff --git a/docs/assets/caffeinate-agent-menu-after.png b/docs/assets/caffeinate-agent-menu-after.png deleted file mode 100644 index 393fbd5c0b1..00000000000 Binary files a/docs/assets/caffeinate-agent-menu-after.png and /dev/null differ diff --git a/docs/assets/caffeinate-agent-menu-before.png b/docs/assets/caffeinate-agent-menu-before.png deleted file mode 100644 index 7c12d9ca581..00000000000 Binary files a/docs/assets/caffeinate-agent-menu-before.png and /dev/null differ diff --git a/docs/assets/codex-account-switcher.gif b/docs/assets/codex-account-switcher.gif deleted file mode 100644 index ba23ea67a67..00000000000 Binary files a/docs/assets/codex-account-switcher.gif and /dev/null differ diff --git a/docs/assets/feature-wall/annotate-diff.gif b/docs/assets/feature-wall/annotate-diff.gif deleted file mode 100644 index 015d63c849b..00000000000 Binary files a/docs/assets/feature-wall/annotate-diff.gif and /dev/null differ diff --git a/docs/assets/feature-wall/annotate-diff.jpg b/docs/assets/feature-wall/annotate-diff.jpg deleted file mode 100644 index b01a69f8c24..00000000000 Binary files a/docs/assets/feature-wall/annotate-diff.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/cli-agents.gif b/docs/assets/feature-wall/cli-agents.gif deleted file mode 100644 index bbc128af7c8..00000000000 Binary files a/docs/assets/feature-wall/cli-agents.gif and /dev/null differ diff --git a/docs/assets/feature-wall/cli-agents.jpg b/docs/assets/feature-wall/cli-agents.jpg deleted file mode 100644 index 3af037a413a..00000000000 Binary files a/docs/assets/feature-wall/cli-agents.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/codex-accounts.gif b/docs/assets/feature-wall/codex-accounts.gif deleted file mode 100644 index ba23ea67a67..00000000000 Binary files a/docs/assets/feature-wall/codex-accounts.gif and /dev/null differ diff --git a/docs/assets/feature-wall/codex-accounts.jpg b/docs/assets/feature-wall/codex-accounts.jpg deleted file mode 100644 index 915fcf2be93..00000000000 Binary files a/docs/assets/feature-wall/codex-accounts.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/design-mode.gif b/docs/assets/feature-wall/design-mode.gif deleted file mode 100644 index ec59d5c3c1b..00000000000 Binary files a/docs/assets/feature-wall/design-mode.gif and /dev/null differ diff --git a/docs/assets/feature-wall/design-mode.jpg b/docs/assets/feature-wall/design-mode.jpg deleted file mode 100644 index 37b4730dcb6..00000000000 Binary files a/docs/assets/feature-wall/design-mode.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/file-drag.gif b/docs/assets/feature-wall/file-drag.gif deleted file mode 100644 index 1875a51eede..00000000000 Binary files a/docs/assets/feature-wall/file-drag.gif and /dev/null differ diff --git a/docs/assets/feature-wall/file-drag.jpg b/docs/assets/feature-wall/file-drag.jpg deleted file mode 100644 index 5e1eec9f77d..00000000000 Binary files a/docs/assets/feature-wall/file-drag.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/github-linear.gif b/docs/assets/feature-wall/github-linear.gif deleted file mode 100644 index 8946d4fbfed..00000000000 Binary files a/docs/assets/feature-wall/github-linear.gif and /dev/null differ diff --git a/docs/assets/feature-wall/github-linear.jpg b/docs/assets/feature-wall/github-linear.jpg deleted file mode 100644 index eefd0f53433..00000000000 Binary files a/docs/assets/feature-wall/github-linear.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/keyboard-native.gif b/docs/assets/feature-wall/keyboard-native.gif deleted file mode 100644 index a407acbfc31..00000000000 Binary files a/docs/assets/feature-wall/keyboard-native.gif and /dev/null differ diff --git a/docs/assets/feature-wall/keyboard-native.jpg b/docs/assets/feature-wall/keyboard-native.jpg deleted file mode 100644 index 641c4174801..00000000000 Binary files a/docs/assets/feature-wall/keyboard-native.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/markdown-editor.gif b/docs/assets/feature-wall/markdown-editor.gif deleted file mode 100644 index 591cd2269a2..00000000000 Binary files a/docs/assets/feature-wall/markdown-editor.gif and /dev/null differ diff --git a/docs/assets/feature-wall/markdown-editor.jpg b/docs/assets/feature-wall/markdown-editor.jpg deleted file mode 100644 index fee2cc8fe69..00000000000 Binary files a/docs/assets/feature-wall/markdown-editor.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/orca-cli.gif b/docs/assets/feature-wall/orca-cli.gif deleted file mode 100644 index d6b6b640934..00000000000 Binary files a/docs/assets/feature-wall/orca-cli.gif and /dev/null differ diff --git a/docs/assets/feature-wall/orca-cli.jpg b/docs/assets/feature-wall/orca-cli.jpg deleted file mode 100644 index 9f7bc9143b3..00000000000 Binary files a/docs/assets/feature-wall/orca-cli.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/parallel-worktrees.gif b/docs/assets/feature-wall/parallel-worktrees.gif deleted file mode 100644 index 69193d12905..00000000000 Binary files a/docs/assets/feature-wall/parallel-worktrees.gif and /dev/null differ diff --git a/docs/assets/feature-wall/parallel-worktrees.jpg b/docs/assets/feature-wall/parallel-worktrees.jpg deleted file mode 100644 index 403fdff52f5..00000000000 Binary files a/docs/assets/feature-wall/parallel-worktrees.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/split-screen.gif b/docs/assets/feature-wall/split-screen.gif deleted file mode 100644 index 444fc0fea09..00000000000 Binary files a/docs/assets/feature-wall/split-screen.gif and /dev/null differ diff --git a/docs/assets/feature-wall/split-screen.jpg b/docs/assets/feature-wall/split-screen.jpg deleted file mode 100644 index 295d2a0ef65..00000000000 Binary files a/docs/assets/feature-wall/split-screen.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/ssh-worktrees.gif b/docs/assets/feature-wall/ssh-worktrees.gif deleted file mode 100644 index b6dc393fb1d..00000000000 Binary files a/docs/assets/feature-wall/ssh-worktrees.gif and /dev/null differ diff --git a/docs/assets/feature-wall/ssh-worktrees.jpg b/docs/assets/feature-wall/ssh-worktrees.jpg deleted file mode 100644 index f6df8ef91a0..00000000000 Binary files a/docs/assets/feature-wall/ssh-worktrees.jpg and /dev/null differ diff --git a/docs/assets/feature-wall/terminal-splits.gif b/docs/assets/feature-wall/terminal-splits.gif deleted file mode 100644 index 861c8959525..00000000000 Binary files a/docs/assets/feature-wall/terminal-splits.gif and /dev/null differ diff --git a/docs/assets/feature-wall/terminal-splits.jpg b/docs/assets/feature-wall/terminal-splits.jpg deleted file mode 100644 index 716d4ed03f9..00000000000 Binary files a/docs/assets/feature-wall/terminal-splits.jpg and /dev/null differ diff --git a/docs/assets/file-drag.gif b/docs/assets/file-drag.gif deleted file mode 100644 index 1875a51eede..00000000000 Binary files a/docs/assets/file-drag.gif and /dev/null differ diff --git a/docs/assets/issue-1920/fix.png b/docs/assets/issue-1920/fix.png deleted file mode 100644 index 625a12aa372..00000000000 Binary files a/docs/assets/issue-1920/fix.png and /dev/null differ diff --git a/docs/assets/issue-1920/reproduction.png b/docs/assets/issue-1920/reproduction.png deleted file mode 100644 index 4116b5c15e8..00000000000 Binary files a/docs/assets/issue-1920/reproduction.png and /dev/null differ diff --git a/docs/assets/orca-design-mode.gif b/docs/assets/orca-design-mode.gif deleted file mode 100644 index ec59d5c3c1b..00000000000 Binary files a/docs/assets/orca-design-mode.gif and /dev/null differ diff --git a/docs/assets/orca-mobile-emulator.gif b/docs/assets/orca-mobile-emulator.gif deleted file mode 100644 index d7efcc3d8a8..00000000000 Binary files a/docs/assets/orca-mobile-emulator.gif and /dev/null differ diff --git a/docs/readme/README.es.md b/docs/readme/README.es.md index 85e48c6d765..bb5f15f14e0 100644 --- a/docs/readme/README.es.md +++ b/docs/readme/README.es.md @@ -54,7 +54,7 @@ Lanza un mismo prompt a cinco agentes, cada uno en su propio worktree de git ais - Orquestación de worktrees en paralelo + Orquestación de worktrees en paralelo @@ -68,7 +68,7 @@ Terminales de nivel Ghostty con renderizado WebGL, divisiones infinitas y un scr - Terminales divididas + Terminales divididas @@ -82,7 +82,7 @@ Haz clic en cualquier elemento de UI en una ventana real de Chromium para enviar - Navegador integrado y modo diseño + Navegador integrado y modo diseño @@ -96,7 +96,7 @@ Explora PRs, issues y tableros de proyecto dentro de la app — abre un worktree - Flujos de trabajo de GitHub y Linear en Orca + Flujos de trabajo de GitHub y Linear en Orca @@ -110,7 +110,7 @@ Ejecuta agentes en una máquina remota potente con edición completa de archivos - Worktrees remotos por SSH + Worktrees remotos por SSH @@ -124,7 +124,7 @@ Deja comentarios en cualquier línea de un diff y envíalos de vuelta al agente - Anotar diffs generados por IA + Anotar diffs generados por IA @@ -138,7 +138,7 @@ El editor de VS Code con autoguardado en todas partes — arrastra archivos o im - Arrastra archivos e imágenes al prompt de un agente + Arrastra archivos e imágenes al prompt de un agente @@ -152,7 +152,7 @@ Los agentes también manejan Orca — automatiza cualquier flujo de trabajo con - Automatiza Orca desde la CLI + Automatiza Orca desde la CLI diff --git a/docs/readme/README.fr.md b/docs/readme/README.fr.md index adf966b5053..549f817b9fe 100644 --- a/docs/readme/README.fr.md +++ b/docs/readme/README.fr.md @@ -58,7 +58,7 @@ Lancez un même prompt sur cinq agents, chacun dans son propre worktree git isol - Orchestration de worktrees parallèles + Orchestration de worktrees parallèles @@ -72,7 +72,7 @@ Terminaux de niveau Ghostty avec rendu WebGL, splits infinis et un scrollback qu - Splits de terminal + Splits de terminal @@ -86,7 +86,7 @@ Cliquez sur n'importe quel élément d'UI dans une vraie fenêtre Chromium pour - Navigateur intégré et Mode Design + Navigateur intégré et Mode Design @@ -100,7 +100,7 @@ Parcourez PRs, issues et boards de projet dans l'app — ouvrez un worktree depu - Workflows GitHub et Linear dans Orca + Workflows GitHub et Linear dans Orca @@ -114,7 +114,7 @@ Faites tourner des agents sur une machine distante costaude, avec édition de fi - Worktrees distants via SSH + Worktrees distants via SSH @@ -128,7 +128,7 @@ Posez des commentaires sur n'importe quelle ligne de diff et renvoyez-les à l'a - Annoter les diffs générés par l'IA + Annoter les diffs générés par l'IA @@ -142,7 +142,7 @@ L'éditeur VS Code avec autosave partout — glissez fichiers ou images directem - Glisser des fichiers et images dans le prompt d'un agent + Glisser des fichiers et images dans le prompt d'un agent @@ -156,7 +156,7 @@ Les agents pilotent aussi Orca — scriptez n'importe quel workflow avec `orca w - Scripter Orca depuis la CLI + Scripter Orca depuis la CLI diff --git a/docs/readme/README.ja.md b/docs/readme/README.ja.md index ce5a7ddf07f..58330fe3f43 100644 --- a/docs/readme/README.ja.md +++ b/docs/readme/README.ja.md @@ -54,7 +54,7 @@ - 並列ワークツリーのオーケストレーション + 並列ワークツリーのオーケストレーション @@ -68,7 +68,7 @@ WebGL レンダリング、無制限の分割、再起動後も残るスクロ - ターミナル分割 + ターミナル分割 @@ -82,7 +82,7 @@ WebGL レンダリング、無制限の分割、再起動後も残るスクロ - 組み込みブラウザとデザインモード + 組み込みブラウザとデザインモード @@ -96,7 +96,7 @@ PR、Issue、プロジェクトボードをアプリ内で閲覧 — 任意の - Orca の GitHub と Linear タスクワークフロー + Orca の GitHub と Linear タスクワークフロー @@ -110,7 +110,7 @@ PR、Issue、プロジェクトボードをアプリ内で閲覧 — 任意の - SSH 経由のリモートワークツリー + SSH 経由のリモートワークツリー @@ -124,7 +124,7 @@ PR、Issue、プロジェクトボードをアプリ内で閲覧 — 任意の - AI が生成した Diff への注釈 + AI が生成した Diff への注釈 @@ -138,7 +138,7 @@ PR、Issue、プロジェクトボードをアプリ内で閲覧 — 任意の - ファイルや画像をエージェントのプロンプトへドラッグ + ファイルや画像をエージェントのプロンプトへドラッグ @@ -152,7 +152,7 @@ PR、Issue、プロジェクトボードをアプリ内で閲覧 — 任意の - CLI から Orca をスクリプト操作 + CLI から Orca をスクリプト操作 diff --git a/docs/readme/README.ko.md b/docs/readme/README.ko.md index 81226572e9f..6e6b174e78f 100644 --- a/docs/readme/README.ko.md +++ b/docs/readme/README.ko.md @@ -54,7 +54,7 @@ - 병렬 worktree 오케스트레이션 + 병렬 worktree 오케스트레이션 @@ -68,7 +68,7 @@ WebGL 렌더링, 무한 분할, 재시작 후에도 유지되는 스크롤백을 - 터미널 분할 + 터미널 분할 @@ -82,7 +82,7 @@ WebGL 렌더링, 무한 분할, 재시작 후에도 유지되는 스크롤백을 - 내장 브라우저와 디자인 모드 + 내장 브라우저와 디자인 모드 @@ -96,7 +96,7 @@ PR, issue, 프로젝트 보드를 앱 안에서 탐색하세요 — 어떤 작 - Orca의 GitHub 및 Linear 작업 워크플로 + Orca의 GitHub 및 Linear 작업 워크플로 @@ -110,7 +110,7 @@ PR, issue, 프로젝트 보드를 앱 안에서 탐색하세요 — 어떤 작 - SSH를 통한 원격 worktree + SSH를 통한 원격 worktree @@ -124,7 +124,7 @@ diff의 어느 줄에든 코멘트를 남기고 에이전트에게 바로 보내 - AI가 생성한 diff에 주석 달기 + AI가 생성한 diff에 주석 달기 @@ -138,7 +138,7 @@ diff의 어느 줄에든 코멘트를 남기고 에이전트에게 바로 보내 - 파일과 이미지를 에이전트 프롬프트로 드래그 + 파일과 이미지를 에이전트 프롬프트로 드래그 @@ -152,7 +152,7 @@ diff의 어느 줄에든 코멘트를 남기고 에이전트에게 바로 보내 - CLI에서 Orca 스크립팅 + CLI에서 Orca 스크립팅 diff --git a/docs/readme/README.pt.md b/docs/readme/README.pt.md index 4f4461607d3..8fbc63e1a03 100644 --- a/docs/readme/README.pt.md +++ b/docs/readme/README.pt.md @@ -54,7 +54,7 @@ Envie um mesmo prompt para cinco agentes, cada um em seu próprio worktree git i - Orquestração de worktrees paralelos + Orquestração de worktrees paralelos @@ -68,7 +68,7 @@ Terminais no nível do Ghostty com renderização WebGL, divisões infinitas e s - Terminais divididos + Terminais divididos @@ -82,7 +82,7 @@ Clique em qualquer elemento de UI em uma janela real do Chromium para enviar HTM - Navegador integrado e Modo Design + Navegador integrado e Modo Design @@ -96,7 +96,7 @@ Navegue por PRs, issues e quadros de projeto dentro do app — abra um worktree - Fluxos de trabalho de tarefas do GitHub e Linear no Orca + Fluxos de trabalho de tarefas do GitHub e Linear no Orca @@ -110,7 +110,7 @@ Execute agentes em uma máquina remota potente com edição completa de arquivos - Worktrees remotos por SSH + Worktrees remotos por SSH @@ -124,7 +124,7 @@ Deixe comentários em qualquer linha de diff e envie-os de volta ao agente — r - Anotar diffs gerados por IA + Anotar diffs gerados por IA @@ -138,7 +138,7 @@ O editor do VS Code com salvamento automático em todos os lugares — arraste a - Arraste arquivos e imagens para o prompt de um agente + Arraste arquivos e imagens para o prompt de um agente @@ -152,7 +152,7 @@ Agentes também controlam o Orca — automatize qualquer fluxo de trabalho com ` - Automatize o Orca pela CLI + Automatize o Orca pela CLI diff --git a/docs/readme/README.zh-CN.md b/docs/readme/README.zh-CN.md index 970628edd32..565b76ff5d5 100644 --- a/docs/readme/README.zh-CN.md +++ b/docs/readme/README.zh-CN.md @@ -54,7 +54,7 @@ - 并行 worktree 编排 + 并行 worktree 编排 @@ -68,7 +68,7 @@ Ghostty 级终端,支持 WebGL 渲染、无限分屏,以及重启后依然 - 终端分屏 + 终端分屏 @@ -82,7 +82,7 @@ Ghostty 级终端,支持 WebGL 渲染、无限分屏,以及重启后依然 - 内置浏览器与设计模式 + 内置浏览器与设计模式 @@ -96,7 +96,7 @@ Ghostty 级终端,支持 WebGL 渲染、无限分屏,以及重启后依然 - Orca 中的 GitHub 与 Linear 任务工作流 + Orca 中的 GitHub 与 Linear 任务工作流 @@ -110,7 +110,7 @@ Ghostty 级终端,支持 WebGL 渲染、无限分屏,以及重启后依然 - 通过 SSH 使用远程 worktree + 通过 SSH 使用远程 worktree @@ -124,7 +124,7 @@ Ghostty 级终端,支持 WebGL 渲染、无限分屏,以及重启后依然 - 标注 AI 生成的 diff + 标注 AI 生成的 diff @@ -138,7 +138,7 @@ VS Code 的编辑器,处处自动保存 — 把文件或图片直接拖入智 - 将文件和图片拖入智能体提示 + 将文件和图片拖入智能体提示 @@ -152,7 +152,7 @@ VS Code 的编辑器,处处自动保存 — 把文件或图片直接拖入智 - 从 CLI 脚本化 Orca + 从 CLI 脚本化 Orca diff --git a/docs/review-evidence/pr-19217/README.md b/docs/review-evidence/pr-19217/README.md index ca664ae0c9a..2eaecc5d4c2 100644 --- a/docs/review-evidence/pr-19217/README.md +++ b/docs/review-evidence/pr-19217/README.md @@ -2,7 +2,8 @@ Validated on September 7, 2026 in a background Electron dev instance of `pr19217-review-r2`, based on `ce1024096b` with the source-adapter refactor. -CDP app identity confirmed the checkout; screenshots show the full hidden renderer. +CDP app identity confirmed the checkout; CDP screenshots of the full hidden renderer +were reviewed at the time and are not retained here. The command output is the real `orca worktree ps --json` response reduced to status, agent state, provider, and pane key for readability. @@ -13,9 +14,6 @@ sidebar showed working. Closing its chat tab removed that exact session's row an returned the worktree to `active`. A different completed chat remained present, confirming that closure removed only the selected session. -- [Working: CLI and sidebar](working.png) -- [Closed: CLI and sidebar](closed.png) - The disappearing session is `codex_40677067_f492_4d7d_86dd_ec566ede04c3`. The host's held-session roster controls eligibility; its retained broadcast cache is history, not a roster. Failed eviction intentionally keeps an entry for retry. @@ -37,7 +35,7 @@ targeted lint and diff checks passed. Ablating the runtime call to enumerate retained history caused the executable call-site test to fail with two rows where one was expected; restoring the live accessor passed both call-site tests. -Live screenshots prove Codex working and closure on macOS. Claude provider turns, +Codex working and closure were observed live on macOS. Claude provider turns, approval/input states, live Windows/Linux/WSL/SSH/relay/mobile scenarios and release-scale latency/heap measurements remain unverified. Existing tests cover remote/WSL evidence, monitoring precedence and lifecycle cases. The existing diff --git a/docs/review-evidence/pr-19217/closed.png b/docs/review-evidence/pr-19217/closed.png deleted file mode 100644 index 7f1d8160844..00000000000 Binary files a/docs/review-evidence/pr-19217/closed.png and /dev/null differ diff --git a/docs/review-evidence/pr-19217/working.png b/docs/review-evidence/pr-19217/working.png deleted file mode 100644 index 8ee57052134..00000000000 Binary files a/docs/review-evidence/pr-19217/working.png and /dev/null differ diff --git a/package.json b/package.json index 9cbae455f2d..0c3bd5e6cb5 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "audit:perf": "oxlint --config config/oxlint-performance-audit.json --format json src", "test:perf:contracts": "vitest run --config config/vitest.performance.config.ts", "format": "oxfmt --write .", - "lint": "oxlint && pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run check:reliability-gates && pnpm run check:max-lines-ratchet && pnpm run check:ts-nocheck-ratchet && pnpm run check:runtime-electron-ratchet && pnpm run verify:rpc-params-catalog && pnpm run verify:bundled-skill-guides && pnpm run verify:skill-bundle-manifest && pnpm run verify:localization-catalog && pnpm run verify:localization-runtime-catalog && pnpm run verify:localization-extraction && pnpm run verify:localization-coverage", + "lint": "oxlint && pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run check:reliability-gates && pnpm run check:max-lines-ratchet && pnpm run check:ts-nocheck-ratchet && pnpm run check:runtime-electron-ratchet && pnpm run check:readme-local-links && pnpm run verify:rpc-params-catalog && pnpm run verify:bundled-skill-guides && pnpm run verify:skill-bundle-manifest && pnpm run verify:localization-catalog && pnpm run verify:localization-runtime-catalog && pnpm run verify:localization-extraction && pnpm run verify:localization-coverage", "audit:code-quality": "pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run audit:react-doctor", "audit:code-quality:native": "oxlint --config config/oxlint-code-quality-native-plugins.json src config tests mobile --deny-warnings", "audit:code-quality:type-aware": "oxlint --type-aware --config config/oxlint-code-quality-type-aware.json src config tests --deny-warnings", @@ -34,6 +34,7 @@ "check:max-lines-ratchet": "node config/scripts/check-max-lines-ratchet.mjs", "check:ts-nocheck-ratchet": "node config/scripts/check-ts-nocheck-ratchet.mjs", "check:runtime-electron-ratchet": "node config/scripts/check-runtime-electron-ratchet.mjs", + "check:readme-local-links": "node config/scripts/check-readme-local-links.mjs", "build:orcad": "node config/scripts/build-orcad.mjs", "build:orcad-prebuilds": "node config/scripts/build-orcad-prebuilds.mjs", "smoke:orcad-terminal": "node config/scripts/ensure-native-runtime.mjs --runtime=node && pnpm run build:cli && pnpm run build:orcad && node config/scripts/runtime-serve-terminal-smoke.mjs --target orcad", diff --git a/resources/onboarding/feature-wall/tile-01.recorded-at.json b/resources/onboarding/feature-wall/tile-01.recorded-at.json index 34380500b27..89b8eb6d827 100644 --- a/resources/onboarding/feature-wall/tile-01.recorded-at.json +++ b/resources/onboarding/feature-wall/tile-01.recorded-at.json @@ -1,6 +1,6 @@ { - "recordedAtUnixSeconds": 1778710735, - "recordedAtIso": "2026-05-13T22:18:55.000Z", - "sourceGif": "docs/assets/feature-wall/parallel-worktrees.gif", - "sourcePoster": "docs/assets/feature-wall/parallel-worktrees.jpg" + "recordedAtUnixSeconds": 1788159085, + "recordedAtIso": "2026-08-31T06:51:25.000Z", + "sourceGif": "docs/site/public/docs/tab-split.gif", + "sourcePoster": "docs/site/public/docs/posters/tab-split.jpg" }