Commit Graph
17159 Commits
Author SHA1 Message Date
Žan MlakarandNeil 4dca163bb7 fix(github): count gh pr and issue commands against the GraphQL rate limit (#28778)
* 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>
2026-10-27 22:57:10 -07:00
yzxcj797andNeil 9105ade917 docs: fix dead Goose and Continue quickstart links (#14574)
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>
2026-10-27 22:56:44 -07:00
Neil 766462be18 perf(native-chat): memoize file-link context per chat on its resolver inputs (#34755)
* 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
2026-10-27 22:51:41 -07:00
b62f9bf624 feat(i18n): add Traditional Chinese (zh-Hant) UI locale (#29795)
* 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>
2026-10-27 22:49:49 -07:00
OrcaWinandOrcaWin 0a5f9e9dc5 fix: keep identifier casing locale-independent (Turkish) (#34709)
* fix: keep identifier casing locale-independent (Turkish)

Under a tr/az default locale, toLocaleLowerCase()/toLocaleUpperCase() map
I to dotless ı and İ, and default-locale collation stops treating I/i as
base-equal. Switch identifier matching (Linear CLI selectors, priorities,
error classification, plugin/Jira/worktree/address/slash-command search) to
toLowerCase()/toUpperCase(), and pin collation to 'en' where ordering feeds
hashes, canonical JSON, semver precedence, remote selection, SSH Include
order, or WSL distro equality. User-visible prose casing and display-list
sorting stay locale-aware.

* fix: order SSH Include globs bytewise and fold dashboard search ids locale-independently

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 22:47:01 -07:00
OrcaWinandOrcaWin 9558439018 perf(i18n): ship only main-process strings in the main bundle (#34711)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 22:46:57 -07:00
OrcaWinandOrcaWin 7b74657a32 fix(sidebar): keep incoming host headers above sticky groups (#34751)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 22:46:42 -07:00
Jinjing 66e2d39827 Keep agent handoff confirmations linked to their workspace (#34722) 2026-10-27 22:16:38 -07:00
OrcaWinandOrcaWin ca2154945b ci: run advisory e2e lanes on free hosted runners (#34725)
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>
2026-10-27 22:08:17 -07:00
lorenzozaneandNeil 57c2b53625 fix(orchestration): allow owner Run to address a nested worker Dispatch (#24974)
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>
2026-10-27 21:49:39 -07:00
OrcaWinandOrcaWin 8b7f8c88ce ci: run terminal perf on demand only, on a hosted runner (#34726)
* 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>
2026-10-27 21:48:08 -07:00
NeilandMatheus Breguêz 32a50856ac fix(ipc): refuse unpinned file:// senders for browser and clipboard IPC (#34710)
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>
2026-10-27 21:38:45 -07:00
Neil 6a55358427 fix(test): resolve Claude rewind session module from structured folder (#34721) 2026-10-27 21:35:51 -07:00
Brennan Benson 5d6cb343ab Native chat tabs show Hand Off in their top-right header, like terminals (#34544)
* Add Hand Off to the native chat pane header

* Test native chat header and menu hand-off parity
2026-10-27 21:34:13 -07:00
Brennan Benson c0a7aca7ee The + menu can start a "(CLI)" agent as a chat (#34587)
* 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
2026-10-27 21:23:03 -07:00
Brennan Benson b4131707fd fix(onboarding): complete default-agent setup for No agent (#31463)
* fix(onboarding): count an explicit no-agent choice as configured

* fix(onboarding): preserve historical setup migration eligibility

* Route setup progress workspace reads through selector
2026-10-27 21:15:26 -07:00
Brennan Benson 74a2ee5337 docs(cli): explain automation prechecks and folder workspace removal (#34523) 2026-10-27 21:13:03 -07:00
Brennan Benson c81b4bc9b4 fix(chat): allow Claude rewind without retained messages (#34239) 2026-10-27 21:12:50 -07:00
lurunzi 884867d5ea fix(native-chat): restore image previews in terminal-backed Chat (#22328)
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
2026-10-27 21:12:20 -07:00
Ehsan-hashandNeil 861d5a2912 fix(cli): show help for bare command groups (#34502)
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>
2026-10-27 21:12:11 -07:00
OrcaWinandOrcaWin ee09f979fa test: remove 78 low-value cases and four entire suites (#34687)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 21:00:57 -07:00
GldywnandNeil a012e457e8 fix(floating-workspace): open agent shortcuts in the focused panel (#23211)
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>
2026-10-27 20:51:13 -07:00
OrcaWinandOrcaWin 2db73d5e47 fix(i18n): resolve count strings with each language's plural rules (#34693)
* 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>
2026-10-27 20:51:09 -07:00
小七andNeil ea6c69be9a fix(runtime): add opt-in agentWait to worktree ps agent rows (#24142)
`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>
2026-10-27 20:46:00 -07:00
Li EnYuandNeil 40721a849b fix(terminal): answer ConPTY startup DA1 before stream attachment (#34466)
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>
2026-10-27 20:40:45 -07:00
Brennan Benson 8d908764dc Revert "Keep same-machine folders with matching Git remotes in separate projects (#32272)" (#34662)
* 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
2026-10-27 20:38:35 -07:00
Neil 44e26301e2 perf(editor): stop rank-only worktree patches and full-state copies from driving owner sweeps (#34705)
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.
2026-10-27 20:31:05 -07:00
Samuel VilaandNeil 66134086bd fix(cli): strip terminal control sequences from Linear text in CLI output (#31677)
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>
2026-10-27 20:30:08 -07:00
76d4b01969 chore(i18n): gate unreferenced catalog keys in the extraction check and retire 1,644 of them (#22056)
* 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>
2026-10-27 20:29:43 -07:00
Hyein ChoandNeil 48f7ce7fed feat(terminal): seed MacPorts /opt/local on PATH when port is installed (#20146)
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>
2026-10-27 20:24:47 -07:00
927a9573c6 docs: record which CI jobs stay on Blacksmith and why (#34685)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-27 20:20:12 -07:00
OrcaWinandOrcaWin 0323d28498 test: remove 49 low-value test cases (#34678)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 20:13:46 -07:00
Neil 68f0c7999f perf(editor): reuse model owner keys in closed-tab cleanup (#34691)
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.
2026-10-27 20:12:02 -07:00
Justas Brazauskas 280dee2477 fix(dsh): resume DSH sessions on the DSH backend (#27949)
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
2026-10-27 20:08:52 -07:00
8b64ec281a ci: restore main's Vitest transform cache in PR unit shards (#34512)
* 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>
2026-10-27 20:04:56 -07:00
Neil 6bb0c14a98 refactor: group native chat text presentation (#34647) 2026-10-27 19:48:24 -07:00
OrcaWinandOrcaWin 5f4d9654f9 ci: run operation-count performance contracts on hosted runners (#34668)
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>
2026-10-27 19:44:37 -07:00
OrcaWinandOrcaWin 1df26abf60 ci(adhoc): package Mac architectures on 6-vCPU runners (#34673)
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>
2026-10-27 19:44:18 -07:00
OrcaWinandOrcaWin 261eb660e3 ci(mac): fail the packaging step when overlapped notarization throws (#34658)
electron-builder's temp-file cleanup registers async-exit-hook, whose
beforeExit handler calls process.exit(0). The overlap script reported
failures through process.exitCode, so a thrown build exited 0: the
retry wrapper logged success and skipped its second attempt (hourly run
40608643418). Exit explicitly instead, as electron-builder's own CLI
guards against the same hook.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 19:44:14 -07:00
OrcaWinandOrcaWin e0f32dcac1 ci: seed hosted Linux packaging and mobile bundle caches on main, and stop PR-local saves (#34672)
- Warm electron-builder-linux-<versions> and the hosted ubuntu-24.04 Electron native modules
- PRs restore hosted Linux Electron native modules without saving
- Replace mobile verify's bundler-cache with a restore of a warmup-saved bundle
- Drop the pnpm store cache where a direct install was faster (mobile main, glibc-floor containers)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 19:40:29 -07:00
OrcaWinandOrcaWin 4cd62c4946 ci: split the layout oracle window scenarios across two shards (#34671)
The single-file oracle cannot be split by whole-file balancing, so pass
Playwright test-level shards to the changed-spec lane. It was the last
required check in 40 of 42 measured runs.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 19:25:17 -07:00
OrcaWinandOrcaWin e1838023cc test: remove 70 low-value test cases (#34665)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 19:25:02 -07:00
OrcaWinandm4air 6ee27ef60e test(wsl): prove Codex and Grok chat inside the distro in the real-WSL lane (#34620)
Scripted guest codex (app-server) and grok (ACP) fixtures, installed on the
guest login PATH beside claude. orcad streams a partial reply, asks for an
approval and takes Stop for each; the lane checks the guest wrapper ran the
fixture with the guest runtime, and that Windows-side codex/grok decoys on
WSL's appended PATH never ran.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-27 19:22:01 -07:00
OrcaWinandOrcaWin 1f5939dffc ci: run relay integration on a free hosted runner (#34666)
It finishes in ~1.2 min beside ~7 min unit shards, so Blacksmith minutes buy no wall time.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 19:21:13 -07:00
OrcaWinandOrcaWin e5f1eef466 test(sqlite): keep node-next-compat green on Node 26.12 (#34661)
Node 26.12 bundles SQLite 3.54, which rejects ALTER TABLE ADD COLUMN for
rowid aliases; rebuild the shadowing table with CREATE TABLE instead.

Node 26.10 binds explicit undefined as NULL. The deleted test only pinned
node:sqlite's own validation (a parity guard for the removed Bun adapter);
SqliteBindings already rejects undefined at compile time.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 19:19:17 -07:00
Neil 6dab169f72 test(orcad): wait on the launcher stub's own markers instead of 5 s windows (#34656)
Each lifecycle step now resolves when the stub prints its marker (ready,
booting:, runtime-exit:N) or rejects with diagnostics when the launcher's
output closes first, so a slow macOS Intel runner only makes a step later.
2026-10-27 19:15:23 -07:00
Neil 2893d06533 test(native-chat): name the stalled step in the live-history watcher test (#34663)
* test(native-chat): name the stalled step in the live-history watcher test

A CI run hit the 30 s test timeout with no step named. Each wait now has its
own 8 s deadline that reports the stalled step with what the watcher had
delivered, and the file sets IS_REACT_ACT_ENVIRONMENT so act() flushes.

* test(native-chat): share one 27 s budget across the live-history waits

Per-step 8 s deadlines were stricter than the old 30 s test timeout; a shared
deadline keeps the total unchanged and only improves the failure message.

* test(native-chat): use an AbortSignal budget instead of the wall clock

Date.now trips the flaky-test wall-clock rule; AbortSignal.timeout gives the
same shared 27 s budget without reading the clock.
2026-10-27 19:13:52 -07:00
ef6e661449 fix(runtime): accept Muse's composer when the voice-input label is absent (#25695)
* fix(runtime): accept Muse's composer when the voice-input label is absent

Muse labels its composer's top rule "Voice input" only where voice is
available, so on Linux the readiness predicate never matched and
worker-start timed out at agent_readiness. Keep the voice-label match and
also accept the composer itself: a rule (two or more rule chars) directly
before the prompt glyph after the latest Muse banner, so a shell prompt like
'~/app ❯' or '╰─❯' under a printed banner is still not ready.

Fixes #25005

Co-authored-by: j33pia <242526320+j33pia@users.noreply.github.com>
Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance>

* fix(runtime): escape Muse composer regex so the orcad bundle stays ASCII

---------

Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: j33pia <242526320+j33pia@users.noreply.github.com>
Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance>
2026-10-27 19:12:13 -07:00
Neil 4fe3d7624b test(pty): scope the group-reap test's ps to its own PTY (#34669)
* test(pty): scope the group-reap test's ps to its own PTY

The helper listed every host process with full command lines, which
overflows execFileSync's 1MB buffer on busy machines (ENOBUFS). Discover
the tagged job on the test PTY's terminal and recheck survivors by their
captured pids, so the output stays small by construction and a job that
lost the hung-up terminal is still caught.

Refs #34410

* test(pty): clean up a job that discovery never captured

Refs #34410
2026-10-27 19:07:07 -07:00
Neil 61337dfb33 chore(ratchet): gate event-loop-blocking calls in the daemon, PTY and orcad code (#34614)
* fix(daemon): read the PTY process table without blocking on terminal kill and resize

The terminal daemon force-killed a session by running ps and reading
/proc/<pid>/stat synchronously, and checked the resize foreground group
with execFileSync('ps'). A slow or wedged ps froze every terminal the
daemon serves for up to the ps timeout on each call.

Both paths now use the async process-table read (runProcess with a
timeout that kills the child). SubprocessHandle.forceKill may return a
promise; the termination controller awaits it so a refused signal still
releases the claim for a retry. A force-kill or SIGWINCH whose root
exits while ps runs signals nothing, since the captured groups could
already be recycled. ConPTY force-kill stays synchronous so dispose()
still sees the node-pty kill it must not repeat. The in-process
provider's app-quit sweep keeps the blocking variant. The ps dialect
and table readers move to posix-pty-process-table.ts.

Refs #34410
Refs #33870

* fix(daemon): address review on async PTY process-table reads

Guard only the root-pid fallback on exit so proven groups are still swept
after dispose, wait out at most one ps dialect probe, move the sync-launch
baseline entry with the table reader, and keep tests cross-platform.

Refs #34410
Refs #33870

* fix(daemon): keep the PTY open until an in-flight force-kill sweep finishes

A sweep whose root exits mid-read must not signal: the freed TTY may
belong to another terminal. Dispose therefore defers destroy() until the
sweep settles, so its hangup cannot end the root first.

Refs #34410
Refs #33870

* test(daemon): build the destroy-tracking PTY mock without a type assertion

Refs #34410
Refs #33870

* fix(pty): make the local graceful-deadline force-kill async and stub ps in tests

The in-process provider's graceful-deadline timer now uses the async
group sweep; the app-quit sweep and the root-signal path stay
synchronous. Tests that drove force-kill through fixture pids now stub
the async process-table read instead of querying the host, and a new
test pins that waiters do not chain behind a failed dialect probe.
Session ids are only read for rows on the root's terminal.

Refs #34410
Refs #33870

* fix(pty): hold PTY teardown until an in-flight force-kill sweep settles

Orphan cleanup could destroy a local PTY while the graceful-deadline
sweep was still reading the process table, neutralizing its fallback
kill and hanging up the root first. Both the daemon handle and the
local provider now defer teardown through PendingPtyGroupSweep.

Concurrent force-kill callers in the daemon now await the shared
in-flight request, so a joiner's physical-exit budget starts after the
signals are sent and it sees their rejection.

Refs #34410
Refs #33870

* fix(pty): let disposal and orphan cleanup join the in-flight force-kill sweep

Session disposal now joins the controller's shared force-kill request
instead of starting a second sweep. Local orphan cleanup decides its
escalation only after a pending graceful-deadline sweep settles, so a
refused sweep is escalated before the handle is released rather than
leaving the retry with a neutralized kill.

Refs #34410
Refs #33870

* fix(daemon): SIGKILL live PTY groups before a shutdown deadline exit

The old synchronous sweep sent its signals before the shutdown deadline
timer could run; the async sweep can still be reading the process table
when it fires. The deadline now SIGKILLs each live session's process
group synchronously before exiting (node-pty roots lead their own
group), falling back to the root pid when the group kill is refused.
POSIX only.

Refs #34410
Refs #33870

* chore(ratchet): gate event-loop-blocking calls in the daemon, PTY and orcad code

The terminal daemon and orcad serve every pane from one event loop, so a
synchronous child launch or file write there freezes all of them. A new
count ratchet tracks execFileSync/spawnSync/execSync, runProcessSync,
appendFileSync and writeSync per file under src/main/daemon,
src/main/pty, src/main/runtime and src/main/orcad; counts may only go
down. It reuses the sync-spawn ratchet's import-aware call collector,
now extracted to gated-call-use-collector.mjs, so aliases, namespace
imports and re-exports count and same-named methods on other objects
do not.

Refs #34410
Refs #33870
2026-10-27 19:05:34 -07:00