* fix(runtime): re-list a repo's worktrees when repo.update changes visibility
`orca repo set --external-worktree-visibility show` (and any other repo.update
client) only emitted repos:changed, so the host renderer kept stale
`visible: false` worktree rows and the newly shown worktree vanished from the
sidebar. The settings controller now also emits worktrees:changed for the repo
when a visibility input changes, without invalidating cached Git scans.
Fixes#32764
Co-authored-by: Younghwan Chae <chyohw97@gmail.com>
* fix(runtime): declare notifyWorktreesChanged on RuntimeConstructionServices
The repository settings controller is built in OrcaRuntimeWithPreservedBranchCleanup,
but notifyWorktreesChanged is implemented further down the chain in
OrcaRuntimeWithGetStatus, so the base class needs the abstract member to typecheck.
---------
Co-authored-by: Neil <neil@stably.ai>
* fix(i18n): give each reused localization key its own sentence
Thirteen keys were shared by call sites that say different things. The
catalog holds one value per key, so the second site rendered the first
site's text: "Move X left" on the right-move button, "Use X repo color"
on the icon picker, "lines above" on the expand-below control, "Open X
issues" on the open-in-Linear action, and similar for status icons,
reclaimable workspaces, remote uploads, automation destination notices,
the add-project button and MiniMax credential errors.
Split every divergent site onto its own key with translations in all
locales, sync the runtime-required catalog, and make
verify-localization-catalog reject a key reused with different fallback
text so the collision cannot come back.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(i18n): pluralize the remote upload toast with i18next count
The toast passed an English "s" as {{value1}}, so ja/ko/zh rendered
"ファイルs", "파일s" and "文件s". The catalog gate requires every locale to
keep the source placeholders, so dropping {{value1}} per locale is not an
option; use count plurals (_one/_other) like nativeDropTempCopyFailed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs: add one-line docstrings to the functions this change touches
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(i18n): reject reused fallback keys before --fix writes en.json
A missing key used with two different fallback sentences had its first
sentence written to en.json before the reused-fallback check failed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): translate the main-process startup and recovery dialogs
The GPU safe-graphics prompts, the profile-state recovery and write-failure
dialogs, the startup failure box and the local-build switch built their copy
from English literals, so they stayed English in every UI language. They now
read it through translateMain(), with entries in all six catalogs.
The GPU prompts built their options once at import; they now build them when
the dialog opens, so the language active at that moment applies.
Some of these dialogs can open before main i18n finishes initializing. Until
then translateMain() returned its fallback with {{placeholders}} unfilled; it
now fills them from the options, so the pre-init English copy stays correct.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(i18n): keep main-i18n out of the profile-state dialog's Bun test graph
The profile-state recovery dialogs imported translateMain directly. Their unit test runs in the Bun node-server suite, so that import pulled main-i18n, Electron's app and the renderer locale catalogs into the node-server build graph. config/scripts/node-server-change-scope.test.mjs forbids renderer files there, and the Bun build also failed on the duplicate "sessionNotRestored" key the es/fr/ja/ko/zh catalogs already carry.
The dialogs now take the translator as a dependency, like showMessageBox. src/main/index.ts passes translateMain; the dialog test passes an English translator that fills the {{time}} placeholder the way translateMain does before i18n loads.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(i18n): read fallback placeholders by index instead of Reflect.get
anti-slop's no-reflect-get flags the placeholder lookup in interpolateFallback. i18next's TOptions already carries a string index signature, so a typed `options[name]` read into `unknown` replaces Reflect.get with the same behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(i18n): finish localizing the main-process recovery dialogs
- Translate the profile repair dialog main added (chooseProfileStateRepair),
including its section labels; CLI and log callers keep English labels.
- Use liveTerminals_one/_other plural keys for the local-build terminal count.
- Retranslate the recovery-not-applied title after main changed its copy.
- Add pt catalog entries for every new key.
- Keep only the pre-init interpolation test; drop the test that pinned
Spanish catalog strings.
Co-authored-by: outof-place <contact@outofplace.space>
* fix(i18n): keep en-runtime-required.json to main plus the new plural keys
* fix(i18n): localize startup dialogs that fire before settings load
Profile-state recovery, preflight failure and recovery-not-applied dialogs
can show before the settings store sets the main UI language. Resolve the
system language first so they no longer fall back to English.
* fix(i18n): keep the uncached pre-ready language read inside the guarded lookup
* fix(i18n): keep the macOS/Windows preflight failure exit synchronous
---------
Co-authored-by: outof-place <contact@outofplace.space>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Hosted macos-15 fails afterPack's packaged x64 terminal host boot check
(hourly run 40608643418: timed out waiting for the PTY), so no
latest-mac.yml is published. Windows, template qualification and routing
jobs stay on hosted runners.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
* ci: narrow native, launcher and packaging cache keys and stop PR-local saves
* ci: hash Rust crate sources, not build outputs, in launcher and hook keys
* ci: fail closed on unlocked native packages and cover transitive key inputs
* ci: resolve the Windows Rust cache scope with a script, not a nested local action
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): render revised UI copy and fail on fallback drift
en.json kept stale values for 47 translate() keys whose source fallback was
rewritten, so the revised copy never rendered in any language.
- Adopt the newer source copy into en.json and retranslate zh/ko/ja/es/fr/pt.
- Move copy whose meaning changed to new keys (artifacts sign-in, remote host
access link / name, ssh config picker, jump palette automation label, Claude
subagent navigation hint) so stale translations cannot survive.
- Split five keys shared by different sentences at the sites the extractor
flagged (activity group-by, automation destination notices, Linear open
action, workspace options label).
- Fix catalog/source mistakes: onboarding "notify you know" typo, crash report
double dot and missing space, mobile search keyword "app", remote server
restart warning repeating "live tabs", and stale source fallbacks where the
catalog was right (Ghostty import, Skills button, too-many-changes banner,
card style and chat UI descriptions).
- verify-localization-extraction now fails on fallback drift and prints the
en.json and source values with how to fix it.
Closes#25572
* fix(i18n): translate es live tab/pane counts used in server restart warning
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Retained sidebar rows were unconditionally inert, so an idle agent whose
live status was dropped could not be navigated to even though its terminal
was still running. Gate activation on the runtime PTY map for the exact
stable leaf (stablePaneHasLivePty) so sleeping panes, whose layout bindings
survive sleep, stay inert and are never resumed implicitly.
Fixes#20803
Co-authored-by: Neil <neil@stably.ai>
* fix(i18n): select whole count sentences at twelve more call sites
Twelve strings were a noun plus a plural ending passed as an
interpolation value, so every non-English locale got a Latin "s" glued
to its own noun whenever the count was not one. Each call site now
chooses between two whole sentences with a single {{count}}, the same
Singular/Plural pattern #27907 uses for three Settings strings.
ja, ko and zh drop the stray ending. es and fr keep what they rendered
for one and get grammatical plural sentences. The "commits ahead"
tooltip in the compare summary takes the wording the catalogs already
have for the identical sentence, because three translations treated the
ending as an object. Legacy keys stay in the catalogs.
Fixes#27973
* fix(i18n): name commits in Korean in the compare-summary tooltip
The Korean pair for the "commits ahead" tooltip was copied from
compareBaseCommitsAheadOne/Other, which keep the English "commit" and
"commits". Both sentences now say 커밋 with the 개 counter, the form
#27907 uses for its Korean count sentences, so the tooltip no longer
carries an English plural.
The locale test also requires ja, ko and zh to use one sentence for
both counts. It fails on the previous Korean pair.
* fix(i18n): take the Korean count sentences from the audit review
Eleven of the twelve Korean pairs still put the number before the noun
with no counter ("3 라벨"), the order left over from dropping the
English plural ending. They now read noun, number, counter
("라벨 3개", "멤버 3명"), the wording abruption supplied in review of
#27974. The "commits ahead" pair already had that form and is unchanged.
Three sentences are also reworded to follow the English: a failed
discard no longer says the files could not be deleted, the group toast
says how many of the contained projects remained, and "restricted key"
is spelled out as an API key with restricted access.
The 22 values are recorded in locale-ko-key-overrides.json, next to the
other reviewed Korean strings.
* chore(i18n): credit the Korean count sentences to their reviewer
The Korean wording applied in f6bbcaf341 was supplied by abruption as a
patch in review of #27974 and went in byte for byte. That commit could
not carry a co-author trailer, so this empty one does.
Co-authored-by: YEONGUK LEE <contact@abruption.dev>
* fix(i18n): drop the twelve keys the count sentences replaced
No call site reads the twelve noun-plus-ending keys any more, so they
leave the six catalogs, as #28185 did for the keys it replaced. With
them go the three Korean override entries for those keys and the one
value ko-ui-semantic-mistranslations.test.ts pinned for the old
sshImportSynced text; the sentence it guarded is now the
sshImportSyncedSingular/Plural pair, covered by
count-sentence-locales.test.ts. en-runtime-required.json is
regenerated.
* fix(i18n): give remote drop uploads their own count keys; drop low-value tests
- Remote terminal drop uploads used the runtime keys with a different
fallback ('to remote…'); split them into uploadingFileToRemote{Singular,Plural}
with translations in all catalogs.
- Remove mock-translate tests and the catalog-pinning count-sentence test;
verify:localization-* already enforces key and placeholder parity.
- Trim the 'why whole sentences' comments.
- Regenerate en-runtime-required.json.
* fix(i18n): natural zh/ja count strings and es host-import wording
---------
Co-authored-by: YEONGUK LEE <contact@abruption.dev>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): translate 229 missing Simplified Chinese UI strings
Complete the zh-CN catalog for recently added surfaces: browser
history, agent permission settings, worktree/workspace management,
cookie import toasts, SSH host server dialogs and source-control
dropdown states. Terminology follows the existing catalog.
11 status-bar credit/balance keys stay untranslated on purpose:
provider-credit-balance-locales.test.ts keeps target catalogs sparse
and interpolates English copy at runtime.
Fixes#34439
* fix(i18n): translate remaining Simplified Chinese strings and unify workspace sleep wording
Add zh translations for the 83 English keys added since this branch was
cut (browser extensions, experimental pane, blocked-page load failure),
leaving the sparse status-bar balance keys untranslated as required.
Use 休眠 consistently for workspace sleep in the sidebar and terminal
close dialog.
* i18n(zh): translate WSL Windows-drive refusal strings
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Shared remote dropdown builders take count/force-push sentence builders
through RemoteDropdownCopy; English defaults keep mobile and older callers
byte-identical. Desktop uses whole-sentence {{count}} plural keys, also for
the primary action tooltip. Refs #34144.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): localize keyboard shortcut titles, groups, and filters
Shortcut action titles and group names came straight from the English
keybinding registry, so the Shortcuts pane, settings search, conflict
warnings, and the terminal shortcut capture toast stayed English in
every locale. The Status filter labels were also hardcoded.
Add a renderer-side copy map with literal translate() keys that
`satisfies` every static action id, one {{agent}} template for agent
tab titles, and a group map. Localized definitions keep the English
title and group as search keywords so English queries still match.
Plugin titles pass through unchanged, and the plugin keybinding consent
preview keeps English registry titles so language packs cannot relabel
the actions a plugin shadows.
Translate the new strings for zh, ja, ko, es, fr, and pt.
* test(i18n): assert shortcut localization behavior without pinning catalog strings
* style: format keybinding title copy test
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
GitHub issue close/reopen swallowed every gh failure mentioning "already"
(e.g. "API rate limit already exceeded"), and GitLab MR close/reopen did the
same for glab. gh exits 0 when the issue is already in the target state, so
every gh failure is now reported. For glab, only its fixed no-op refusals
("this merge request has been closed" / "this merge request is already open")
count as success; "has already been merged" and all other errors surface.
Fixes#28766
Co-authored-by: Neil <neil@stably.ai>
* fix(i18n): interpolate the settings-search empty-state query
The empty state rendered three sibling JSX nodes: a translated prefix
`No settings found for "`, the raw query, then a translated closing `"`.
English reads correctly only because English puts the quoted term after
the verb. Korean and Chinese put it before, so translators given the
leading fragment in isolation localized it as a complete clause and the
query was concatenated after the sentence had already ended:
ko: "에 대한 설정을 찾을 수 없습니다.screen reader"
zh: 找不到“的设置screen reader”
No value for the prefix key can fix this. A fixed prefix/suffix split
hard-codes one word order into the code, and the position where a
language needs the interpolated value is exactly what differs between
languages — so any single split is wrong for some locale by
construction. The message has to be one string with a placeholder, which
moves the decision of where the query goes from the JSX into each
locale's catalog entry.
Replace the fragments with one `{{value0}}` message under a new key.
The old keys are retired rather than reused: their translations are
clause fragments and would be wrong under the new shape. Korean and
Chinese get the natural order; es/fr/ja reassemble their own existing
fragments around the placeholder. ko/zh are also pinned in the
cross-locale key overrides next to the existing precedent for this same
fragment-concatenation class, so a catalog regeneration cannot
reintroduce the clause form.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(i18n): drop assertions the expected-message table already makes
Three of the file's assertions restated what the per-locale exact-match
table proves on its own, and one setup step was dead:
- "carries the query placeholder in every locale" — an exact match on the
rendered sentence cannot pass if a catalog value lost `{{value0}}`,
since the query would be missing from the output. Its `undefined` skip
branch was also unreachable: the catalogs it iterates are the same six
the table covers.
- "closes the ko/zh clause after the query" — `toBe` on the full string
already fixes where the clause sits relative to the query.
- `beforeEach(changeLanguage('en'))` — the remaining table test sets its
own language per case, and the catalog test reads the JSON directly and
never consults i18n.
Verified by mutation rather than assumed. Each of these makes the
trimmed file fail, so nothing the deleted assertions guarded is now
unguarded:
ko value loses {{value0}} 1 failed / 6 passed
es value loses {{value0}} 1 failed / 6 passed
ko puts the clause before the query 1 failed / 6 passed
zh ends with the query 1 failed / 6 passed
a retired fragment key returns in ja 1 failed / 6 passed
Clean: 7 passed. With the rest of the change reverted to main and this
file kept: 6 failed / 1 passed. The docblock keeps the reason the shape
changed and loses the retelling of it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): use whole count sentences instead of appending English 's' in JSX
* fix(i18n): drop unrelated reformatting in McpConfigSection
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* 한국어 비활성 상태 라벨을 문맥에 맞게 수정
사용량 통계의 비활성 상태는 비활성으로, 터미널 색상 대비의 Off 옵션은 끔으로 수정했습니다. 활성 상태의 기존 활성화됨 표현은 유지했습니다.
번역 재생성 시에도 두 표현이 유지되도록 한국어 키별 보정 설정에 반영했습니다.
* fix(i18n): pair Korean usage badge enabled label with 비활성
* fix(i18n): translate remaining Korean runtime RPC startup failure strings
Carried over from #14044.
Co-authored-by: JeongSu <zz1996zz@naver.com>
---------
Co-authored-by: Willy <willy@Willy-MacBookPro.local>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: JeongSu <zz1996zz@naver.com>
Correct 22 Korean labels to match the workspace or worktree named by
their English source. Pin the same values in the Korean key overrides
and cover catalog values and repair-policy stability with regression tests.
Fixes#11727
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* Fix default agent action sizing for translated labels
* fix(i18n): drop unused default-agent label and locale-leaking fixture
Remove the now-unused 'Set default' key from all catalogs, drop the
AgentCatalogRow fixture that switched the shared UI language, and keep
main's en-runtime-required.json since the layout change needs no entries.
* fix(settings): keep agent availability toggles aligned when default button is hidden
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* feat(plugins): allow language packs to declare a native display name
Plugin language packs can set contributes.languagePacks[].displayName so
the Settings language picker shows 中文(繁體) instead of
`zh-TW — pluginKey`. Omitted names keep the previous fallback label.
Fixes#13031
* refactor(plugins): inline language-pack picker label and guard displayName
Inline the one-line picker label fallback, type-check displayName in the
registration guard, drop issue refs from comments, and trim tests.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Its three parallel real-Git lanes, two of them through Docker, push
git-binary-compatibility.test.ts past the 30s test timeout on the 4-vCPU
hosted runner (64s file time vs 14s), failing PR #34600 twice after #34566.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Production liveness publishes distro-stopped when a stopped distro loses its
bridge; the e2e fake published closed. An explicit disconnect still reports
closed.
* perf(wsl): stop the idle profile-state writer thread on WSL hosts
The writer thread holds ~13-15 MB while orcad sits idle. On WSL hosts the
authority now closes it after a minute without a command and reopens it,
at the last acknowledged revision, for the next one (~22 ms). The desktop
and SSH hosts keep the always-on writer. Also covers an empty and a
misnamed keep-existing launch value.
* perf(wsl): count and log idle profile writer reopens
Writes arriving just over the idle window apart would churn the writer
thread unnoticed. Each reopen now counts, with one log line per ten
minutes so the field shows it.
* fix(wsl): retry a failed idle writer reopen instead of wedging saving
A failed reopen (spawn failure, thread exit, EMFILE) left the faulted
writer in place, so every later write was refused until orcad restarted.
A non-conflict initialize failure now rejects that one command and puts
the authority back in the stopped state; the next command retries at
once, repeated failures back off up to a minute, and a revision conflict
stays terminal. Abort no longer waits a tick when nothing is stopping.
* fix(wsl): let the final flush through a reopen backoff and report only terminal reopen failures
A final or maintenance flush now gets one reopen attempt even inside a
backoff, so shutdown never drops state for a transient spawn failure. A
retriable reopen failure is logged as a warning naming the retry delay
instead of reporting that saving has stopped; only a revision conflict
reaches onFailure.
* test(wsl): prove an unset idle stop arms no timer instead of sleeping
The no-option case waited in real time to show the writer stayed open.
With no idle timer armed nothing can close it later, so assert that
directly.
* fix(native-chat): list OMP skills in the / menu as /skill:<name>
* test(native-chat): OMP now carries the Pi-shaped skill profile
* Publish native OMP skills with compatible command catalogs
* Index native skill descriptions once per picker build
* Combine catalog test composer imports
* Correct native catalog test types and project inputs
* Run cross-platform picker scaling contract with mobile tests
* fix: discover native commands before the first chat message
* test: isolate native command discovery from mobile typechecking
* fix: release command discovery ownership after managed root exit
* refactor: reuse the ACP child owner during shutdown drain
* test(acp): load filesystem implementation before test execution
* test: drive discovery close completion explicitly
* test: await discovery admission cleanup between demand waves
* test: control discovery close ordering in demand waves
---------
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* fix(i18n): localize GitHub project view errors and states
Main now tags Orca-authored project-view failures with an optional
reason code plus host, rate-limit numbers and diagnostic detail; the
English message is unchanged for mobile, older clients and logs. The
renderer maps type/reason to translated copy in the error state, picker,
item dialog and mutation toasts, falling back to the English message for
older hosts and GitHub's own text. Also wraps the layout labels,
unsupported-layout, not-found/too-large copy, picker partial-failure
summaries and the gh sign-in help.
Closes#34589
* test: expect input_too_large reason on oversized project refs
* fix: make project view error copy switches exhaustive
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(skills): force English git messages in copied POSIX skill install commands
skills@1.7.2 falls back to fetching a pinned commit only when git's
clone error is in English, so the npx command Orca shows or copies for
WSL, macOS and Linux failed under translated git (e.g. tr_TR). Prefix
those commands with env LC_ALL=C, matching the earlier in-app fix
(#28994). Native Windows cmd/PowerShell commands are unchanged.
* fix(skills): skip LC_ALL prefix when a remote runtime is focused
A focused remote runtime may be a Windows orcad host where env is unavailable.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): localize the rest of the source control dropdown
The Commit & Push, Push, Force Push, Pull, Fast-forward, Sync, Publish,
abort and Push-before-PR rows and their tooltips were English literals
next to rows that already go through translate(). Route them through
translate(), reusing the primary button's and the conflict card's keys
where the words match, and add 42 keys to the English catalog.
Commit blockers stay English inside eligibility, which compares them,
and are translated only when the dropdown shows them.
* test(i18n): pin the other two commit blockers under the pseudo-locale
The pseudo-locale test only reached the stage-file blocker, so an English
return for the conflict or commit-message blocker still passed. The new
case checks both in the Commit, Commit & Push and Commit & Sync titles.
* i18n: translate source control dropdown keys; trim duplicate pseudo-locale test
Add zh/ko/ja/es/fr/pt translations for the 42 dropdown keys this PR adds to en.json,
matching each catalog's existing source-control glossary. Drop the second pseudo-locale
test; the first already covers commit-blocker titles through the active locale.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
resolveCommand only checks what it resolves, so a file that also builds its
own wsl.exe exec no longer passes the import check on a resolveCommand call
alone. Note editor --remote wsl+<distro> launches as out of scope.
On CI the first keystrokes typed right after the WSL host terminal attached
were sometimes dropped (the shell received "L HOST TERMINAL ..."), leaving an
open quote, so the marker never printed. The spec now waits for the prompt,
which names the project folder, before typing. The dropped input itself is a
separate follow-up.
- git-binary-compatibility: give the docker image runs of the ref-pairing case
a 90 s budget; each Git call is a docker exec and the case normally takes
22-25 s of the 30 s default.
- claude-transcript-catch-up: fire the 5 ms catch-up deadline with fake timers
only after the fallback lookup has started, instead of racing a real timer.
* fix(source-control): read the Kimi answer from stream-json
Kimi Code's text mode prefixes thinking and hook output with a bullet, so the
commit message arrived mixed with narration. The recipe now asks for
--output-format stream-json and the answer is taken from the last assistant
record, which is the commit message (#33556).
A record that requests a tool is narration rather than an answer, so it clears
the candidate: a stream that ends on a tool call yields no answer, which
finalizeFromAgentOutput already treats as a failed run. Only a body whose every
non-empty line is a record counts as stream output, so a plain answer that
happens to contain a JSON line is left alone.
* fix(source-control): decode Kimi output only for the selected protocol
* fix(source-control): satisfy generation hook checks
* Preserve Kimi generation failures and normalize options linearly
* Fix Kimi argument failure messages
* Bound Kimi option failure recognition
* Fix Kimi generation test fixture types
---------
Co-authored-by: beduldul <alkaysan07@gmail.com>
* fix(wsl): refuse Windows drive folders on a WSL host and offer to add them on this computer
A /mnt/<drive> project on a WSL host shows false line-ending changes, misses
edits made from Windows, and searches slowly. Add Project refuses typed,
picked and dropped Windows drive folders for a WSL host and shows the refusal
inline with Add on this computer, which switches the open dialog to this
computer. The WSL-host orcad re-checks by /proc/self/mountinfo (after
resolving symlinks) in repo.add, repo.create, repo.clone, explicit
folderWorkspace.create and the nested scan/import, answering with the
existing runtime_error code plus optional data, so older clients still show a
readable message. Everything is behind the WSL hosts gate; SSH is untouched.
* test(wsl): hold the e2e's this-computer add instead of racing its failure
On the Linux CI host the switched local add of a Windows path fails its nested
scan and hands off to the Open as Folder modal, closing Add Project before the
test looked. The refusal itself already came before any scan. The e2e now
records the local add at its scan step and asserts it went to this computer
with the Windows path; a unit test pins that a refused pick never reaches the
host path step.
* test(wsl): type the e2e's held-scan window hooks instead of Reflect
* fix(plugins): reject locale ids Intl cannot parse
`pluginLocaleIdSchema` checks the shape of a locale id but not its grammar,
and the shape check is looser than BCP 47 in one direction: `en-US-US`
(duplicate region) and `en-aaa` (a subtag that is neither region nor script)
both match it. A pack declaring one installs, loads, and translates every
string — and then `Intl.DateTimeFormat` throws inside `getIntlLocale()`, which
swallows the error and falls back to English. Nothing is logged, so the pack
author sees a working pack with English dates and no way to tell why.
Delegate the grammar to `Intl.getCanonicalLocales` in a `.refine`, so the tag
is rejected at install where the author can still act on it. The bundled
`pt-BR` pack and every other well-formed tag are unaffected.
* Condense this branch's comments to one line
AGENTS.md asks for one-line comments that say why, and main's comment
cleanup (#33249) applied that across the repository. This brings the
comments this branch adds in line with it. No code changes.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* feat(wsl): internal distro allowlist for WSL execs on shared test boxes
ORCA_INTERNAL_WSL_DISTRO_ALLOWLIST (comma-separated distro names) keeps every
wsl.exe call out of distros not on the list: process-host's resolveSpawn,
the main and daemon node-pty spawns, and the two codex-accounts calls that
bypass process-host. Pure list/status/version calls stay allowed; any other
form must name an allowlisted distro, and --shutdown or a default-distro exec
is refused. A malformed value refuses every distro and logs once. Unset, the
check reads the variable and returns, so behavior is identical to today.
* fix(wsl): cover every direct wsl.exe exec with the internal distro allowlist
- Restore #34525's worktree-create payload and captured-host test, reverted by
accident in the first commit.
- Check the allowlist in execFileCapture, the choke point for WSL Git, gh and
worker-thread captures, and before the WSL git-read probe, the Codex hook
path canonicalization and the CLI login spawn. The WSL watcher now spawns
through process-host.
- Stop scanning wsl.exe argv at the first positional argument, which wsl.exe
runs in the default distro.
- check-process-host-imports fails on any direct wsl.exe exec outside
process-host that does not call assertWslDistroAllowed.
* fix(wsl): check the distro allowlist where resolveCommand produces the wsl.exe form
Every Git, gh and glab path into a distro resolves through resolveCommand, so
gitExecFileSync, gitSpawn, git stream reads and wslAwareSpawn are covered too;
the execFileCapture check is now redundant and removed. The import check also
treats buildWslExecArgs as a wsl.exe exec and accepts resolveCommand as covered.
* ci: move secondary, scheduled and contract workflows to GitHub-hosted runners
Public-repo standard hosted runners are free under Enterprise. Release, build,
benchmark, e2e and unit workflows stay on Blacksmith. ci-xterm-cache seeds both
cache stores since its PR consumer's pool is undecided.
* test(pi): resolve the smoke bundle's external packages from the repo
#34148 pulled zod into the commit-message planner graph; the bundle in the
OS temp dir could not resolve it on any runner.
* ci(unit): use four workers on the hosted four-core x64 runner
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(cli): hide unsupported profile-state flags
* fix(cli): derive --page and remote-selector help from what each command takes
--page is now a property the browser spec modules set for commands that act on
one page, rather than offered to every command group not on a deny-list, so
serve, environment, agent, connector, host, vm and profile commands stop
advertising and accepting it. Local-only commands offer only --help and --json
plus a selector they take as their own argument, and a test ties their help to
the same local-only list dispatch uses.
Co-authored-by: William Poisel <53629276+epoisel@users.noreply.github.com>
---------
Co-authored-by: William Poisel <53629276+epoisel@users.noreply.github.com>
Hourly and daily builds publish unvetted dev channels on a schedule, so their
latency is not user-facing. Move the macOS build to hosted macos-15, the
Windows build to hosted windows-2022 (the release path), template
qualification to hosted lanes, and the small routing/publish jobs to
ubuntu-latest. Adhoc and release builds stay on Blacksmith.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
* test(wsl-host): native chat on a WSL host through the fake transport, including a stopped distro
* test(wsl-host): type the chat spec's focus host id
* test(wsl-host): harden the WSL host chat spec and re-run fake-connector specs on change
* test(wsl-host): scope the chat reply check to the transcript and test the fake's route
Find the prompt only in the transcript so the composer can't stand in for it,
re-check the boot-free stop window after unfocusing, right before the focus,
give the fake's distros.json temp file its own name so it can't collide with the
spec's, and test that the fake connector routes to both WSL host specs.
* test(wsl): find the chat lane's claude on the guest PATH, with a Windows-side decoy
* test(wsl): prove the Windows decoy is reachable before asserting it never ran; record probe errors