mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 01:47:24 +00:00
6653bb60fef9707e3052f899f396eaaa150f8249
3977
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
969435e2a4 | Merge remote-tracking branch 'origin/orch-auto-release' into orch-v2-integration | ||
|
|
228f63707e | Merge orch-auto-ack into integration | ||
|
|
49695f37b1 | refactor: group native chat subagent transcript rules (#35200) | ||
|
|
66b2478224 |
fix(managed-server): let the update candidate name the daemon generations an old host cannot (#34908)
Hosts that predate the census protocol set report a null protocol whenever terminals span daemon generations, so a forced update stayed refused there even though the incoming build could reach every daemon. When the census cannot answer, the candidate's profile preflight now lists the daemon generations alive under the data root the server serves, passed to it explicitly, and the planner checks attachability against that list. An uncounted census still refuses, and any generation the probe cannot rule in or out leaves the update unverifiable. |
||
|
|
045f8c8266 |
feat(files): show images and PDFs from the byte-range preview path, local and remote (#35165)
* feat(files): show images and PDFs from the byte-range preview path, local and remote ImageViewer and PdfViewer read an orca-media:// URL instead of base64 when the editor opens a file: images load by URL, and pdf.js reads PDFs by range, so a large PDF no longer arrives whole through files.readPreview or pages into memory first. The grant mints only for the editor's viewers; diffs, git blobs, markdown images and the paired web client keep base64. - Minting an image checks its header with the base64 path's rule, so an image proven too large to decode safely never reaches the decoder. - orca-media gains fetch and CORS privileges, and range responses expose Accept-Ranges and Content-Range, so pdf.js can read by range. - Grants report the file size the viewer used to estimate from base64. * fix(files): read PDFs by real range, check served images, keep old hosts' previews - pdf.js fetches ranges only over http(s), so an orca-media URL was read whole; a small range transport now hands it bytes=a-b reads from the grant, and a failed range fails the preview instead of hanging it. - A file can change after mint, so the raster header is checked again on the bytes each image request serves (the same handle locally). - A paired host without files.readChunk falls back to files.readPreview for images and PDFs, as before; only audio and video need the update. * fix(files): mint no local document grant for a renderer gone mid-mint The local image/PDF mint is async now (authorize, open, header check), so a renderer that closed meanwhile could leave a grant no teardown drops. It binds the renderer lifetime first and refuses to mint once it's gone, as the remote mint does. * fix(files): keep the 50 MB cap for URL images, and probe remote headers incrementally An <img> decodes the whole file, so image grants keep the base64 path's 50 MB cap; PDFs, now read by range, don't need one. A remote header probe reads only each wider step's new bytes instead of re-reading from the start. A replaced image of a different size resets its zoom. * fix(files): tear down a PDF load whose range failed, and read 256 KiB ranges A failed range only showed the error and left the pdf.js task, its worker and pages alive; it now destroys that load first. pdf.js asks for one readChunk-sized range at a time instead of 64 KiB, and a Range preflight gets its CORS answer instead of 405. * fix(files): read PDF ranges over IPC so orca-media needs no fetch or CORS orca-media had gained supportFetchAPI and corsEnabled, and its responses sent Access-Control-Allow-Origin: *, so pdf.js could fetch ranges. That let any default-session frame holding a token read the bytes. pdf.js now reads a PDF grant's ranges through fs:readPreviewRange, which main answers only for the renderer that minted the token. The scheme is back to element-load privileges (standard, secure, stream), responses carry no CORS headers, and preflights get 405. Grant bookkeeping moves to preview-grant-registry.ts. An e2e spec proves an orca-media URL can't be fetched from the app page or read from another session. * ci(e2e): route the byte-range preview sources to the viewer specs that exercise them Changes to the orca-media grant path, the image/PDF viewers and the PDF range transport now run the PDF reload, rebuild and find specs, the remote large-file open, media playback and the partition-isolation spec. * fix(files): stop PDF range reads on abort, abort remote reads with the window, fix the CI route - A closed or reloaded viewer schedules no further pieces of a merged range, and a remote range read stops when its window goes away. - A URL without a size is an error rather than a fetch the scheme refuses. - The PR guard job's sparse checkout and its admission test include the new route module, and the route now also covers the mint handler, preload bridge, editor surfaces, scheme registration and read client. * fix(files): classify linked previews by their target, keep range reads off stopped WSL distros A local image or PDF reached through a link is classified by the file it resolves to, at mint and on every read, and a re-mint after the link is retargeted gets a fresh grant of the new type. A paired host's document whose first bytes are another kind defers to files.readPreview, which classifies the target there. Lazy local reads go through the non-waking WSL guard, as fs:readFile and fs:readFileChunk do. |
||
|
|
74937b50aa | refactor: group native chat transcript retention (#34761) | ||
|
|
6ddcf1d453 |
feat(files): save a remote text file larger than one request (#35073)
* feat(files): save a remote text file larger than one request The editor opened files up to 50 MB from a WSL host or SSH server but refused to save anything over 720 KB. A staged save sends the content in chunks to a temp the host makes beside the target, and the commit replaces the target by rename under the same locks and disk precondition as files.writeIfUnchanged. Bounded per save, connection and host; idle saves are dropped; a journal lets host start remove temps a crash left. Older hosts keep the refusal. Co-Authored-By: Claude <noreply@anthropic.com> * fix(files): stage large remote saves privately and commit them with the one-request save Review of #35073: chunks now go to the profile's private staging folder, the commit re-authorizes the target and writes it in place through writeLocalTextFileWithDiskPrecondition (same locks, precondition and inode as a one-request save), ops on a save run one at a time so an abort or commit never races an append, a closed socket's saves are aborted, and host start clears the staging folder in the background. Co-Authored-By: Claude <noreply@anthropic.com> * fix(files): check a staged save's temp size at commit, and stage per process Review of #35073: the commit refuses a temp whose size on disk isn't the declared total, and each process stages in its own subfolder; the start sweep removes only its own folder and those whose owner has exited, so runtimes sharing a profile never wipe each other's saves. Co-Authored-By: Claude <noreply@anthropic.com> * fix(files): a runtime without staged saves closes a socket cleanly Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
bc80bc59fb |
fix: retire extension iframe event listeners with native frame (#35011)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
b654c3454a |
fix(persistence): stop rewriting migrated Compact profiles on every load (#34736)
The legacy Compact card-property migration returned the Compact preset even when the stored list already was a current Compact preset, so every clean reload of a Compact profile scheduled a full profile write. Treat both the raw ['status'] and the normalized ['status', 'unread'] form (persisted by any UI write) as already migrated. Fixes #34828 Co-authored-by: Neil <neil@stably.ai> |
||
|
|
3fd928373c |
fix(source-control): flag failed git status reads instead of showing a clean workspace (#28079)
When git status failed (e.g. a corrupted index), the read returned an empty result and Source Control said the workspace was clean. getStatus now carries Git's error as an optional readError; the store keeps the last known entries and conflicts while it is set, and the panel shows a status-read banner with Git's message and Retry instead of the clean empty state. The Retry logic is shared with the too-many-changes banner, and the per-worktree error is cleaned up on teardown and migrated on worktree rename. Fixes #28033 Co-authored-by: Neil <neil@stably.ai> |
||
|
|
a7d9a10e4a |
feat(files): page a remote server's big folders in the explorer (#35115)
* feat(files): page a remote server's big folders in the explorer * fix(files): list a remote folder whole unless the host refuses it as too large, then page it * fix(files): page a remote folder after a cursor entry, not at an offset * fix(files): release expired folder listings, share one in-flight listing, keep an oversized one alone * fix(files): cap and time out cached folder listings, bound the cursor name, match id: selectors |
||
|
|
ab512bfe13 |
Show a chat's saved permission mode while its agent isn't reporting (#34546)
Chats with an explicit mode showed a disabled 'Permissions' placeholder whenever no running agent had reported, which is every idle or resumed chat, so the mode could not be read or changed. A live report still wins; chats that follow the agent's own settings still wait for the report. |
||
|
|
daf806bb41 |
fix(wsl-host): refuse Windows-only agent CLIs in phone, resume and fork launches (#35016)
* fix(wsl-host): give phone, resume and fork agent launches the Windows-only refusal * fix(wsl-host): hint the Command setting on required-CLI refusals * fix(wsl-host): refuse explicit resumes of a Windows-only CLI with the fix-it message |
||
|
|
f231d1cde6 |
feat(files): play remote audio and video through one byte-range preview path (#35038)
* feat(media): read remote media ranges through the paired runtime Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(media): stream remote media through orca-media grants Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(editor): play video and audio from remote runtime workspaces Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(media): surface update-required for remote media and cancel in-flight chunks Probe files.readChunk once per environment and pairing revision before minting a grant so older servers show the update message. Closing a media stream now aborts the in-flight remote chunk. Also validate the IPC address, fix extension-only names, and tighten the preview return type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(files): one classifier decides which viewer opens a file Local reads, files.readPreview on hosts, git blob previews and the desktop's remote binary handling each kept their own image/PDF extension table, and media had another. file-preview-kind.ts is now the one table: image, PDF, audio or video, with the MIME type. AVIF, which only local reads knew, previews on hosts and in git diffs too. * perf(runtime): give byte-range reads their own small call lane files.readChunk (media streams, paged files, downloads) now runs in a two-call lane per environment, so a playing video or a download never holds the slots terminal input and workspace calls use. * feat(files): stream previews from paired runtimes by byte range Generalises the remote media grant into one byte-range preview path: an orca-media:// grant keyed by environment, worktree, path and pairing revision, streamed over files.stat/readChunk. Audio and video use it now; the shared classifier decides which viewers do. - One files.stat at mint replaces the readChunk probe: it proves the host serves range reads and that the path is a file, so an old host or a missing file fails in the tab, not as a silent player error. - A burst of range requests shares one stat (reused for 1s), so seeking costs one round trip less on a slow link; later requests re-stat, so a growing recording keeps playing. - Removing a paired runtime revokes its grants; a re-paired one answers 410 and drops the grant. - Only readers that render bytes mint a stream; baseline checks don't. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): prove chunk reads at mint, and let a reload report the new size Hosts from v1.4.5 answer files.stat but only v1.4.111 and later answer files.readChunk, and no capability names it, so minting reads one byte, cached per pairing, and an older host fails in the tab with the update message. A re-mint seeds the grant with its fresh stat, so a reload never reuses an older size. A renderer gone mid-mint mints nothing. Preview chunks time out after 20s so a stalled one frees its lane sooner. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): resolve preview hosts in the pairing registry's own directory The remote preview reader looked environments up under the canonical user-data path, while the pairing IPC writes the registry under app.getPath('userData'), which can differ in casing on case-sensitive installs. Both now use one getter. A chunk-read verdict is cached only when a pairing revision pins it, so it can't outlive a re-pair. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): read the pairing registry from one directory everywhere Doc previews resolved paired servers under the canonical user-data path, the same casing mismatch the media reader had. They and every other main caller that names the registry directory inline now use getRuntimeEnvironmentRegistryRoot(), so it has one source. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): pin an unpinned preview grant to the pairing it was minted on A renderer that hadn't loaded the environment's pairing revision yet sent none, and every later chunk read went unguarded, so a re-pair under the same environment id would let the old URL read from the new host. Main now pins the registered revision at mint. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * refactor(files): route the remaining pairing-registry readers through the one getter AI-vault host scans, the settings runtime-environment preference, skill capability checks and the mobile relay host list named the registry directory inline. They now use getRuntimeEnvironmentRegistryRoot() too; callers that also use the directory for other storage keep their own path. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * refactor(files): write new pairings through the same registry root The ephemeral VM pairing writer named the registry directory inline; it now uses getRuntimeEnvironmentRegistryRoot() like every reader. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> --------- Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f59bd43c46 |
fix(wsl-host): Remove keeps a WSL host's server that another Orca on this computer shares (R39) (#34699)
* fix(wsl-host): Remove keeps a WSL host's server that another Orca on this computer shares A WSL host's server lives in the Linux login's ~/.orca, so two Orca installs on one Windows account (stable and dev), or a desktop reaching the distro over SSH, share one server. Remove used to close every terminal there and decommission it, ending the other desktop's sessions and agents. The server now answers host.peerDesktops (capability orcad.peer-desktops.v1): the other desktops paired with it, whether each is connected now, and when each was last seen. Before tearing anything down, Remove asks. If another desktop is connected or was seen in the last 30 days, it only closes this desktop's bridge and reports the server kept. If the server can't answer, the teardown is refused. An older server without the capability gets today's teardown, plus a warning. * fix(wsl-host): a shared Remove releases this Orca from the host, and says the host keeps running - On a shared server, Remove now revokes this desktop's own device (and its phones) on the host, through the new host.releaseDesktop, before letting go. Otherwise its recent row would make a peer's later Remove keep the server forever. Peers also skip rows of the caller's own installation (same caller fingerprint), such as an enrollment from before a re-add. - The renderer says when a removal kept the host for another Orca, and the Remove confirmation no longer promises to end terminals unconditionally. - Remove-path files now route CI to the fake transport e2e spec, which exercises Remove. * i18n(wsl-host): Russian and Traditional Chinese for the shared-host Remove copy * fix(wsl-host): tell desktops apart by device key, and release this Orca on every Remove - Peers are no longer hidden by caller fingerprint. Every device-key fork of one pairing token row inherits that row's fingerprint, so two installations that paired through one code hid each other, and one's Remove could tear the server down under the other. Only a shared device public key now marks the same installation, as with a re-add under a new token. - This desktop's own device is released as the last call over the bridge on every Remove that proceeds (no terminals left), not only a shared one. A later Add then Remove never meets a stale row of ours. - When the release fails on a shared Remove, the toast says the host may keep running for a while. The Russian confirmation copy is corrected. * fix(wsl-host): move undo refuses a removed host whose server another Orca kept A Remove that kept a WSL host's server for another Orca (R39) now records that. Before, undo of a move onto that host read the missing environment as "its terminals and automations stopped with it", and would have restored the project here while the host's copies kept running, duplicating its agents and automations. Undo now reads such a host as unreachable and refuses, as it does for any host it can't reach. A later Remove that proves the server stopped clears the record. If the record can't be saved, the host stays listed as pending instead. * i18n(wsl-host): Turkish for the shared-host Remove copy * fix(wsl-host): each WSL desktop splits off its own row from orcad's startup pairing orcad publishes one startup pairing offer and never rotates it, so every desktop that enrolled through it shared one token row and device id. Stable and dev Orca on one distro were invisible to each other as peers, and releasing that shared row broke the next re-add and pairing repair. - New host.forkDesktop (same orcad.peer-desktops.v1 capability). A runtime device on a shared desktop token mints its own token row, forked from it and named by the caller. Forks share the device-key fork cap, and a released fork frees its slot. - The WSL desktop forks right after enrolling through the startup offer, or after a repair lands back on it, and keeps the forked pairing (named after its userData folder, e.g. Orca or Orca Dev). On an older orcad, or if the fork fails, it keeps the shared pairing and warns. - A token row that desktops forked from counts as a peer only while something is connected on it. One that nobody forked from keeps the last-seen rule. * fix(wsl-host): keep host.forkDesktop to the startup offer's holder, over E2EE, with a clean label host.forkDesktop mints a credential, so: - only the holder of the desktop pairing offer this server advertised last (orcad's startup offer) may fork; an older offer, a fork, a phone or any other row is refused; - the fork takes exactly the caller's grants and reach; params are just a label (strict, so a grant request is refused); - it runs only on an authenticated E2EE socket; the token goes back only in that reply and is never logged; - the label is display-only: control, zero-width and bidi characters stripped, whitespace collapsed, at most 64 characters; an empty result is refused. * refactor(wsl-host): count only Orcas connected right now as WSL host peers; drop fork and release Review found the token fork and self-release add more identity state than R39 warrants: orphan forks, a desktop left on the shared token releasing it, and a changed caller fingerprint. So this drops host.forkDesktop, host.releaseDesktop and the 30-day last-seen rule, and restores the restart test. A peer is now another Orca installation with a control socket open on the server right now. The desktop declares its installation (a hash of its userData path) with host.declareClient on its shared-control socket after every ready, including reconnects. The server tags that socket and drops the tag when it closes. host.peerDesktops takes the caller's installation id, so its own other sockets (multiplex, one-shot) never count, and two desktops sharing one startup token stay distinct. Undeclared sockets, phones and browser sessions are ignored. Peer names go through sanitizeDeviceLabel, and a startup-offer "CLI <date>" name shows as "another Orca". An older orcad lacks the method: nothing is declared, and Remove keeps today's teardown with a warning. Limit: an Orca that's closed while its terminals keep running isn't protected. * fix(wsl-host): keep a reconnecting Orca as a WSL host peer for 60 seconds Lost contact isn't proof an Orca left. When an installation's last declared control socket closes (a bridge exit, an orcad restart, resume from sleep, reconnect backoff), the server keeps counting it as a peer for 60 seconds, or until it re-declares. A Remove inside that gap no longer tears down its terminals. * fix(wsl-host): say an open Orca keeps the host, and name each peer once - The Remove confirmation now reads "Unless another Orca that's open on this computer is using it", since only a connected Orca keeps the server. Updated in all 10 locales. - The kept-host toast dedupes peer names, so several unnamed peers read "another Orca" once. * test(wsl-host): pin the reconnect grace to the last socket's close, and to the server's own forget - The unit test advances the clock between the two closes and checks that the peer still counts when the first close's grace would have run out. - The integration test waits until the server has dropped the closed socket before reading peers, so it fails without the grace (checked by setting the grace to zero). * fix(wsl-host): sweep expired reconnect graces on every close, on a monotonic clock Expired graces are dropped at the start of forget() as well as peers(), so the map stays bounded even when nobody asks for peers. The default clock is performance.now(), so a wall-clock jump can't stretch or cut the grace. * i18n(wsl-host): German for the shared-host Remove copy |
||
|
|
0b6071aec4 |
fix(wsl-host): tell users how to fix a distro Orca can't host (D1c-1) (#33085)
* fix(wsl-host): tell users how to fix a distro Orca can't host With the WSL bridge going away there is no fallback for a distro Orca's server can't run in, so each refusal now names the step that fixes it: - WSL 1: the wsl --set-version command, also shown in the Add host form, where the disabled option could never show it. - An unregistered distro, at Add and at connect: how to list installed distros. - NixOS's stub loader: turn on nix-ld. - glibc below every runtime's floor: the minimum release to use. - A WSL distro with an unknown platform no longer reads as "this SSH host". Connect refusals other than WSL 1 report as 'unsupported-distro' instead of reusing 'unsupported-wsl1'. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): show only the plain message when a WSL host can't connect or be added * test(wsl-host): fold the plain-message case into the existing readIpcErrorDetail tests * fix(wsl-host): keep SSH's old-glibc and NixOS refusals as they were; add the fix only for a WSL distro The glibc and nix-ld hints were appended in code SSH hosts share, so SSH users saw new wording with the WSL hosts gate closed. The shared messages are back to main's text; the WSL add flow adds the fix to its own refusal. (cherry picked from commit c7a07b61c440e87652ca956570b8b91492c2a375) * refactor(wsl): map a missing distro in the unsupported-distro module, keeping orcad deploy under its line cap --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
9e1443ecf2 |
fix(wsl-move): undo connects the WSL host after a relaunch, and startup heals a crash mid-pairing save (#33279)
* fix(wsl-move): undo connects the WSL host after a relaunch, and startup heals a crash mid-pairing save Undo is the user's act, so it connects the host the way Connect would before asking it anything; without that, a relaunched host with no open work refused every undo as unreachable. A crash between refreshWslHostPairing's two writes leaves the record's bridge port off the saved pairing, and the overlay then drops the WSL link. Startup realigns the record to the pairing. Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-hosts): startup realigns bridge ports before any bridge connects, and not while gated off Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-move): undo's terminal stop never connects a host whose Remove is pending Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
fe3eb45b85 |
feat(i18n): add German UI language (#34917)
* feat(i18n): add German UI language Register German (de) as a built-in UI language alongside en, zh, zh-Hant, ko, ja, es, fr, pt, ru and tr: language setting, system-locale detection (de, de-DE, de-AT, de-CH, de_DE.UTF-8), renderer and main-process lazy catalogs, Settings picker label in every catalog, the "Sprache" settings search keyword, onboarding picker, docs and a German glossary and style guide (config/i18n-german.md). de.json covers every en.json key except the sparse-policy entries that must fall back to English (status-bar credit balance copy and the incomplete goal change notice). Tests that used de-DE as the unsupported system language now use it-IT. The catalog is machine-translated, reviewed by two independent passes with arbitrated fixes, and swept for terminology consistency. * feat(i18n): translate German strings added on main Translate the 158 keys main added since the branch point (WSL project move, diff size limits and others), reviewed by two passes like the rest of the catalog, and drop the 5 keys main retired. --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
8377149070 |
Preserve terminal exit queries across snapshot restore (#34723)
* fix(terminal): preserve Codex exit queries across snapshot restore * fix(terminal): replay owed queries from discarded output and superseded replays - Mark yielded queries discarded when ACK overflow trimming, the recovery cutoff, or snapshot-buffer overflow drops their output unsent, and replay them after the covering snapshot (including the ACK recovery snapshot). - Purge snapshot query replays and escape-tail frames still queued behind the ACK window when a newer snapshot is published, and put new replays at the head of the ACK queue so they follow their snapshot. - Share isPrimaryDeviceAttributesQuerySequence across DA1 call sites. - Move replayed-query settlement into settleReplayedYieldedQuery. * fix(terminal): replay DA1 still batched when an ACK recovery snapshot covers it * test(terminal): type the overflowed initial-snapshot stream fixture * test(terminal): give the host-chain recovery stream fixture its required query and batcher state |
||
|
|
0cca424b51 |
feat(wsl): admit no new WSL host or move in serve-only (kill switch 2/2) (#34694)
* feat(wsl): admit no new WSL host or move in serve-only Main refuses wslHosts:add while the internal gate is closed and reports acceptsNewWork in the WSL host capability; moves already need the open gate. The renderer hides Add WSL distro and every Move entry point once main says serve-only, while saved hosts keep their Connect and Remove. * fix(wsl): offer no new WSL host or move until main answers the capability The renderer's acceptsNewWork now starts false, so Add WSL distro and the Move entries never flash in serve-only before the capability reply. * fix(wsl): point the WSL-bridge chat refusal at Add WSL distro only when it is offered In serve-only Add WSL distro is hidden, so the refusal keeps its terminal-only words there. * test(wsl): give the move status-line test's hosts mock the new-work hook #34676's test mocks use-wsl-hosts-enabled; WslHostsSection now also reads useWslHostsAcceptNewWork, which follows the same gate there. |
||
|
|
21ad2d9dc5 |
fix(wsl-mover): settle an interrupted move automatically, and hold the host's server update during a move (#34823)
* fix(wsl-mover): settle an interrupted move automatically, and hold the host's server update during a move An app update or crash between sending a move's copy and the host's commit leaves a `blobs-transferred` record. Startup recovery has no host to ask, so the projects stay fenced, and the automatic mover only previewed, which refuses an in-flight move, retrying forever. The projects stayed read-only until the user started the move from the dialog. The automatic mover's preview now settles that record first (through the host: back to zero, or forward when the host committed), holding the distro's run while it does so it never races a move the user starts. The dialog's preview stays read-only. The preview moves to its own module. A Settings Update or Force, or any reconnect, could also redeploy the host's server in the middle of a move, cutting it off (safe, but the move is lost). Once a running move has journaled, a version-changing redeploy now keeps the running server and reports the update as waiting for the move, mirroring the SSH path's skip while migrating. The move's own first connect, before it journals, can still update an outdated server. * fix(wsl-mover): an automatic settle never reloads the window, and never holds its own host update Review of #34823: - A settle that finds the host committed ran the desktop rewrite, which reloads the window past its unload veto. From the automatic mover it now records the commit only (the projects stay fenced), and the next start's rewrite pass finishes it before any window opens. A move the user starts still finishes at once. - The server hold counted any unfinished record of the distro, so an automatic settle of an old record with an outdated server was held, refused for an update, and retried the same way. The hold now counts only the cutover the running move journaled itself. * fix(wsl-mover): let the user finish a committed move in-session; park the automatic mover meanwhile After an automatic settle records a commit for the next start, nothing could finish it in-session: the user's Move refused as already in flight and the orchestrator retried for nothing. - A settle that finds the head committed but not yet rewritten on this desktop finishes it now when the user asked (their Move, or the status line's Retry), returning the existing "finished an earlier move" answer; the automatic mover still leaves it for the next start. - The automatic refusal carries detail `finish-pending`, which parks the distro (new reason `finish-pending`) instead of retrying; the next start, whose rewrite pass finishes the move before any window opens, puts it back to pending. - The park rules move to wsl-move-orchestrator-park.ts. * fix(wsl-mover): give the finish-pending park its own status line Main's move status line (#34676) names every park reason; the finish-pending reason this PR adds needs one: the earlier move is done on the host, and finishes here at restart or with Check again. |
||
|
|
fa5284aca2 |
feat: edit queued messages inline with the full chat composer (#31180)
* fix(native-chat): a refused queued message still blocks the queue when its card write fails Every reader of a queued card goes through one derived view of the journal's dispatch facts, so a card whose message was refused reads as returned even when its card-table update and heal both failed. One decision and one writer store the derived state for every action. * refactor(native-chat): keep each queued message in the chat's journal, not a second table A queued message lived in its own SQL table, and a hook that may be skipped copied each refusal from the journal into it. When that write failed, a refused card vanished: the cards behind it sent, and its Send and Delete did nothing. Each queued message is now a `queue` row in the chat's journal beside the submission that hands it off and the dispatch row that answers it. The reducer folds the card from those rows, so a refusal returns the card and holds the cards behind it with nothing written, and replay reads the same. Every action writes its own rows in one transaction. Cards an earlier build stored are read through the same classification until they move: each action moves its own card, and a bulk import runs once per open. A new epoch restates every card still owed an answer in the transaction that deletes the old rows. The settlement hook and its savepoint, the open-time heal, the drain's heal and the derived-card view are gone. The published card list is unchanged. * test(native-chat): adapt the queue tests to cards kept in the journal Cards are written through the journal, so tests queue them with their body alone and hand them off under their real fingerprint. Tests of the removed settlement hook, heal and SQL store are deleted; the text-update spec now covers the edit decision alone, and a test of an earlier build's stored holds seeds the legacy table and reads the imported cards. Rolling over an epoch now keeps a card whose hand-off was never handed over, so that test checks the retried id never sends rather than that nothing sends. * test(native-chat): a refused card holds the queue through rewind, a new epoch and a restart One whole-flow test through the host: the refusal writes no card row, a rewind that retires the refused hand-off and a rolled-over epoch keep the card returned, a restart and Resume send nothing behind it, its own Send refused again still holds the queue, and its Delete releases the next card in order. * test(native-chat): an earlier build's queued cards move into the journal once, each read the same One mixed-import test through the host. The first open's import fails and moves nothing, yet every card reads as it will; Delete and Send each move only their own card. The next open moves the rest in one transaction, writing a refusal only where its hand-off is gone, nothing for answered cards, and leaving an unreadable row on disk. A later command turn spends a moved command card, a third open writes nothing, an old Delete replays from its receipt, and a chat with only answered legacy rows clears them in a delete-only transaction. * test(native-chat): adapt typechecked tests to cards kept in the journal The row-kind table lists a queue row, the clear and legacy-import tests match the current signatures, and the downgrade test keeps only the leftover-send case: a queued card is now a newer-version journal row an older build keeps read-only, and users don't downgrade. * refactor(native-chat): drop the journal row writer's unused transaction hook No caller passes one since the queue's savepoint bookkeeping left. * test(native-chat): downgrade probes write rows at the version older builds read The highest version this build reads is now 4, the queue row's. A newer build's row in these probes is written at version 3 so the older build meets its kind, not a newer version, and the Stop-event probe hands the older build the rows as stored, since a read raises each row's version. * test(native-chat): unit tests follow the queue row's version 4 The legacy-import test opens real SQLite, so it runs in the Node runtime project. The newest version this build reads is now 4, and a read raises a row's version to it, so the turn-lifecycle test no longer pins the in-memory version (the written one stays pinned by journalRowSchemaVersion). * fix(native-chat): one batch echoing two refused queued messages spends both The per-row delivery check returned only the first waiting card an echo proved delivered, so when one settlement carried echoes for two cards the second stayed waiting and was sent again. It now returns every card the row proves delivered, and the fold withdraws each; replay folds the same. * fix(native-chat): a rewind moves an earlier build's cards into the journal first While the open's import had failed, an earlier build's card that read as refused through its hand-off lost that reading when an in-place rewind retired the hand-off: it disappeared and the card behind it sent. The rewind now adopts every legacy card ahead of its tombstones and deletes their rows in its own transaction, as an epoch replacement already does, so the fold latches each card's reading before its hand-off is gone. * fix(native-chat): keep an earlier build's card whose hand-off is still unconfirmed The import dropped a legacy card handed off as a send whose delivery was unknown, though the fold keeps such a card linked and a later refusal returns it. The import now keeps every card whose hand-off a later row can still answer, through the same check the reducer folds dispatch rows by. * fix(native-chat): one delivery echo withdraws at most one queued card One provider echo proves one delivery, yet it withdrew every waiting card with the same text whose hand-off was refused, so a second identical card was lost. The fold now pairs each echo with one card: on its own row the earliest-positioned match no other echo of that row took, and for a card that waits again the earliest applied echo no card has taken. Paired echoes live in the fold's state, so live and replay pair the same; readers of cards not yet imported work on a copy. * fix(native-chat): a queued message handed to the agent is sent again only on proof it never got it Pressing Stop after Orca handed a queued or steered message to the agent, before the agent confirmed it, put the card back in the queue, and Resume or the next send sent it again. A check matching the agent's echo of the text was the only guard against a double send, and it kept trading a resend for a lost card. Whether the card waited again was decided by the rejection's category, not by proof the agent never got the message. A refused hand-off now waits again only where Orca proves the agent never received it: the host still held it, or whoever settled it recorded that. A failure still returns the card and holds the cards behind it. Anything else may have reached the agent, so the card is spent and its message reads as sent, derived on every fold from the stored rejection: with the turn it was answered into, as that turn's unconfirmed message where it was handed over; withdrawn before any turn opened, as a person's own send a Stop took back. The reopen mark ignores a recovered doubt, and the restart reconciler no longer judges a queued hand-off unsent from what history lacks. The echo text matching and its pairing are deleted. A close or quit while the agent starts settles sends with the unrun hold. The host hands nothing to a child before its start answers (structured-agent-session-delivery-loop.ts: a handover needs phase ready), so such a send went to an earlier child and may have run: it now reads as sent instead of waiting again. * fix(native-chat): Claude's report that it removed a queued message unrun lets the card wait again Claude says when it removed a send without running it: the interrupt receipt's cancelled list, or a command_lifecycle cancelled, discarded or refused frame for a command that never started. Every one settles through rejectClaudeDispatchWaiters, which now marks the settlement unrun. For a queued card's hand-off the host records that as proof the agent never got it, so the card waits again under the queue's pause. A direct send keeps the plain refusal: there the proof would owe it as stopped history. * fix(native-chat): an earlier build's card stopped after hand-over follows the same rule on upgrade Earlier builds put a card back to waiting after any refusal without a verdict and cleared its link, so a card the agent may already have would be sent again after the upgrade. The card's own hand-offs in the journal decide now: unchanged and last sent as one that may have reached the agent, it is spent on that hand-off and its message reads as sent; edited or sent again since, it is held for its own Send under a host-only marker that publishes as a plain hold; with no hand-off in doubt, including one that never left Orca, it waits as before. The import writes a card spent on a hand-off in doubt, so its message shows. * fix(native-chat): read a queued row's hand-off before the lookup that uses it The lookup's callback lost the narrowing of the row's change, which the mobile test typecheck rejects. * test(native-chat): a card steered into a turn a Stop ends stays sent in the Stop tests Three tests pinned the old rule, that a card handed into a running turn comes back to waiting when a Stop ends it. Under the new rule nothing proves the agent never got it, so the card is spent: with the turn named, its message reads as that turn's unconfirmed one; without, as a send the Stop took back. Neither is ever sent again. * fix(native-chat): a queued message stopped before Orca handed it to the agent waits again A Stop that aborts a hand-off after its row is written but before the agent call now records the withdrawal as never reaching the agent, for queued hand-offs only, so plan D's rule returns the card to waiting under the Stop's pause instead of spending it. Direct sends keep the plain withdrawal (the flag would owe them as stopped history). The agent's own refusal while aborted is kept rather than overwritten, and an abort thrown during the call stays in doubt. * fix(native-chat): a queued message stopped while the agent prepares it waits again The abort signal reaches only an adapter's preparation (its options, the previous turn opening), never its write, so the signal's own reason thrown back is the adapter saying nothing was written. The handover now reads that, for queued hand-offs only, as never reaching the agent, so the card waits again under the Stop's pause. Claude no longer wraps that abort as an option refusal, which had returned a stopped card as a refused one blocking the queue. A real refusal keeps its cause and its barrier; any other throw stays in doubt and is never resent. * test(native-chat): the usage-limit Continue backlog case writes its card through the journal queue Main's #30396 wrote its backlog card with the stored fingerprint and host-instance stamp the journal queue derives instead; the card the Continue must yield to is the same waiting card. * test(claude): the real-CLI queued Stop expects the unrun mark Claude's cancelled-unrun receipt carries * feat(mobile): edit a queued message's images on the phone: remove or attach * fix(mobile): gate queued image edits on the host reader verdict * test(mobile): declare the upload fixture chat mode * fix(native-chat): retain spent legacy messages when import fails * fix(mobile): reveal the full queued image editor on open * fix(mobile): invalidate queued editor geometry without a render ref write * refactor(chat): prepare composer drafts and measured queue dragging * feat(native-chat): add conditional queue removal and authoritative reordering * feat(native-chat): move queued edits into the normal composer on desktop and phone * fix(native-chat): own complete phone drafts before authoring * fix: preserve submitted composer drafts across storage replacement * fix composer validation and mobile CI diagnostics * fix mobile composer test contracts and diagnostic output * Capture mobile test compiler diagnostics in CI * Fix queued message contract typing and English strings * test: complete queued extraction transport fixtures * refactor: separate composer skill binding from send mutations * fix(mobile): grant draft storage within route limits * fix(native-chat): settle each draft save on its own and publish complete composer drafts Phone: a queued Edit copy no longer consumes the save that later typing owns. Each ordinary save and the exact copy settle only their own result; an explicit save waits for its own pending write, and a failed or retired write never schedules another or revives the copy. Desktop: a pasted-text leaf no longer shifts which selected file binds where, and a hand-back held during an IME composition reaches the store only merged with the visible editor document, including writes the editor admits without an update and the composition settle. * fix(native-chat): import the draft type once in the draft cache * test(mobile): type the held-write state without an assertion * test(native-chat): assert the handed-back file on Send without reading a typed transport as a mock * test(mobile): pass main's agent-confirmed flag to the submitted-files harness * fix: reveal queued reorder grip on touch screens * fix: save reopened phone drafts and batch reorder measurements * test: use an explicit React module type * Preserve queued message sortable identities on unchanged renders * Prevent stale queued drag completion after unmount * fix(mobile): hand off navigation across session workspaces * test(mobile): use resolved session identity in dictation fixture * feat: edit queued messages inline with the chat composer * fix: normalize queued edit skill ownership * fix: retire phone skill selections with the sent draft * fix: consolidate queued edit module imports * fix: separate edit save action and stabilize image callbacks * fix: complete phone inline composer integration * fix: retain same-name queued skill selections * fix: complete desktop queued composer integration * test: use typed phone composer host lookups * fix: include queued edit localization keys * Preserve inline edit input across save and attachment completion * Preserve complete queued edits across delayed saves * Preserve queued edit input across delayed completion * Complete queued edit lease loss and pending cancellation * Use recognized queued edit test fixtures * Consolidate queued edit imports and type host test spy * Print mobile test compiler diagnostics on ratchet failure * Correct queued edit integration fixture types * fix: keep queued edit placeholder independent of readiness * Fix queued edit compiler fixture boundaries * Align upload completion test with ordinary insertion * Combine mobile composer draft imports * Load queued edit host fixture during test collection * Size inline phone queue editor to available space * Use typed scroll components in phone presentation contract * Save typed text in a queued edit as written The inline editor is the chat composer, so it keeps the composer's own identity model and no longer refuses Save for text that looks like a command. Command rows picked from the menu are still refused, Enter still means Save, and Edit never sends or runs anything. Regression tests cover Undo after deleting an accepted command or skill pill, a scanned skill named like a command, two saved files behind one token, and typed command text saving literally. Also fixes two merge leftovers in tests: a missing import and a fixture that stored the whole menu row as a skill. * Keep ordinary sends on the main composer contract * Fix mobile composer imports and fixture loading * Consolidate queued edit imports and duplicate regression * Restore ordinary send catalog short circuit and repair test boundaries * Preserve returned rich drafts through send acceptance * Remove obsolete queued editor strings from new locales |
||
|
|
d6918c7a1d |
fix(remote-files): cap search replies, say when a diff is too large, and measure a 100 MB read on WSL (#34882)
Follow-ups from the large-file audit (E7): - files.search had no byte budget: a result past the remote reply cap failed outright with reply_too_large. It now keeps the whole files that fit and marks the result truncated, as files.listAll and searchPaths already do. Local callers stay uncapped. - A diff side past the 10 MiB read cap came back as binary, so the diff said "Binary file changed" for a large text file. Blob reads mark it `tooLarge`, the binary diff result carries an optional `tooLarge`, and both diff views say "File too large to diff". Older clients ignore the field and keep the binary view. buildDiffResult builds its binary sides without a cast. - The real-WSL lane pages a 100 MB file over the plain distro's shared control socket in the editor's 384 KiB chunks and records the time, chunk count and orcad's VmHWM. Record-only: it asserts nothing, and a failure is recorded in the receipt. |
||
|
|
780ab3d71d |
fix(bitbucket): canonicalize ssh.bitbucket.org remotes in review links and Gitea detection (#30808)
Fold every forge SSH host alias (ssh.github.com, altssh.gitlab.com, ssh.bitbucket.org) through one shared normalizeForgeWebHost so main-process provider detection and renderer manual review links agree. Remotes on ssh.bitbucket.org now open bitbucket.org pull request forms instead of ssh.bitbucket.org URLs, and Gitea no longer claims the host. Co-authored-by: Eric Junker <4758+ejunker@users.noreply.github.com> Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> |
||
|
|
1a0ce3a55c |
feat(editor): highlight Groovy files and Jenkinsfiles (#26792)
Register Groovy as a lazily loaded TextMate language using Shiki's bundled grammar, and map .groovy/.gvy/.gy/.gsh/.gradle, Jenkinsfile, Jenkinsfile.* and *.Jenkinsfile (plus the groovy shebang) to it. Token scopes are mapped onto ids the stock Monaco themes already style. Fixes #25635 Co-authored-by: Neil <neil@stably.ai> |
||
|
|
bd4702fbb5 |
fix(managed-server): let a forced update or rollback cross mixed daemon generations (#34664)
The terminal census collapsed sessions spread over more than one daemon generation to a null protocol, so a host that kept a legacy daemon alive across an earlier update refused every forced update and rollback while any terminal ran. The census now reports every live protocol, and the crossing check requires the incoming build to attach each one. The single-protocol field stays for older desktops. |
||
|
|
612febdadd |
Open existing agent chats and retained panes from their rows (#34650)
* fix(agents): open existing chat and retained pane destinations * fix: keep agent navigation scoped to the current destination owner * test: initialize dashboard tabs without a type assertion * fix: complete navigation test and English catalog contracts |
||
|
|
cd1fe07182 |
feat(kimi): add K3 to the commit-message model picker (#11386)
Adds kimi-code/k3 (Kimi K3) to the static Kimi model list, which is also the allowlist, so planning with K3 no longer fails with "not available". Drops the test that only restated the catalog. Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> |
||
|
|
85ea1cc4c5 |
feat(browser): add Vivaldi as a Chromium cookie-import source (#11449)
Detect Vivaldi profiles on macOS, Windows, and Linux and import their cookies like other Chromium browsers. On Linux, Vivaldi stores its cookie key under Chrome's libsecret application name, so the browser definition can override the keyring application used for the lookup. Co-authored-by: Neil <neil@stably.ai> |
||
|
|
96cd21bbc4 |
Keep remote agent status in sync after completion and approvals (#34729)
* fix(remote): reconcile stale paired agent status and pane titles Adapt the remote completion repair from #25205 while preserving sparse runtime pane slots through existing PTY bindings. Co-authored-by: Manan Chataut <mananchataut@gmail.com> * fix(remote): preserve pane identity when reconciling moved titles Use mounted manager identities and retained PTY bindings ahead of replay order; keep fresh byte-stream ownership on the correct moved pane. * fix(remote): release byte status fence after host approval * fix(remote): tighten paired title removal and test the timing fence - Share the byte-write timing decision (resolveRendererOwnedAgentStatusTiming) between pty-connection and the flap test so reverting it fails a test. - Only delete a saved pane title when its durable leaf is absent from both the host layout and local panes; unresolved or surface-less slots are kept. - Share the client-fence predicate (clientAgentStatusFencesHost) between status and title reconciliation. - Cover removed-leaf spinner fallback in worktree status and a client split absent from a pre-split host snapshot. * fix(remote): correct fence predicate and title test types --------- Co-authored-by: Manan Chataut <mananchataut@gmail.com> |
||
|
|
d20791e522 |
fix(session-search): read --since as an instant, whatever offset it carries (#28329)
Hosts filter with `updated_at >= ?`, comparing text against UTC toISOString() values, so a `+08:00` cutoff was read as if UTC and a whole-second `...00Z` cutoff dropped sessions in that same second (`Z` sorts after `.`). The cursor key also hashed the raw spelling. Normalize `since` to toISOString() in AiVaultSearchFiltersSchema. Every client and host path parses this schema, so new clients send a cutoff older hosts already compare correctly, and new hosts normalize whatever older clients send before filtering or building the cursor key. `Date` keeps milliseconds only, so a cutoff like `...00.0005Z` rounds up to the next millisecond rather than letting in a session from before it. Fixes #28253 Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> |
||
|
|
d155cfba05 |
feat(editor): syntax highlighting for Glimmer .gjs/.gts files (#13236)
Register glimmer-js and glimmer-ts Monaco languages that embed JavaScript/TypeScript as the background script and tokenize each <template> block as a Handlebars island. Embed entry is bounded by the shared line budget so long lines cannot blow the Monarch recursion limit. Mobile maps the new ids to javascript/typescript highlighting. Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> |
||
|
|
e3cabd5e3c |
feat(wsl-mover): restore the host's browser link before a move, else say logins stay behind (#33086)
* feat(wsl-mover): restore the host's browser link before a move, else say logins stay behind A WSL host without its deployment link has no stable browser partition, so the move's cookie copy carries nothing. Connecting a move's host now re-saves the live connection once when the link is missing, which restores it whenever the pairing or ports were what broke it. When the host still cannot keep logins, the move preview lists "browser sign-ins won't carry over"; the move is never blocked for it. The move result also names the reason the copy recorded. * refactor(wsl): share the save-and-notify of a host connection; keep the service under its line cap Rebased on main, wsl-host-service.ts went over 300 lines. The persist-then-retire-transports step now lives in wsl-host-connection-record.ts (saveWslHostConnection), used by both the connection-change handler and resaveConnection. |
||
|
|
82c492c684 |
fix(agents): use a Qoder icon that stays visible in dark mode (#29038)
Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
c017ef983c |
Preserve WSL Codex question and child completion status (#34724)
* fix(agent-status): preserve WSL Codex questions and child completion * test(agent-status): route remote Codex question test through relay envelopes * fix(agent-status): scope remote Codex roster removals to the reporting relay session - Unlabelled relayed polls retire only children the current relay link listed; each WSL link starts a new session, so a restarted guest's partial roster cannot delete children an earlier guest reported. - One removal rule: an explicit list, a done aggregate, or an unshed absent roster proves removals; a shed roster with live work keeps the children. Drops the old done-main-agent clear that wiped shed rosters. - An unshed poll with no roster now retires the last child while the root works. - Share the Codex hook event-to-state rule between local and relayed paths. |
||
|
|
bb10b80be5 |
feat(wsl-mover): D3a-2 move status line on WSL host rows (dark) (#34676)
* feat(wsl-mover): D3a-2 per-distro move status line on WSL host rows, with decline causes and stale-record pruning (dark) * fix(wsl-mover): key D3a-2 status records without the node-only journal module in the renderer * fix(wsl-mover): D3a-2 pre-review — never prune user choices or on an unreadable host file; calm paused line; one-key blocker sentence; Show terminal feedback * refactor(wsl-mover): D3a-2 distro-in-use check in its own module * test(wsl-mover): the orchestrator host-connect test gives the new in-use port * fix(wsl-mover): D3a-2 Check again runs as the user's act on the distro (stopped-distro gates) * fix(wsl-mover): D3a-2 user steps use main's runAsWslUserAct gate; wiring test |
||
|
|
a21f79dee4 |
Fix copying from Codex started manually in remote shells (#34715)
* fix(terminal): forward copies from Codex started in remote shells * test(terminal): capture PowerShell copy probe exit status * fix(terminal): preserve configured shell arguments for remote profiles * test(terminal): isolate profile result from system startup output * test(terminal): run native daemon shell probes with Node * fix(terminal): keep an inherited remote-viewer marker out of local panes An Orca started from a remote viewer's pane inherits ORCA_REMOTE_VIEWER_CLIPBOARD, which would make every local Codex fake an SSH session. Treat the marker as per-spawn identity so only explicit launch env carries it. |
||
|
|
c698f9bded |
fix: prevent setup command truncation during shell startup (#25820)
* fix: keep setup command short so it survives shell startup The POSIX setup wrapper inlined the runner path six times. On long worktree paths it exceeded macOS's 1024-byte canonical PTY input limit when typed while the shell was still sourcing rc files, so the tail and submit byte were dropped, setup never ran, and a gated agent waited forever. Carry the setup script in ORCA_SEQUENCED_SETUP_SCRIPT and submit only `bash -lc 'eval "$ORCA_SEQUENCED_SETUP_SCRIPT"'`, mirroring the existing startup gate. The env is merged into setup.envVars wherever the gate is built so provisioning, fallback retries and renderer tabs/splits all receive it, and WSL imports it untranslated. Closes #20935 * fix(wsl): forward the setup script WSLENV entry before the daemon boundary Same-protocol daemons from older builds rebuild WSLENV without ORCA_SEQUENCED_SETUP_SCRIPT, so WSL setup would eval an empty script and the gated agent would wait for its timeout. Also swap new spec casts for the spawnedPtyEnv fixture. * fix: fail loudly when the sequenced setup script env is missing A dropped ORCA_SEQUENCED_SETUP_SCRIPT made eval run an empty string and exit 0, silently skipping setup. ${VAR:?missing} reports it in the Setup pane. --------- Co-authored-by: Neil <neil@stably.ai> |
||
|
|
ad8d35eb59 |
feat(wsl): serve saved WSL work behind a closed hosts gate (gate states, kill switch 1/2) (#34683)
* feat(wsl): serve saved WSL work behind a closed hosts gate (serve-only) The WSL hosts gate gains three states. A closed gate with a saved WSL host or a committed move becomes serve-only: saved hosts stay listed and reachable, committed rewrites, retention, interrupted-move recovery and the way back keep running, and the preload API is exposed through a stamped window argument. Adding hosts and starting moves still need the open gate. With nothing saved the gate stays closed exactly as before. * fix(wsl): stamp serve-only into the dashboard popout and Space windows too They load the same preload, so without the argument they hid saved WSL hosts' status and Connect in serve-only. One helper now supplies the argument for every window on the shared preload. * fix(wsl): reviewer follow-ups for the serve-only gate - Refuse wslHosts:add unless the internal gate is open here, so this PR is safe on its own. - Promote on any move journal entry, so recovery can reset an in-flight move whose host record is gone. - List unfinished moves in serve-only. - An unreadable WSL deployment store fails closed in serve-only too, through a shared serving flag main sets at startup. - Report the gate state in wsl_usage_snapshot as an optional field. |
||
|
|
36edb4a9ce |
fix(orchestration): refuse an automatic close after real input, join remote releases, converge the home
- An automatic close checks the terminal's last driving-input time right before closing and keeps a worker someone typed into after worker_done; typing itself does no orchestration database work. - Remote releases share the per-resource single-flight with local release, so a home worker-release joins the host timer's close. - Host fleet snapshots and federationShow report released and the pending deadline; the home applies the existing release projection inside its observation fence. - Real restart tests: a file-backed database reopened by a fresh runtime releases a missed deadline once and finishes interrupted requests. |
||
|
|
1eaaf85e9f |
Land the WSL project mover dark (merges only after verify-15b, the flag-off audit and green CI) (#34059)
* test(orcad-migration): pin the SSH manifest through the real dormant collectors Co-Authored-By: Claude <noreply@anthropic.com> * refactor(orcad-migration): read the dormant-state export through a source-kind scope A local-WSL scope lives on host local and owns only its projects, so host-wide matches stay an SSH whole-host rule. SSH bytes are pinned by the collector golden. Co-Authored-By: Claude <noreply@anthropic.com> * feat(wsl-mover): export a local WSL move's signed manifest with its dormant state (D1b-3c) Collects the scoped projects, their groups and every dormant-state kind through the local-WSL export scope, rewrites UNC paths to the distro's, and returns blockers for anything the collectors can't carry instead of dropping it. Automations move disabled, as the wire requires, and come back as a list to re-enable on the host after commit. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): reset an interrupted move to zero, or finish it once the host proves a commit Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): abort a move by its identity when its manifest is too large for a request Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): cap a new move's manifest below the request limit, and move forward on a by-reference commit only once the host flushed it Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): remove only the newest move of a distro, so its chain stays readable Co-Authored-By: Claude <noreply@anthropic.com> * feat(runtime): clients read a migrated pane's scrollback from its host (D1b-6d-1) * fix(runtime): hold a remote pane only when its host is known to serve scrollback, and never read bytes in render (D1b-6d-1) * fix(runtime): route the scrollback read by the tab's own host, never the focused one (D1b-6d-1) * fix(runtime): resolve the scrollback host through resolveOwner and use the shared RPC error check, after main moved both (D1b-6d-1) * feat(wsl-mover): a moved project's existing chats stay listed and resumable on this computer (D1b-7a) * fix(wsl-mover): moved-project chats go through the layout owner instead of writing layout directly (D1b-7a) * test(wsl-mover): run the moved-project chat runtime test in the Node runtime (D1b-7a) * test(wsl-mover): read the hidden local row through main's per-host hidden-repo API (D1b-7a) * feat(wsl-mover): rewrite the desktop's routing and seed the host's session after a move (D1b-7c) Registers the main-side desktop rewrite stores ui-routing, session-globals and host-session-seed. Adds a +2 main layout-writer baseline line for wsl-move-main-rewrite-stores.ts: these are one-shot, ledgered move rewrites, and no LayoutCommand can set focus or seed a runtime host's partition. * fix(wsl-mover): finish the main rewrite before the window loads, keep one copy of each moved tab, and copy instead of move (D1b-7c) * feat(wsl-move): rewrite renderer stores for moved projects and keep their UI through catalog prunes (D1b-7d) Registers the renderer-side desktop rewrite stores quick-open-history, file-view-preferences and notebook-environments. The renderer copies each moved workspace's entry to its WSL host key, marks it applied in the same storage, and records the ledger entry; main requests a storage flush first and accepts only the main window. Committed moves are re-listed for re-application at every startup. Catalog prunes keep filters, hook trust and setup-script dismissals of moved repos. * fix(wsl-move): import the migration manifest types from main's orcad-migration folder (D1b-7d) * fix(wsl-move): import wslUncPathToLinux from shared wsl-paths in the manifest exporter, where 7d moved it (D1b-7d) * feat(wsl-mover): rewrite a moved project's orchestration history on the desktop (D1b-7e) Settled local worker dispatches and their worker-terminal rows in a moved project take the WSL host's worktree id, in one ledgered, idempotent store. Chat workers, live rows, federated attachments and JSON receipts stay as written; automations keep their unchanged local copy (the scheduler only advances it). Per-table dispositions for orchestration.db. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): hold the orchestration store while a worker in scope is live; skip federated rows (D1b-7e review) Co-Authored-By: Claude <noreply@anthropic.com> * feat(wsl-mover): copy in-app browser logins into the WSL host on a move (D1b-7f) A committed WSL move now copies each in-app browser profile's cookies once into the WSL host's stable route partition (owner decision 3a), merging without overwriting what the host jar holds and never touching the source. Where that is infeasible (no deployment link so no stable partition, the destination is not a WSL host or is gone, or the partition name is held by another identity) the host starts fresh and the move journal records why (3b). Registered as the ledgered browser-cookies rewrite store; it runs only once browser sessions and an app window exist. WSL_MOVE_DESKTOP_REWRITE_REGISTRY_COMPLETE stays false. * feat(wsl-mover): retain moved source rows, reconcile them on start, and plan delta moves (D1b-8) * fix(wsl-mover): keep the retained mark out of the WSL move manifest (D1b-8) * feat(wsl-mover): the move driver runs a WSL move end to end, with production gate facts and journaled restore folders One entry point (and preview/start/cancel/listUnfinished IPC for D1b-9) plans the move, gates terminals on the hook server's agent status, the close-tab process probe, running automation runs and live dispatches, pauses and proves exit, stages, sends blobs, commits only from blobs-transferred (#29825), and finishes on the desktop. Any failure resets to zero or goes forward when the host committed. Restore folders and the automations to turn back on are kept in the journal; the host turns those automations back on after commit, retried until it confirms. A real-PTY test pauses daemon shells, and runs on a real distro in the WSL orcad lane. * feat(wsl-mover): move dialog with preview, blockers, progress and result behind the internal WSL hosts gate (D1b-9) * fix(wsl-mover): move dialog hides instead of blocking, follows runs after a reload, and lets a start settle an unfinished move (D1b-9 review) * fix(wsl-mover): word an unfinished earlier move as still finishing (D1b-9) * test(wsl-mover): type the e2e's fake move state instead of reading it through Reflect (D1b-9) * WIP(wsl-mover): 7f-2 registry complete, coverage proof, startup re-apply (D1b-7f-2) * test(wsl-mover): registry-complete lifecycle, stale-focus restart, unload re-apply (D1b-7f-2) * fix(wsl-mover): share the session focus write so the re-apply adds no layout writer (D1b-7f-2) * fix(wsl-mover): redo additive rewrites once at a stale window's unload; behavioural coverage proof (D1b-7f-2 review) * test(wsl-mover): the IPC record test now finishes the rewrite with the registry complete (D1b-7f-2) * fix(wsl-mover): fence worktree-less spawns by cwd and re-prove terminal exit before commit (R46, WIP) * test(wsl-mover): pin the commit re-proof, browser jar identity and repeated move generations (R45, R46, R47) * fix(wsl-mover): fence any spawn by its folder and name the re-proof's reason (R46 review) * fix(wsl-mover): a terminal in a known folder outside the move never blocks it (R46 follow-up) * test(wsl-mover): kill the real move driver at every point against a real host store; abort a reset move's leftover stage on reconnect Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): carry unsaved drafts into the moved project; round-trip every fixture through the real export, driver and host import Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): reset a move waiting on a distro that is proven unregistered; test updates mid-move (R41), lost distros (R38) and two desktops (R39) Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-mover): list the D1b-10 real-SQLite mover tests Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-mover): type the fault test's journal hook without a cast Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): reset for a lost distro even when its kept host fails to connect, never for a renamed one; compare filled-in repo keys only where the source lacked them Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): carry markdown frontmatter visibility and closed-terminal-tab tombstones into the moved project Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-mover): read the persisted stage through a typed record, not Reflect Co-Authored-By: Claude <noreply@anthropic.com> * feat(telemetry): report how WSL moves end, by phase and reason code (R43) Co-Authored-By: Claude <noreply@anthropic.com> * fix(telemetry): report a pause refusal's reason, an outcome for a thrown run, and only real transport errors as unreachable Co-Authored-By: Claude <noreply@anthropic.com> * fix(agent-hooks): a WSL host's orcad never removes the hook entries the WSL bridge shares (R42) Co-Authored-By: Claude <noreply@anthropic.com> * fix(agent-hooks): a WSL host's Codex account-home launch with hooks off skips too; mark the R42 guard to drop with the bridge Co-Authored-By: Claude <noreply@anthropic.com> * feat(wsl-mover): "Use on this computer again" brings a moved project back as it was before the move Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): judge a bridge WSL pane's foreground inside its distro On Windows every live bridge pane's own process is wsl.exe, so the busy-terminal gate read every open WSL terminal as running a program and refused the move. Read the pane's terminal foreground process group inside the distro (processes carry ORCA_PANE_KEY): only shells means idle, anything else blocks, and an unreadable guest stays unverifiable. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): only the selected projects' session rows can refuse a WSL move The session eligibility check treated host local's whole partition as the move's, as the SSH conversion does. So an agent session or unsaved draft in any other project on this desktop, or in a project an earlier move retained, refused every later WSL move from that distro. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): sign the manifest as the journal and the host read it The digest was computed over in-memory rows. A value with toJSON (a Date on a row added this session) canonicalized to {} when signing but to its string once written to the journal or sent to the host, so the first move after adding a project reset with orcad_migration_manifest_digest_mismatch until a restart reloaded the row. Normalize through JSON before signing. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): carry a slept pane's scrollback from its daemon checkpoint The move sleeps every pane first, and a slept pane's history lives only in the daemon's checkpoint, never in a renderer snapshot. The export carried renderer snapshots only, so moved terminals opened empty. After Sleep the driver reads each paused pane's checkpoint (as cold restore would replay it) and the export carries it under the pane's own snapshot ref; the snapshot channel serves those bytes, checked against the signed hash. SSH conversions pass no reader and are unchanged. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): say why when a move can't be prepared, instead of a bare reset An export or journal failure after the pause (a digest mismatch, on awin) was rethrown and shown as "everything was put back" with no reason. Nothing is journaled yet at that point, so refuse with the error named instead. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): retry a renderer store main refused to record The renderer applied a store and wrote its marker, but ignored a refused ledger record (gated-off, failed, not-main-window), so a committed move stayed unfinished and refused every later move of the distro until the next app start. Log the reason and retry with backoff until it lands. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): a WSL pane is idle only when its shell has nothing else Review of #32343: reading only the terminal's foreground group let background jobs, nohup and disowned work, setsid daemons and a script waiting at read pass as idle, and the move's Sleep would end them. Scan the pane shell's subtree, its session and every process carrying its key; any non-shell process, or a shell running a script, blocks. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): never leave behind an agent whose key may be the selected project Review of #32343: scoping the session check to the selected projects let an unqualified key for a repo id another host also registers fall out of both the transfer and the refusal. Such a key now refuses. Adds tests that fail on the old code: another project's live agent with its tab open and its draft don't refuse, the same kinds of state in the selected project still do. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): refuse an unreadable slept checkpoint, prefer it, and spool it to disk Review of #32343: - A checkpoint behind an unreadable log (or an unreadable one) refuses with the pane named instead of carrying stale history. - For a pane the move just slept the checkpoint is the newest copy, so it wins over an older renderer buffer or snapshot. - Buffers spool to a per-move folder and only their hashes and sizes stay in memory; the snapshot channel reads them by offset. The folder is removed whatever the outcome. - A journal write that landed before it threw is reset, so no orphan record blocks the next move. awin's checkpoints were 310-615 KB, well inside the 5 MB per-pane cap, so nothing there is trimmed. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): retry a failed listing, never a record another window was refused Review of #32343: not-main-window can't clear by waiting, while a listing failure is transient. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): sign the manifest as the host parses it The likelier cause of awin's digest mismatch: the signature covered the exported objects, but the manifest parser keeps only the fields it knows, so a session field it drops (one a sleep can write) left the journal and the host hashing something else. Sign the parsed form, and warn when the parser dropped anything, since such a field does not move. Co-Authored-By: Claude <noreply@anthropic.com> * chore(wsl-mover): split the journal step out of the driver, and format The review fixes took wsl-move-driver.ts past the line limit; the export-and-journal step moves to its own module unchanged. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): a slept pane passes the busy check; say what each move dropped or lacked Re-run on awin ( |
||
|
|
cb43b47359 |
fix(terminal): let file existence pick spaced path readings so prose cannot hide a path (#34281)
* fix(terminal): let file existence pick spaced path readings so prose cannot hide a path * refactor(terminal): let the host's file check decide spaced paths and replay phone taps that name no file Spaced readings no longer guess where a path ends: a rooted path offers one reading per following word (up to ten), and a relative path grows only to its first filename so dense path lists stay cheap. A phone tap whose readings name no file replays the ordinary tap instead of reporting a failed open, and checks up to 16 readings at once. * fix(terminal): drop a phone tap's replay after a newer tap, and accept digit-led extensions * fix(terminal): drop a phone tap's replay after typing, URL taps or selection, and accept Unicode extensions * refactor(mobile): decide terminal file taps from the text under the finger instead of replaying withheld taps A tap is a file tap only when it lands on a path itself; prose beside a path stays an ordinary tap at once. This removes the withheld-tap fallback and its stale-tap counters. * refactor(terminal): return spaced path guesses apart from written paths so only a host check can act on a guess Hover and chat check every reading as before. A click opens a guess only after the host finds its file, and never past an external share. A phone tap is a file tap only when a written path is under the finger, so a markdown destination with spaces counts. OSC 8 targets are parsed as written. Phone file checks return to 8 at a time. * fix(terminal): leave a click on prose beside a path to the terminal unless a written path or a confirmed guess covers it * fix(terminal): fall back to the shortest checked written path when a click's file checks fail * docs(terminal): say relative paths grow only to their first filename |
||
|
|
4b1967bdd8 |
feat(i18n): add Turkish UI language (#34718)
* feat(i18n): add Turkish UI language Register Turkish (tr) as a built-in UI language alongside en, zh, ko, ja, es, fr and pt: language setting, system-locale detection, renderer and main-process lazy catalogs, Settings picker label in every catalog, Settings search keyword, onboarding picker, docs, README link and a Turkish style glossary (config/i18n-turkish.md). tr.json comes from the community Turkish catalog (#22200, refreshed in #31316), reconciled with the current en.json: keys retired from en.json, entries whose English source changed since the refresh, and entries with placeholder mismatches are dropped and fall back to English until the next translation pass. Supersedes #31316. Co-authored-by: Uğur Pala <mail@ugurpala.com> Co-authored-by: mert <mmerttpz@gmail.com> Co-authored-by: Mehmet Efe Aytaş <mehmetefeaytas@icloud.com> * feat(i18n): complete Turkish catalog Translate the 1,432 keys tr.json was missing, restore the count placeholder in six Turkish singular forms, and order the catalog like en.json. * fix(i18n): apply Turkish translation review Correct 32 mistranslations (wrong meaning, translated command names and example paths, swapped placeholders) and 525 glossary and grammar issues that two independent review passes both flagged. * fix(i18n): Turkish review fixes and dotted-I settings search Fold U+0307 from lowercased Turkish İ so settings search matches plain-i queries, fix sampled Turkish meaning/terminology issues, and align the glossary casing rule with the catalog. --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Uğur Pala <mail@ugurpala.com> Co-authored-by: mert <mmerttpz@gmail.com> Co-authored-by: Mehmet Efe Aytaş <mehmetefeaytas@icloud.com> |
||
|
|
8916bf36aa |
fix(mobile): release queued inbound frames after transport teardown (#34777)
* fix(mobile): release queued inbound frames when transports close * test(mobile): run relay inbound retention regressions in every runner --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
52a43ed99e |
feat(i18n): add Russian UI language (#34717)
* 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> |
||
|
|
55f9525c49 |
feat(editor): highlight CUDA C and C++ files (#21384)
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> |
||
|
|
0866cb1b08 |
fix: bound local iteration checks and show live progress (#34700)
* 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> |
||
|
|
fed9a762be |
feat(editor): detect the language of extensionless scripts from their shebang (#25055)
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> |
||
|
|
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> |
||
|
|
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> |