* feat(i18n): add Russian UI language
Register `ru` as a built-in UI language using the catalog from #33370,
reconciled against current en.json: keys pruned from English were dropped,
stale translations whose English source changed were removed, and the
catalog verifier now accepts CLDR few/many forms for an existing `_other`
family.
Co-authored-by: Vyacheslav Scherbinin <gentslava@mail.ru>
* fix(i18n): drop Russian _one entries superseded by count placeholders
Main now interpolates the count in English _one strings (#34693), so the
literal-1 Russian forms no longer match their source.
* feat(i18n): complete Russian catalog and add terminology glossary
Translate the 650 remaining English keys and the few/many plural forms for
every count family, and document the Russian glossary and style conventions.
* fix(i18n): apply reviewed Russian translation corrections
Fix mistranslations and grammar flagged in a full-catalog review, and align
terminology with the glossary: рабочее дерево for worktree, рабочее
пространство for workspace, пул-реквест and файлы cookie.
* fix(i18n): resolve Russian plural forms in main-process strings and align ru terminology
translateMain now resolves literal _one/_other keys through the CLDR plural
family like translate(), so native dialogs pick Russian few/many forms. The
plural helpers move to src/shared for reuse. apply-translation-delta accepts
locale-only plural categories sourced from English _other. ru.json follows the
glossary for account/session/prompt and uses a single ellipsis character.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Vyacheslav Scherbinin <gentslava@mail.ru>
* perf(native-chat): skip session-bridge reconcile for rank-only worktree patches
Share the worktree owner-row token with editor identity so sort-order,
unread and activity patches no longer re-walk every structured session tab.
* test: type the reranked owner row
Register a `cuda-cpp` Monaco language (VS Code's id) that reuses Monaco's
C++ grammar with CUDA qualifiers, built-ins, and vector types as keywords.
Map `.cu`/`.cuh` to it, and alias it to lowlight's cpp grammar on mobile.
Fixes#21267
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
gh pr list already scopes --search with repo:OWNER/REPO type:pr. The
extra is:pr Orca added made private-repo PR lists come back empty when
gh is authenticated with a GitHub App user token (ghu_).
Fixes#34536
* fix(mobile): release cancelled relay subscription callbacks
* test(mobile): run relay cancellation GC regression tests by default and in CI
Expose GC via v8 flags so the collection cases no longer skip under the default pool or Bun, run the file on Node in mobile CI, and drop cases that already passed on main.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(mobile): show pasted pairing feedback without camera access
* test(mobile): drop unreachable revoke and mock-only listener tests
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix: bound local iteration checks and show live progress
* fix: harden check lifecycles and cached test evidence
* fix: preserve process instrumentation and fixture lifecycles
* fix: give fixture unref spy a portable function type
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Extensionless files such as bin/deploy now pick their syntax highlighting
from a leading shebang (python, shell, node, ruby, perl, php, lua,
powershell, ts-node/tsx) via the shared setup-script shebang parser.
Named files and unmapped extensions keep their name-based language, and
diff tabs stay name-based so highlighting does not flicker on save.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* fix(github): count gh pr and issue commands against the GraphQL rate limit
gh serves pr/issue/repo view-style subcommands over GraphQL, but the breaker
filed every non-api command under core and only matched REST's
"API rate limit exceeded" wording, so GraphQL exhaustion never tripped it.
Map those subcommands to the graphql bucket, match GraphQL's
"API rate limit already exceeded", and guard project-view issue close/reopen
against the GraphQL quota.
Fixes#28767
* test(github): drop redundant Date.now() args in graphql breaker test
Keeps the flaky-test-pattern ratchet at its baseline.
---------
Co-authored-by: Neil <neil@stably.ai>
The Goose (block.github.io/goose/docs/quickstart/) and Continue
(docs.continue.dev/guides/cli) links 404. Point them at
goose-docs.ai/docs/quickstart/ and docs.continue.dev/cli/quickstart in
the READMEs, the supported-agents docs page, and the in-app agent catalog.
Co-authored-by: Neil <neil@stably.ai>
* perf(native-chat): memoize file-link context per chat on its resolver inputs
Every mounted chat (hidden ones included) re-resolved its directory and
runtime owner on every store write. Reuse the context until an input the
resolvers read changes.
* docs(native-chat): scope the file-link input completeness comment
* feat(i18n): add Traditional Chinese (zh-Hant) UI locale
Adds 繁體中文 as a selectable UI language and derives its catalog from
zh.json rather than translating English afresh, so the reviewed Simplified
terminology and Orca glossary decisions carry over.
The conversion needed three corrections beyond OpenCC's `cn -> twp`:
- One pass only. `twp`'s phrase dictionary is not idempotent (it maps
進程->程序 and 程序->程式), and iterating to a fixed point makes output
worse: it rewrites the correct Taiwan 游標 to 遊標, and 程序 to 程式 where
the source meant an OS process.
- 16 terms where `twp` emits a form Taiwan does not use, each confirmed
against Microsoft's VS Code zh-Hant language pack (許可權 0 vs 權限 84,
賬戶 0 vs 帳戶 111, and so on).
- 進程 vs 程序 collapse in `twp` output. Taiwan calls an OS process 行程, so
the generator consults the Simplified source to disambiguate; daemon copy
reads 守護行程, not 守護程式.
Also pins `load: 'currentOnly'` on both i18next instances. i18next's default
expands `zh-Hant` into ['zh-Hant', 'zh', 'en'], so a key missing from the
Traditional catalog would silently render Simplified.
zh-Hant.json is generated and compared byte-for-byte, so the new check is
wired into verify:localization-catalogs to fail when a Simplified edit skips
regeneration.
Refs #10592
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(i18n): fail the zh-Hant check on an unreadable zh.json
The generator caught every error from reading and parsing zh.json, so a
malformed or unreadable Simplified catalog logged "absent here" and exited
0 without ever comparing the generated Traditional catalog. Only ENOENT
means there is nothing to derive, so every other failure now propagates.
Tests cover the three paths the catch was conflating: an absent zh.json
still passes for the combined verifier's synthetic fixtures, malformed
JSON throws, and a directory where the catalog belongs throws EISDIR
rather than reporting the file as missing.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* feat(i18n): ship Traditional Chinese (Taiwan) as a maintained built-in catalog
Keeps the zh-Hant locale from this PR and makes it a hand-maintained
catalog like the other built-ins, without the OpenCC generator:
- Catalog reconciled with current en.json. Per key it prefers the
Taiwan-reviewed copy from #22402 (which carries #14223), falls back to
the zh-derived copy here, and drops entries whose English changed.
A review pass then applied Taiwan terms (代理程式, 工作階段, 存放庫,
分頁, 列/欄) and 「」 quotes. Glossary: config/i18n-traditional-chinese.md.
- Label 繁體中文(台灣)in every catalog, the picker, onboarding and search.
- Detection maps zh-TW/zh-HK/zh-MO/zh-Hant* to zh-Hant; zh-CN/zh-SG/zh-Hans
stay on zh. Both i18next instances use load: 'currentOnly' so missing
keys fall back to English, not Simplified.
- Drops opencc-js, the generator scripts and their verify hook.
Co-authored-by: hungchihsueh <84211143+hungchihsueh@users.noreply.github.com>
Co-authored-by: chilung-cgu <b0423031@gmail.com>
* feat(i18n): translate remaining Traditional Chinese (Taiwan) catalog keys
Fill the 2,043 keys added to en since the source PRs branched, following
the Taiwan glossary, and extend the glossary with skill, automation,
usage, review, token and related terms.
* fix(i18n): review Traditional Chinese (Taiwan) catalog wording
Apply 629 reviewed corrections across the full catalog: 30 meaning or
untranslated-text fixes and 599 glossary and phrasing fixes (終端機, 用量,
API 金鑰, clearer counts and actions). Each edit was cross-checked by an
independent review pass.
* fix(i18n): polish sampled zh-Hant strings and drop redundant locale test
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: hungchihsueh <84211143+hungchihsueh@users.noreply.github.com>
Co-authored-by: chilung-cgu <b0423031@gmail.com>
The layout oracle merge gate keeps Blacksmith via fast_runners: true; the
advisory e2e call, nightly schedule and layout-owner dispatch run on
ubuntu-24.04.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Naming a Dispatch's own Run with --run is equivalent to omitting it, so
mail to a Dispatch whose assignee now coordinates a child Run redirects
to that Run's mailbox instead of failing recipient_run_mismatch.
Fixes#24699
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* ci: run terminal perf on demand only, on a hosted runner
The nightly failed every run: the presented-frame guard accepts only
GitHub-hosted Xvfb displays, but the workflow ran on Blacksmith. Drop the
schedule, move dispatch runs to ubuntu-24.04 and document local use.
* docs: record the first hosted terminal perf result
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
isTrustedBrowserRenderer and isTrustedClipboardRenderer fell back to
trusting any sender whose URL started with file:// in packaged builds
when no main renderer id was pinned (e.g. after the last window closes
on macOS), unlocking clipboard read/write and all browser:* handlers for
arbitrary local documents. Fail closed like isTrustedUIRenderer already
does, and share one isTrustedMainRendererSender check across the browser,
clipboard, and UI trust gates so they cannot drift again.
Fixes#25521
Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
* feat(tab-bar): "(CLI)" rows in the + menu offer a chat button
An agent set to open as a CLI shows as "Claude (CLI)" in the + menu with no
way to start it as a chat, while chat rows already carry a trailing terminal
button for the CLI. A CLI row whose agent can open as a chat on this host now
carries the mirror button: the row starts the CLI, the button (or ArrowRight,
then Enter) starts the chat.
* Test agent menu activation and alternate route work
* Use activated agent menu action and skip unused route work
* Fix agent menu lint and formatting
* Cover CLI row annotations in picker and search
* Share prepared agent menu answer context and verify route work
* Align agent menu fixture imports with static checks
NativeChatResolvedView rendered NativeChatMessageList without an image
runtime context, so image-ref attachments in terminal-backed chats (e.g.
Claude pasted images) fell into the label-only compatibility mode with
no thumbnail or click-to-open. Resolve the owner with the existing
useNativeChatImageRuntimeContext(terminalTabId), as the structured lane
does, so reads route through the tab's local/folder/runtime/SSH owner
and fail closed while ownership is unresolved.
Fixes#22327
Running a command group with no subcommand (e.g. `orca skills`,
`orca browser identity`) printed "Unknown command" with unrelated
suggestions. Print the group's help instead, and when flags are passed
to a bare group, report a missing subcommand that points at its help.
Co-authored-by: Neil <neil@stably.ai>
New-agent tab shortcuts pressed while the floating workspace panel owns
focus now launch the agent in the floating workspace instead of the main
worktree. Both the main workspace capture listener and the floating
panel's own shortcut handler route through one shared launcher, so the
agent launches exactly once regardless of listener order, including when
no main worktree is open.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* fix(i18n): resolve count strings with each language's plural rules
translate() now resolves a literal _one/_other key passed a numeric count
through its plural family, so i18next picks the CLDR form for the active
language or plugin pack. Built-in catalogs fill missing plural categories
(e.g. many in es/fr/pt) from _other so large counts stay in-language.
_one strings that hardcoded 1 now interpolate the count.
Closes#12106
* fix(i18n): pass value0 to fullCoverage_one so one-form languages interpolate the count
Languages with a single plural category (ja/ko/zh) now resolve count 1 to fullCoverage_other, which interpolates {{value0}}.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
`orca worktree ps --agent-wait --json` now reports, on each terminal-backed
agent row of the returned page, the same agentWait verdict
`orca terminal show --json` gives for that terminal. The lookup is opt-in
(RPC `includeAgentWait: true`) because it reads screens and may probe PTYs,
which is too costly for default pollers. Hook rows use their terminal handle
only when a connected PTY confirms it, and pane-only hook rows resolve the
live terminal by pane key. Structured-worker rows and older hosts omit the
field (absent = not evaluated; null = looked, no wait).
Fixes#23921
Co-authored-by: Neil <neil@stably.ai>
Bundled ConPTY 1.23 sends a DA1 query as soon as its input reader starts
and stalls ~3s waiting for the reply. The daemon held that query in the
startup buffer until a client attached, so every new Windows pane paid
the stall. The startup watcher now answers the DA1 itself, strips the
query from the replayed startup output, and leaves CPR and other output
for the client. The ConPTY DA1 reply moves to a shared constant used by
the daemon and renderer.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* Revert "Keep same-machine folders with matching Git remotes in separate projects (#32272)"
This reverts commit 29a5f89b8a.
On a machine with several clones of one repo, #32272 moved the oldest clone
into the shared cross-host project. Shared Windows QA machines have several
orca clones, so everyone's sidebar "orca" project suddenly gained that
machine's main checkout and its worktrees. Revert until the intended
grouping is decided.
Conflicts resolved against later main: Settings files moved into
settings/repository (imports adjusted), and two test files later deleted on
main stay deleted.
* Use checked types in restored test fixtures
* Combine restored fixture type imports
resolveEditorOwnerRoute spread the full app state on every owner lookup;
project only route inputs, cached per state. Compare worktreesByRepo by its
owner fields so sort-order/unread/activity patches skip editor ownership
invalidation.
Linear-provided titles, states, assignees, projects, labels, workspace
names and error messages were printed verbatim, so remote text could
emit OSC/CSI/C1 sequences or forge extra output lines. Move terminalSafe
into src/shared/terminal-safe-text.ts, add terminalSafeLine (collapses
CR/LF), and apply it to every Linear text field in the human-readable
formatters. --json output is unchanged.
Fixes#20478
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* chore(i18n): add a detector for catalog keys no source references
A key can leave the code without leaving the catalog: a feature is reverted, a
setting is rewritten in place, a component is deleted. Nothing fails, so the
entries stay. Every locale carries them, translators spend effort on strings no
screen renders, and coverage numbers understate how much is actually translated.
`verify:localization-extraction` already reports an unreferenced set, but it
cannot be deleted as-is: i18next-cli does not see a key held in a data structure
(`{ key: '…' }`) or passed as a variable, and 18 files do exactly that. So this
requires two independent conditions — extraction misses the key AND the exact
string appears in no source literal under src/ or mobile/.
Two properties matter and both were found the hard way:
- Plural variants are judged by their base key. i18next appends the CLDR
category at runtime, so `…_one` never appears in a source file even though the
base does. Without this the scan eats every plural in the catalog.
- The scan is iterative. Removing a base key can strand the variants that
survived on its account, so it must be re-run until it reports none.
Registered as `verify:localization-orphans` but deliberately left out of the
lint chain: it reports 1,401 keys on current main, so gating now would fail CI.
The prune and the gate come together in a follow-up.
* test(i18n): cover the orphan detector's two non-obvious rules
Both rules decide whether a key is live, and both are easy to break without
noticing: the plural rule keeps `…count_one` when only `…count` appears in
source, and the literal scan is the sole evidence for keys extraction cannot
see — held in a data structure or passed as a variable.
Extracting them as pure functions changes no behaviour: the detector still
reports 14,459 keys, 12,887 referenced, 1,401 orphans, and --check still
exits 1.
* chore(i18n): rename the detector's key pattern constant
main gained the anti-slop rule no-shape-in-symbol-names after this branch
was cut, and KEY_SHAPED trips it once the branch is merged with main.
Renamed to CATALOG_KEY_PATTERN; no behaviour change.
* chore(i18n): name the orphan detector like the other localization verifiers
CODEOWNERS routes /config/scripts/*localization*.mjs to the localization owner, and find-orphaned-catalog-keys.mjs matched neither that pattern nor *locale*, so a change to it asked nobody for review. The file now carries the name of the npm script that runs it, verify:localization-orphans.
* fix(i18n): report stranded plural variants in the same pass as their base key
isKeyReferenced kept a plural variant alive whenever en.json still carried its base key, even when no source reached that base key. The base key was reported and the variants were not, so a prune needed a second run to find them. Only a base key that extraction or a source literal references keeps its variants now; the --check message drops the re-run advice and names the override tables, which sit outside the scan roots.
* fix(i18n): let the literal scan accept every key-shaped literal
The scan captured only literals of seven characters or more and then applied CATALOG_KEY_PATTERN, which has no such floor. A live key shorter than that, held in a data structure, would have been reported as an orphan. en.json has no key that short today, so the result is unchanged; the capture now leaves the shape decision to the one pattern.
* fix(i18n): stop the orphan scan when a source root cannot be read
collectSourceFiles swallowed every readdir error, so a directory it could not read contributed no literals and a key named only there would have been reported as safe to delete. Only a missing mobile/ root is skipped now, since a checkout without the mobile app is still a complete desktop scan; any other error stops the scan.
* style(i18n): wrap one line of the orphan detector to the formatter's width
* chore(i18n): fold the orphan-key detector into the extraction check and retire 1,644 unreferenced keys
verify-localization-extraction.mjs now filters its own unreferenced set by
source literals (src/ and mobile/), plural base keys and dynamic prefixes
composed inside translate calls, and fails when any key is named nowhere.
That replaces the standalone verify-localization-orphans.mjs script and its
second extraction pass.
The prune is recomputed on current main: 1,644 keys leave all seven locale
catalogs, 285 stale entries leave the key-override tables, and
en-runtime-required.json is regenerated.
Supersedes #19801.
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
* chore(i18n): scope the unused-key scan to src/ and require a dotted dynamic prefix
mobile/ edits do not trigger the extraction check, so literals there must not
decide its verdict; a dotless runtime-built prefix would keep unrelated keys alive.
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
Packaged macOS builds now append /opt/local/bin and /opt/local/sbin to the
seeded PATH when the default-prefix `port` binary exists, and the agent CLI
install-dir fallback also checks /opt/local/bin. Both are appended last so
existing Homebrew/system resolutions never change.
Co-authored-by: Neil <neil@stably.ai>
Each openFiles change (e.g. a dirty toggle) re-resolved every tab's owner
route twice. Cache owner keys per tab until an owner input changes, so a
single-tab update resolves only that tab.
dsh-tui 0.14+ boots the backend last picked in its launchpad
(~/.dsh-tui/kernel.json), so a plain `dsh-tui --resume <id>` could hand
a DSH session id to the Claude or Codex backend. Pin --backend=dsh in the
resume argv; dsh-tui <0.14 skips the joined form, but would read a
separate `dsh` token as the initial prompt.
Fixes#27944
* ci: restore main's Vitest transform cache in PR unit shards
Main produces per-shard transform caches on a schedule; PR shards restore
the newest one for the same config/lockfile/runtime policy. A Vitest cache
key generator folds each literal specifier's resolution candidates into the
per-module key so newly added files that shadow a resolution invalidate the
importer, and bails on glob-expanded dynamic imports.
* ci: list the resolution key plugin in the node tsconfig project
* ci: accept Vitest's CACHEDIR.TAG when sealing the unit module cache
Vitest 5.0.5 tags its cache root, which made every seal fail with
'invalid cache entry name' so no producer cache was ever saved.
* ci: reseed the unit module cache when any cache-key input lands on main
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
The contracts count operations and retained objects; wall-clock budgets
stay in pnpm test:perf:benchmarks, which no CI job runs. They do not
need Blacksmith's consistent hardware, and the PR path filter runs them
~40 times a day ($7.90/day, $5.50 of it on the 6-vCPU Mac).
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Each 12-vCPU arch job spends ~3 of its ~7 minutes waiting on Apple's
notary service; packaging itself runs at the same speed as the hourly
build's 6-vCPU runner. Halve the per-minute rate.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>