Repository navigation
Sync upstream/main to v1.4.229's cut point, and ship a Windows installer - #2
Merged
Merged
Conversation
…9566) * fix(accounts): open the browser for a WSL account sign-in A WSL Add account / Sign in again ran the provider CLI inside the distro, where stock distros have no opener, so no browser opened. Claude's link is now caught by the same BROWSER stand-in Copy link uses, Codex's by the link it already prints, and the desktop opens it after validation. * fix(accounts): never open a cancelled WSL sign-in's link; wait the full login window Addresses review: watch the login's cancel signal before opening, give auto-open the whole login window to receive Claude's link, log the refused host, and cover cancel-before-delivery and service wiring in tests.
…ent has proven exited (stablyai#29588) A pane whose shell outlived its agent kept counting as the session's live holder because its PTY was alive, so a paired client got a plain shell. Ask the hook store: a holder it proves exited no longer blocks the resume; unverifiable still does.
…marker out of terminals (stablyai#29569) * test(e2e): prove the held-6768 case really held the port and orcad bound another Co-Authored-By: Claude <noreply@anthropic.com> * fix(pty): keep orcad's managed-launch marker out of user terminals A terminal on a managed host inherited ORCA_ORCAD_MANAGED_ACTIVATION_ROOT, so an orcad a user started there looked client-managed: --port stopped being strict and idle exit applied. Scrub it like the other per-launch identity variables. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…tablyai#29577) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…owner build switch (off by default) (stablyai#29353) * feat(layout): add the dark layout.apply channel and route pane splits through main behind ORCA_LAYOUT_OWNER A build made with ORCA_LAYOUT_OWNER=main registers layout.apply: main applies the window's layout command to the stored partition through the shared applyLayoutCommand, minting new ids. A user split then waits for main's answer and mounts the pane id main minted. Every other build substitutes 'window', so neither branch is compiled in. * fix(layout): write only the records a layout.apply command touched A load-then-save rewrite also normalizes records the command never touched. The command's effect is now the diff between the save before and after it, written onto the stored partition record by record. A split whose main reply says a paired server holds the tab splits as today. * fix(layout): write a load-supplied record whole and check that patched partitions reload to the command's result * feat(layout): close, rename and equalize panes through main behind ORCA_LAYOUT_OWNER In a layout-owner build the window's pane close, title change and equalize go through layout.apply and the window shows main's answer. A window pane close keeps the legacy close's rules: the tab's last pane is refused, a pane restarted since main read the close is left alone, every partition holding the tab closes it, and the tab's remote session id follows the remaining pane. The rules sit behind a command field only layout.apply sets. * fix(layout): close the tab when a racing pane close leaves the window one pane * fix(layout): leave an unmounted tab alone when main refuses its last pane * feat(layout): move panes and save divider ratios through main behind ORCA_LAYOUT_OWNER Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * test(layout): a taken pane drop whose pane closed does nothing Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * test(layout): pin the window's pane move to main's saved tree, and the drops main cannot take Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * fix(layout): close a user's pane even if its terminal restarted, as today Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * test(layout): pin the restarted-pane close directly, not through a made-up profile state Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * fix(layout): leave a split to today's path only when the workspace's row names a paired server The split switch point asked which host to route to with a helper that falls back to the focused server, so a focused server could claim a workspace whose row names no owner. Use the same owner test the tab mirror uses. * test(layout): type the split owner mock without a cast * test(layout): type the layout-owner command mocks with the real signature * test(layout): type the gesture command mock with the real signature * fix(layout): close the dark path's gaps: unmounted split panes, refused or failed splits and moves, ratios during a move, release guard - A pane main saved but the window could not mount (source pane or manager gone during the await) is closed again in main, so it does not come back on restart. - A split main refuses because its copy lacks the workspace, tab or pane, or a failed call, splits as today; a refused or failed move moves as today. - Divider ratios committed while a move is in flight wait for the window's move, then go to main. - The orcad bundle gets the ORCA_LAYOUT_OWNER define when the switch is on. - Packaging and the orcad template refuse ORCA_LAYOUT_OWNER=main and any output a dark build marked. - workspace-layout-record-patch.ts: no non-null assertions; plain comment for the map depth. * test(layout): count a split pane as mounted from the split mock's own results * fix(layout): act as today whenever main lacks the target or the call throws, not just for splits - sendPaneCommandToLayoutOwner runs asToday for workspace/tab/pane_not_found and a thrown call, so close, rename and equalize fall back like split and move; a handler that throws no longer runs the fallback too. - A close main refuses as its last pane, while this window still has others, closes as today. - A move whose local step throws still releases held divider ratios. - Drop the orcad output marker: nothing read it; the template build refuses the switch itself. * test(layout): plain names for the last-pane fallback test and the marker comment * docs(layout): say plainly what an indeterminate write can leave behind * fix(layout): finish the main merge with this branch's versions of the layout-owner files * test(build): copy the layout-owner build guard into the compiler-cache checkout fixture * feat(layout): send tab rename, color and pin through main behind the layout-owner build switch In an ORCA_LAYOUT_OWNER=main build, the tab bar's rename, color and pin ask main's layout.apply first; the window then runs today's action. When main lacks the tab or the call fails the window acts as today; a paired server's workspace keeps today's path. Pinning a tab now also ends its preview in main's copy, as the tab bar's pin does. Other builds compile the switch out. * fix(layout): leave a pinned tab's preview mark to the window until main opens files Changing the shared pin command would change what a paired client's pin does in every build. * fix(layout): write a folded legacy row in its loaded form when a layout.apply command touches its claim A legacy terminal row the load folds into a tab-bar tab stays stored as is. Closing the tab it repeats, or giving it a tab-bar entry by moving it, let the next load resolve the claim the other way: the row came back or took the other tab's terminal. Such a command now writes the row as the load had it; every other record still stays as stored. * feat(layout): accept tab moves, group splits and group sizes on layout.apply Group sizes have no tab, so they go to the workspace's routed partition. * refactor(layout): move the window's layout.apply sender out of the terminal pane folder Tab groups send through it too; it now also acts as today when main lacks the group. * feat(layout): reorder, move and split tab groups, and save group sizes, through main behind ORCA_LAYOUT_OWNER A tab drop and Move Tab to Split wait for main's answer and then show main's placement, with main's new group id; group divider sizes are drawn while dragging and saved by main when the drag ends. Closing an empty group needs no command: main never holds an empty group. * docs(layout): wrap the layout-owner sender's doc comment * fix(layout): review fixes for tab moves through main - Read a folded row's terminals with the loader's own claim rule, so rows sharing only an SSH session are covered too, and drop the row's remote session entry with it. - The record-patch test allows a folded row only in its loaded form. - A tab drag ends at once; main's answer shows the move after. - A lone group main moved whole is placed so only when this window's group is lone too. * refactor(layout): adopt only a folded row's pane layout beside its row A row's remote session entry is carried through load and save unchanged, so adopting it from the load changed nothing (the earlier commit's message overstated it). * feat(layout): record a window's terminal tab close through layout.apply closeTabs can now record each terminal tab it closes, or does not find, as closed for the given reason (pruned as a partition's records are), so a start that commits later is refused, as today's close records it. layout.apply takes one tab's close with the window's reason: main forces it in every holder partition, marks a user close's launches, stops no terminal (the window already did, sparing any another tab shares), and leaves a workspace it lacks to today's close. A sibling the load supplied that the close only renumbered is no longer written. * feat(layout): send the window's terminal tab close to main behind ORCA_LAYOUT_OWNER The window still closes the tab and stops its terminals itself; main records the close through layout.apply instead of the close intent, which stays for paired servers and when main lacks the workspace. * fix(layout): review fixes for the tab close through main - The window's close sends through a store-free sender, so the store no longer imports itself. - Main marks a user close's launches by the terminal's own id. - A recorded close prunes the whole partition's close records, as today, not one workspace's. * feat(layout): open and close browser tabs and pages through main behind the layout-owner build switch Co-Authored-By: Claude <noreply@anthropic.com> * refactor(layout): name the browser sender's no-op so the window bundle keeps its names * feat(layout): move a window's dragged-out pane into a new tab through layout.apply behind ORCA_LAYOUT_OWNER * refactor(layout): keep the topology commit under its line limit * fix(layout): keep a served browser tab's open, address and close in order while main writes it Co-Authored-By: Claude <noreply@anthropic.com> * fix(layout): review fixes for the window's pane drag-out through main * docs(layout): note what a refused served-tab close leaves * refactor(layout): re-key a moved pane from the move alone * refactor(layout): share one record-only layout.apply sender and inline the id schema Co-Authored-By: Claude <noreply@anthropic.com> * Restore the browser layout-apply hook dropped by the main merge --------- Co-authored-by: Claude <noreply@anthropic.com>
…a possibly reused PID (stablyai#29548) * fix(orcad): reclaim a pre-stablyai#28125 lock whose PID another user now owns, and explain a possibly reused PID Records written before stablyai#28125 carry no start ticks or boot id, so on Linux a wall-clock mismatch is unproven and a reused PID kept the lock held forever. A PID owned by another non-root uid cannot be the holder (orcad never changes uid), so that now proves reuse in both lock reclaim and managed stop. When the verdict stays unproven, the error names the live process and the orcad.lock path that is safe to remove once no orcad is running. * fix(orcad): treat the overflow uid as unproven and word the reused-PID error for any boot-less record * test(orcad): keep the Linux-platform lock cases off Windows, where the platform hook also drives data-root privacy
…to install (stablyai#29556) Every orcad start ran installPendingOrcadMigrationShellHistory, which paid a process inventory with an empty worktree list. That inventory could leave a surviving daemon session unfiled and drop its restored orchestration receipt before any client connected. Return early unless a committed migration still holds a received shell history, and refresh against the host's real worktrees when one does. Follow-up to stablyai#28902.
…, behind the per-host switch (STA-10765) (stablyai#29571) * fix(ssh): relay-era terminals' orca orchestration commands work again, behind the per-host switch (STA-10765) * fix(ssh): attest bridge-verified relay terminals for legacy records, replay settled receipts, cancel on disconnect * fix(ssh): admit retained legacy coordinators, their delivery targets, and legacy receipt replays * fix(ssh): reject emptied retry ids, match moved panes by leaf, replay completed retries after reassignment * fix(ssh): answer --help in a relay-era terminal without running the command * fix(ssh): exempt only matching mutation replays from relay CLI scope; keep legacy retries replayable after reassignment * fix(ssh): relay CLI security review: pane-bound legacy coordinators only, revoke and cap calls, exact-hash replays, target-aware identity, consent copy * fix(ssh): admit settled legacy workers only with a committed receipt; honor exact reply replays
…ablyai#29439) * ci: remove Windows build and persistence test overhead * ci: collect unit phase diagnostics during PR checks * test(ci): seed hook reuse fixture from the canonical prebuild The hook reuse regression first built into a missing private --output, so it always reached Cargo (74s warm on Windows). Build through the default output instead, which reuses a warm canonical prebuild, then copy its executable and fingerprint into the private fixture root. * fix(lint): clear inherited max-lines and broad object tab parameter after main merge Combine the duplicate shared/execution-host imports in runtime-host-services (301 -> 300 lines) and type the overlap test's tab mapper with the RuntimeMobileSessionClientTab owner type instead of object. * fix(ci): align inherited runtime and workflow contracts * test: establish changed runtime probe signatures deterministically * test: await asynchronous daemon profile cleanup * test: shut down owned daemons before deleting profiles * test: clean up oracle daemons during final app close * test: recognize verified Linux zombie exit during daemon teardown * fix: preserve folder SSH ownership when project groups conflict
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…yai#29590) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
… reads, and name orchestration in the reset notice (STA-10765) (stablyai#29596)
…yai#29323) * test: batch lint fixtures and remove repeated runtime scan * test(cli): consolidate owner coverage and remove false decoding proof * test(renderer): retain IPC lifecycle behavior without copied inventories * test: share floating panel behavior suite startup * test: retire synthetic runtime constructor probes * test: share saved terminal title runtime setup * test: share native chat render cost setup * test: share terminal close continuity runtime setup * test(runtime): prove mobile geometry through desktop restores --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(agent-hooks): bound retained agent exits Proven exits were only forgotten by a successor claim, so closed tabs and retired panes kept theirs forever and every save rewrote them. Drop an exit when its tab closes, its pane retires or its PTY is really torn down (not a reconnectable disconnect), and prune exits older than the hydrate window at save. * fix(agent-hooks): closing a moved pane's former tab keeps its exit * fix(agent-hooks): keep an aged exit while its retained resume row remains * fix(agent-hooks): launch-authority retirement keeps a proven exit
…by default) (stablyai#29354) * feat(layout): add the dark layout.apply channel and route pane splits through main behind ORCA_LAYOUT_OWNER A build made with ORCA_LAYOUT_OWNER=main registers layout.apply: main applies the window's layout command to the stored partition through the shared applyLayoutCommand, minting new ids. A user split then waits for main's answer and mounts the pane id main minted. Every other build substitutes 'window', so neither branch is compiled in. * fix(layout): write only the records a layout.apply command touched A load-then-save rewrite also normalizes records the command never touched. The command's effect is now the diff between the save before and after it, written onto the stored partition record by record. A split whose main reply says a paired server holds the tab splits as today. * fix(layout): write a load-supplied record whole and check that patched partitions reload to the command's result * feat(layout): close, rename and equalize panes through main behind ORCA_LAYOUT_OWNER In a layout-owner build the window's pane close, title change and equalize go through layout.apply and the window shows main's answer. A window pane close keeps the legacy close's rules: the tab's last pane is refused, a pane restarted since main read the close is left alone, every partition holding the tab closes it, and the tab's remote session id follows the remaining pane. The rules sit behind a command field only layout.apply sets. * fix(layout): close the tab when a racing pane close leaves the window one pane * fix(layout): leave an unmounted tab alone when main refuses its last pane * feat(layout): move panes and save divider ratios through main behind ORCA_LAYOUT_OWNER Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * test(layout): a taken pane drop whose pane closed does nothing Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * test(layout): pin the window's pane move to main's saved tree, and the drops main cannot take Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * fix(layout): close a user's pane even if its terminal restarted, as today Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * test(layout): pin the restarted-pane close directly, not through a made-up profile state Claude-Session: 10569c9a-a0a1-4fc9-8469-0edfb7aed125 * fix(layout): leave a split to today's path only when the workspace's row names a paired server The split switch point asked which host to route to with a helper that falls back to the focused server, so a focused server could claim a workspace whose row names no owner. Use the same owner test the tab mirror uses. * test(layout): type the split owner mock without a cast * test(layout): type the layout-owner command mocks with the real signature * test(layout): type the gesture command mock with the real signature * fix(layout): close the dark path's gaps: unmounted split panes, refused or failed splits and moves, ratios during a move, release guard - A pane main saved but the window could not mount (source pane or manager gone during the await) is closed again in main, so it does not come back on restart. - A split main refuses because its copy lacks the workspace, tab or pane, or a failed call, splits as today; a refused or failed move moves as today. - Divider ratios committed while a move is in flight wait for the window's move, then go to main. - The orcad bundle gets the ORCA_LAYOUT_OWNER define when the switch is on. - Packaging and the orcad template refuse ORCA_LAYOUT_OWNER=main and any output a dark build marked. - workspace-layout-record-patch.ts: no non-null assertions; plain comment for the map depth. * test(layout): count a split pane as mounted from the split mock's own results * fix(layout): act as today whenever main lacks the target or the call throws, not just for splits - sendPaneCommandToLayoutOwner runs asToday for workspace/tab/pane_not_found and a thrown call, so close, rename and equalize fall back like split and move; a handler that throws no longer runs the fallback too. - A close main refuses as its last pane, while this window still has others, closes as today. - A move whose local step throws still releases held divider ratios. - Drop the orcad output marker: nothing read it; the template build refuses the switch itself. * test(layout): plain names for the last-pane fallback test and the marker comment * docs(layout): say plainly what an indeterminate write can leave behind * fix(layout): finish the main merge with this branch's versions of the layout-owner files * test(build): copy the layout-owner build guard into the compiler-cache checkout fixture * feat(layout): send tab rename, color and pin through main behind the layout-owner build switch In an ORCA_LAYOUT_OWNER=main build, the tab bar's rename, color and pin ask main's layout.apply first; the window then runs today's action. When main lacks the tab or the call fails the window acts as today; a paired server's workspace keeps today's path. Pinning a tab now also ends its preview in main's copy, as the tab bar's pin does. Other builds compile the switch out. * fix(layout): leave a pinned tab's preview mark to the window until main opens files Changing the shared pin command would change what a paired client's pin does in every build. * fix(layout): write a folded legacy row in its loaded form when a layout.apply command touches its claim A legacy terminal row the load folds into a tab-bar tab stays stored as is. Closing the tab it repeats, or giving it a tab-bar entry by moving it, let the next load resolve the claim the other way: the row came back or took the other tab's terminal. Such a command now writes the row as the load had it; every other record still stays as stored. * feat(layout): accept tab moves, group splits and group sizes on layout.apply Group sizes have no tab, so they go to the workspace's routed partition. * refactor(layout): move the window's layout.apply sender out of the terminal pane folder Tab groups send through it too; it now also acts as today when main lacks the group. * feat(layout): reorder, move and split tab groups, and save group sizes, through main behind ORCA_LAYOUT_OWNER A tab drop and Move Tab to Split wait for main's answer and then show main's placement, with main's new group id; group divider sizes are drawn while dragging and saved by main when the drag ends. Closing an empty group needs no command: main never holds an empty group. * docs(layout): wrap the layout-owner sender's doc comment * fix(layout): review fixes for tab moves through main - Read a folded row's terminals with the loader's own claim rule, so rows sharing only an SSH session are covered too, and drop the row's remote session entry with it. - The record-patch test allows a folded row only in its loaded form. - A tab drag ends at once; main's answer shows the move after. - A lone group main moved whole is placed so only when this window's group is lone too. * refactor(layout): adopt only a folded row's pane layout beside its row A row's remote session entry is carried through load and save unchanged, so adopting it from the load changed nothing (the earlier commit's message overstated it). * feat(layout): record a window's terminal tab close through layout.apply closeTabs can now record each terminal tab it closes, or does not find, as closed for the given reason (pruned as a partition's records are), so a start that commits later is refused, as today's close records it. layout.apply takes one tab's close with the window's reason: main forces it in every holder partition, marks a user close's launches, stops no terminal (the window already did, sparing any another tab shares), and leaves a workspace it lacks to today's close. A sibling the load supplied that the close only renumbered is no longer written. * feat(layout): send the window's terminal tab close to main behind ORCA_LAYOUT_OWNER The window still closes the tab and stops its terminals itself; main records the close through layout.apply instead of the close intent, which stays for paired servers and when main lacks the workspace. * fix(layout): review fixes for the tab close through main - The window's close sends through a store-free sender, so the store no longer imports itself. - Main marks a user close's launches by the terminal's own id. - A recorded close prunes the whole partition's close records, as today, not one workspace's. * feat(layout): open and close browser tabs and pages through main behind the layout-owner build switch Co-Authored-By: Claude <noreply@anthropic.com> * feat(layout): open editor tabs under the window's id, per split, and promote previews through layout.apply openEditorTab takes the window's tab id (the same open again is a no-op, a held id is refused), dedupes per group so a file open in another split gets its own tab, pins an existing preview on a non-preview open, and places the new tab before closing the replaced preview so a group whose only tab is its preview keeps its id. layout.apply accepts openEditorTab, promotePreviewTab and a closeTabs with no terminal close record. * feat(layout): record the window's editor tab opens, closes and preview promotions in main behind ORCA_LAYOUT_OWNER The window still draws first (openFile returns at once and its callers act on the tab by id). Main then records the tab under the window's ids and decides the group fallback and preview replacement by the same shared rule. Switch points: the one editor tab create, the unified tab close, preview promotion on activation, edit and make-permanent, and the reopened tab's position. * refactor(layout): name the browser sender's no-op so the window bundle keeps its names * feat(layout): move a window's dragged-out pane into a new tab through layout.apply behind ORCA_LAYOUT_OWNER * refactor(layout): keep the topology commit under its line limit * fix(layout): keep a served browser tab's open, address and close in order while main writes it Co-Authored-By: Claude <noreply@anthropic.com> * fix(layout): review fixes for the window's pane drag-out through main * fix(layout): review fixes for editor tabs through main openEditorTab refuses a group main lacks instead of placing the tab in another group, and gives a workspace with no group (the window keeps its emptied root group; main closes it) the sender's group id. Tests pin close-all, the emptied root group, the refused open into a fresh split, and that the window sends an edit-mode file's record exactly as its session save keeps it. * docs(layout): note what a refused served-tab close leaves * refactor(layout): re-key a moved pane from the move alone * test(layout): assert the window drew the tab main refused * refactor(layout): share one record-only layout.apply sender and inline the id schema Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…9595) * ci: reuse prepared natives in Windows serve-switch builds * ci: route legacy relay SQLite fixtures through Node
…lyai#29324) * test: batch lint fixtures and remove repeated runtime scan * test(cli): consolidate owner coverage and remove false decoding proof * test(renderer): retain IPC lifecycle behavior without copied inventories * test: share floating panel behavior suite startup * test: retire synthetic runtime constructor probes * test: share saved terminal title runtime setup * test: share native chat render cost setup * test: share terminal close continuity runtime setup * test(runtime): prove mobile geometry through desktop restores * test(runtime): skip unused RPC catalog in bind-host coverage * test: route legacy relay database fixtures through Node * test: require process exit after daemon cleanup loses contact --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* test: consolidate terminal query ownership proof * test: route legacy relay database fixtures through Node * test: require process exit after daemon cleanup loses contact --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…ts done (stablyai#29604) * fix(runtime): keep a restored agent turn unverifiable instead of done after a server restart * fix(runtime): retire restored turns by the synced leaf's title clock; no Stop for unverifiable mobile turns * fix(runtime): capability-gate restored agent rows so older clients keep the legacy done projection * fix(runtime): retire restored turns only on shell titles; restored rows never pierce live client status * test(web): the browser client advertises the restored agent status capability
…ommitted move (D1b-7b) (stablyai#29597) * feat(wsl-mover): the ledgered desktop rewrite stage that finishes a committed move (D1b-7b) * fix(wsl-mover): a move finishes its rewrite only once every store exists (D1b-7b) * fix(wsl-mover): chats never move per decision C, the journal enforces registry completeness, stores time out (D1b-7b)
…i#29620) Co-authored-by: Claude <noreply@anthropic.com>
…#29619) * test: route legacy relay database fixtures through Node * test: require process exit after daemon cleanup loses contact * test: limit WebSocket budget suites to their RPC handlers --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…inear/Jira without a restart (stablyai#29608) * fix(orcad): tell the user when a locked macOS Keychain hides Linear and Jira, and recover without a restart A managed macOS host reached only over SSH keeps its login Keychain locked after a reboot, so the server's credential key failed closed and the app asked the user to reconnect a token that was fine. Exit 36 from security find-generic-password (errSecInteractionNotAllowed) is now a 'locked' lookup: the server logs it once, retries the Keychain on each credential use and before each Linear/Jira status read, and status carries an optional credentialErrorReason: 'keychain_locked' that the app shows in place of the generic text. Once unlocked, Settings offers a one-click move of the same key into the owner-only key file. * fix(orcad): keep retrying a locked Keychain after a timeout, fence the key move to the host that asked, report the lock only for credentials that need the key * fix(settings): offer the file-storage switch to a paired browser's implicit server too * fix(settings): route the Keychain notice and key move by the host that reported the status; sweep stale key-record staging; say the moved key is not machine-bound * fix(orcad): sweep only this machine's key-record staging, so a shared home's other hosts keep theirs
* test: batch lint fixtures and remove repeated runtime scan * test(cli): consolidate owner coverage and remove false decoding proof * test(renderer): retain IPC lifecycle behavior without copied inventories * test: share floating panel behavior suite startup * test: retire synthetic runtime constructor probes * test: share saved terminal title runtime setup * test: share native chat render cost setup * test: share terminal close continuity runtime setup * test(runtime): prove mobile geometry through desktop restores * test(runtime): skip unused RPC catalog in bind-host coverage * test: share transcript scroll suite startup --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
… as stale (stablyai#29957) The preparation lock reason named only the owner's pid, so a host sharing the repo's disk (an NFS home) read another machine's in-progress preparation as abandoned and discarded it. The reason now carries the writer's machine identity (optional, appended after the fields older builds read); a different or unknown machine is unverifiable, and a reason without one is judged by pid only on a local disk.
…pen terminals (stablyai#29958) * fix(orcad): replace a retired terminal daemon when a client returns during idle shutdown * fix(daemon): drop idle-retired legacy generations when replacing the daemon * fix(orcad): treat a lost or late daemon retirement reply as committed * fix(orcad): settle a lost retirement reply with the daemon itself before replacing it * fix(orcad): bind the replacement to the retired daemon and honor the router fence * test(daemon): type the pending census * fix(daemon): skip the owner check only for a proven-dead endpoint
…say when a conversation isn't found (stablyai#29105)
… still starting (stablyai#29911) The + agent menu waited 5 s for the new tab's terminal and otherwise showed "Couldn't launch X — the terminal did not start." Any slow spawn (Windows, a cold or busy terminal host, a queued spawn) passed through that state and got the false toast before the agent came up. The pane's own spawn already reports a real failure in the pane, so the guess is removed.
…er (stablyai#29946) * fix(sidebar): order sidebar text the same on every device Sidebar names, project labels, project-group names and folder workspace names were ordered with localeCompare, whose result depends on the ICU data bundled with Electron, the phone WebView or Node. Order them with one comparator in src/shared/sidebar-list/text-order.ts instead: case-folded and NFC-normalized, digit runs by value, the rest by code point, and equal text broken by host-qualified id. Co-Authored-By: Claude <noreply@anthropic.com> * perf(sidebar): fold each sort label once per sort; reuse the phone row identity helper Co-Authored-By: Claude <noreply@anthropic.com> * fix(sidebar): ignore accents when ordering sidebar names Accents and case now only break exact ties, so "Éclair" sorts beside "eclair". Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…tablyai#29124) * fix(native-chat): identify the owner when resume create is refused * test(native-chat): consolidate transcript refusal cases * test(native-chat): keep ownership coverage at the launch boundary * test(native-chat): update adoption fixture for early ownership admission * test(native-chat): align resume admission assertions with host ownership * test(native-chat): keep RPC coverage focused on ownership proof * test(native-chat): assert blank request presence before optional source * fix(native-chat): admit the actual CLI source during chat creation * fix(native-chat): satisfy source admission lint checks * test(native-chat): provide the waiting hook prompt * test(native-chat): isolate source admission fixtures from host homes * test(native-chat): canonicalize adoption fixture directories * test(native-chat): preserve early ownership admission in source stack * fix(native-chat): preserve resume refusal behavior and honest transcript feedback * fix(native-chat): retain import read evidence in typed result * fix(native-chat): preserve admitted source and prepared execution home * fix(chat): retain source evidence for dispatched adoption * fix(chat): keep source capture within module limits * test(chat): allow host evidence in create routing * fix(native-chat): admit an unsaved transcript under a linked account folder A missing transcript stayed unresolved while its account root resolved through symlinks, so containment failed and a not-yet-saved conversation showed a load error instead of the unsaved notice. * refactor(native-chat): move the newest-item import window into its own module Keeps journal-legacy-import.ts under the line limit after the source identity observer landed on top of the streaming import. * fix(native-chat): restore the refusal error import lost in the main merge * fix(native-chat): admit Pi transcripts against the root Session History walks A PI_CODING_AGENT_DIR that already ends in sessions, or any custom folder, made admission expect <dir>/sessions while the lookup searched <dir>, so a found conversation was refused. * refactor(native-chat): admit and look up CLI transcripts in one store per account Each agent's import described where an account keeps its conversations twice, once for the path check and once for the lookup, and the two could disagree (the linked-folder and Pi custom-root refusals). The import now names one conversation store per account; the create path resolves it once and both the hook-path check and the fallback lookup judge that same store. OpenCode's store is its exact database.
…e like a sidebar delete (stablyai#23593) * fix(workspace-cleanup): let select-all include the workspace you are in Deleting the current workspace is allowed like any other, so select-all now includes it; a live agent stays excluded. Cleanup removal now hands focus to a surviving sibling after the batch, as the sidebar's batch delete does. Linear: STA-4686 * test(workspace-cleanup): cover focus handoff after the dialog closes and after Delete anyway * fix(workspace-cleanup): move focus off a deleted active workspace as soon as its row is gone * fix(workspace-cleanup): don't reopen a workspace the user left while a cleanup batch runs The per-row focus handoff fired whenever no workspace was selected, so closing the successor's last tab mid-batch re-activated it (and spawned a new terminal) on the next row. Move focus only when the workspace the batch left the user on is actually gone and nothing else took focus. * refactor(workspace-cleanup): move focus off the active workspace when a cleanup delete starts Switch to the successor once, right after the batch rows are marked deleting, instead of repairing an empty selection after each row settles. The active row is no longer active when it is removed, so the store never clears the selection and no later handoff is needed. * fix(workspace-cleanup): never hand focus to a workspace in the same cleanup batch The scan qualifies local rows as host `local`, so their delete state lives under a host-qualified key, while a sidebar row with no stored host only matches an unqualified key. The successor picker therefore saw batch rows as not deleting and could focus one about to be removed, leaving an empty screen once it went. Exclude the batch's own ids directly. * test(workspace-cleanup): use scan-shaped hosts in the active-workspace focus tests Candidates now carry the `local` host the scan publishes, which is what exposed the picker gap. The other-host case also stamps the viewed row with its host so it resolves; before, the lookup missed and the test passed with the host check removed. * feat(workspace-cleanup): confirm before a cleanup delete stops a running agent A cleanup delete (bulk, single row, or "Delete anyway") that includes a workspace with a running agent now shows a step naming those workspaces before anything is queued. The check reads live agent state at click time, attributed like the sidebar so structured chats count too, and re-asks if another agent starts while the step is open. The approved candidate records which agents the user agreed to stop; the per-row preflight that runs right before each delete refuses a row whose agent started after confirmation. With the step in place, live-agent rows join select-all like the active workspace. * refactor(workspace-cleanup): name the agent-stop same-action check * fix(workspace-cleanup): drop an open agent-stop step when the dialog reopens mid-batch * style(workspace-cleanup): match the agent-stop step's heading to the delete step * test(workspace-cleanup): type the cache-hydration mocks in the reopen test * style(workspace-cleanup): let the agent-stop step's heading use the dialog's own typography The changed-lines design-system gate rejects restyling DialogTitle and DialogDescription; the delete step's overrides predate that gate. * fix(worktree-delete): key delete state by the identity the sidebar card reads A cleanup delete names local rows with the 'local' host, so their queued and deleting state landed under 'local|<id>' while a card stored without a host reads the bare id and never showed it. Every delete-state write now derives its key from the store's own worktree record. * refactor(workspace-cleanup): reuse the sidebar delete's focus hand-off Drops the move-focus-before-delete path. Each confirmed row prepares the same prepareActiveWorktreeFocusAfterDelete committer the sidebar delete uses and runs it when that row's own removal succeeds, so the user stays on the workspace while it is queued, lands on the most recently visited surviving sibling once it is gone, and stays put if its delete fails. * refactor(workspace-cleanup): reuse the close-terminal stop-agent wording The stop step's single-agent title is the existing "Stop this agent?" string, and its description follows the close-terminal prompt's wording. * test(worktree-delete): cover a local-qualified removal failure on an unhosted card * docs(workspace-cleanup): describe the after-delete focus hand-off in the bulk-select note * fix(workspace-cleanup): name one agent in the stop step's button and keep one agent term per locale * fix(terminal): keep starting terminals in a workspace that is only queued for deletion A cleanup batch now marks its local rows with the same delete state the sidebar card reads, so the terminal spawn guard sees them. The guard exists because removal just killed the workspace's terminals; a queued row still has them and can fail its own delete and stay, so a new terminal opened there (often the current workspace) stayed blank. * refactor(terminal): name the teardown-started check the spawn guards share * chore(workspace-cleanup): keep one agent term in ko/zh and refresh a spawn-guard comment * fix(workspace-cleanup): refresh consent and focus per removal * fix(workspace-cleanup): invalidate detected host evidence * fix(workspace-cleanup): admit removal at transport send * test(workspace-cleanup): expect the send-time admission callback and a published chat tab
…ames (stablyai#29966) Records the post-stablyai#29946 text order for workspace rows (Name, Recent and project-name sort), project group names and folder workspace names, ungrouped and grouped by project, so a future ordering change shows up as a golden diff.
…t reported, not the capped status store (stablyai#29905) * fix(native-chat): decide owed helper work from what the provider reported, not the capped store Idle cleanup, replacing an outgrown agent, /clear, /compact, rewind, command handover and the teardown resume marker decided whether a chat still had helpers running by reading the agent-status store. That store is a bounded display projection: it refuses records when it is full or for per-record reasons, and a refused helper is still running. The host now keeps an uncapped per-session set of the child work its provider reported running and has not reported over, fed from every child-work edge before the store sees it. Every owed-work decision reads that set. An entry leaves on the child's own end (a late end of an earlier run leaves the current run open, as the store's run verdict does), on a Stop the store settled, or on the session's end. The strip's "incomplete" note and Stop all's unlisted route are now derived: open work that no live current-run record answers to. This replaces the refused-for-room side list, so every refusal reason is covered and nothing needs separate bookkeeping. * test(native-chat): the real-store test sink reads recorded helper handles, as production's does * fix(native-chat): keep helper run identity through delayed events and Stop * fix(native-chat): name the host helper lifetime token * test(native-chat): explain the Stop adapter fixture boundary * fix(native-chat): derive helper coverage from running store records * docs(native-chat): clarify running helper coverage * test(native-chat): use an explicit helper end event * Scope background Stop to captured child work * Exercise refused helper Stop race through status store
…#29224) * fix(mobile): remove the dead space around the chat composer The Tools toggle floats over the transcript and shows only when the chat has tool calls; the composer is one row (attach, message, mic, send) until focused or drafted; Stop takes Send's slot while there is nothing to send; the bridge lane's working dots move to the transcript's tail. * fix(mobile): name the composer's content facts for their role * fix(mobile): preserve composer controls and picker focus * fix(mobile): typecheck working indicator test lookup * test(mobile): find the floating Tools pill when checking a chat switch keeps it expanded
…, for Settings and chat (stablyai#29049) * feat(acp): one install row shows and drives a managed runtime install, for Settings and chat The row reads the shared host state: Install, byte progress with Cancel, extract and verify lines, Retry after a failure or cancel, and in Settings Reinstall or Update once installed. A failed status read says it could not check, never that nothing is installed. Strings in all six locales. * fix(settings): the install row says when a copy is damaged, when a PATH copy is used, and when the host needs unzip - A damaged copy reads "This copy of {agent} is damaged." with Install, which repairs it. - A copy found on this host outside Orca's reads "Uses the copy of {agent} found on this host." with no Install, since a launch would never run the download. - A host without the program to unpack the archive says so, with no Install. * fix(settings): say why a host running its own copy is offered no download * fix(settings): the install row says Cancelling only where Cancel was clicked, offers Orca's copy beside one found on the host, and keeps its status line after a failed install The host no longer publishes a cancelling phase or a missing unzip, so the row drops both: the row whose Cancel is still out says Cancelling and holds its button until the host's cancel settles. A copy found on PATH or in an install folder still gets Install of Orca's copy in Settings (the chat keeps its composer). An older installed release reads Installed. with Update. A failed first install keeps Not installed. beside the failure and Retry. The status line is a polite live region. * fix(settings): the install row says it is retrying a failed status check, and names the step after the download * fix(settings): a Cancel that fails for no stated reason says the cancel failed, not the install
… the saved layout (stablyai#29961)
…ect groups (stablyai#29962) Relinking projects the server already held still re-imported this desktop's retained copy of their project groups, so a group renamed on the server while it was managed failed the reconnect with orcad_migration_project_group_id_conflict. A relinked move now leaves to the server every group its projects sit in (read from repo.list's projectGroupId) and those groups' ancestors unless a moving row needs one, journals those ids, and keeps them out of the exported rows while still reading them for folder-workspace host ownership. Later delta moves subtract them as they do moved groups.
…self (stablyai#29964) * fix(runtime): the host stops a removed project's terminals itself Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): a runtime-stamped project still stops the shells that run here Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): refresh the PTY inventory and sweep again after a project's removal Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): bound the project inventory refresh and recheck the WSL move fence Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): fence a project's removal sweep by its SSH connection and wait out in-flight spawns Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): bound the project stop's lease wait by the removal deadline Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): refuse spawns into a removed project and skip a stop a same-id sibling shares Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): bound each project stop by the removal deadline Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): pass the removal deadline to the lease so a timed-out waiter is dequeued Co-Authored-By: Claude <noreply@anthropic.com> * test(runtime): type the project-removal fixtures instead of casting Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…s again (stablyai#29984) Partially reverts stablyai#27540 and the plain-http part of stablyai#27552, which broke web pairing on upgrade for 1.4.227 users who open Orca at a LAN or Tailscale address: - The host no longer refuses a first pairing from a plain-http page on another machine (insecure_origin, ORCA_ALLOW_INSECURE_WEB_PAIRING). - Such a page keeps its pairing code in local storage and signs in with it, as in 1.4.227, so reloads, new tabs and bookmarks stay paired; no notice. - Session-only browser keys (pairing.device-key-ephemeral.v1, the idle sweep) stay for browsers without Ed25519. - A web client whose credentials are refused shows the host's reason instead of an empty workspace and "Session restore failed".
Cut point: merge-base of v1.4.229 and upstream/main (2026-10-16), six days old at merge time. Window: 1.4.199's cut point (6108ce6) .. de1f6e3. Reverts landed upstream after the cut point, all targeting work outside the window: stablyai#30875 (reverts stablyai#30851), stablyai#30572 (reverts stablyai#30134), stablyai#30207 (reverts stablyai#30185). Known open upstream bugs accepted with this merge: - stablyai#31767 terminal_pane_owner_changed recurs on 1.4.229; fix stablyai#30448 landed after the cut point. - stablyai#31545 Claude account switch relaunches sessions in the wrong folder (regression from 1.4.224). - stablyai#29899 memory saturation / UI freezes with many concurrent agents. Conflicts resolved (17): fork capability gates, release-repo plumbing and the yolo-default gate kept alongside upstream's new imports and defines; the fork's failed-local-exit teardown re-expressed on upstream's keepsUntouchedFreshPane; release-mapping.json and windows-process- enumeration.md follow upstream's deletion. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit a0cd164)
Upstream added background push (push.onorca.dev) after the fork compiled out Orca Mobile, and starts it on both the desktop and orcad paths with no relation to the mobile capability. A build without mobile has no phone to push to, so it must never construct the gateway client. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mpiled out Upstream's native chat seeds new chats as Full access from a default independent of DEFAULT_TUI_AGENT_ARGS, so emptying those args for yolo-default left chats launching with every permission bypassed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Also lists the files that now carry fork patches in FORK_OWNED_PATHS: the build defines helper, the split updater modules, and the two new capability gates. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e 1.4.229 merge Three things undid `fix(terminal): tear down failed local exits after input` in the merge, with typecheck green: - The port onto upstream's new keepsUntouchedFreshPane helper read the raw lastTerminalInputAt instead of the input generation, so a late ack for input typed into a previous PTY made its fresh replacement look user-interacted. - Upstream moved its PTY suites into register-style .spec.ts files (stablyai#29193), which brought back the five upstream tests asserting the behaviour the fork inverts and dropped the fork's replacements. Those five are removed from the spec; the fork's versions now live in pty-connection-failed-local-exit.test.ts so the upstream suite stays byte-comparable. - The fork's `!session.connectionId` guard named a field upstream renamed to worktreeConnectionId; the session is untyped, so it was always true. Upstream dropped that guard itself in stablyai#27489 (a pane is now local or remote-runtime, and an SSH pane is the latter), so the fork does too, along with its unreachable direct-SSH test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-lines budget register-app-menu.ts and pty-input-forward.ts sit at exactly 300 counted lines upstream, so every fork line pushed them over. The crash-report gate now spreads ifCapabilityEnabled() in one line, markTerminalInputAttempted() returns the generation it credited, and pty-input-forward claims the viewport once before its two synchronous branches instead of in each. Also lists pane-host-capability-flags.ts in FORK_OWNED_PATHS; it carries the input-generation state. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Takes the runtime half of upstream eb9d2f9 (stablyai#31687, 2026-10-21), which landed after the 1.4.229 cut point: the Node that Orca installs on SSH hosts as their managed server moves from 24.21.0 to Node's October security release. Only the pin, the tests asserting it, and the node-server-tests image the change-scope test checks against are carried; the remaining CI, cloud and Dockerfile bumps arrive with the next sync. (partially cherry picked from commit eb9d2f9) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ease erli-linux-release.yml becomes erli-release.yml: one dispatch builds the Linux x64 .deb and the Windows x64 NSIS installer from the same commit, and publishes both into a single release only once both succeeded. Two workflows cutting separate releases would leave one platform's updater resolving /releases/latest/download against a release without its manifest. The Windows build is unsigned, because ERLI has no Authenticode identity. ERLI builds therefore drop upstream's SignPath publisherName and verifyUpdateCodeSignature, as upstream's dev channels do: electron-updater checks every downloaded installer against the publisher baked into the installed app, so keeping it would make each ERLI build reject the next one. Both platforms now also need two things this sync introduced. The orcad deployment template, built by upstream's node-server-tests.yml exactly as release-cut does, is required since upstream deleted the SSH relay (stablyai#27215); without it no SSH host can connect. And mobile/node_modules, since build:release always builds the mobile web bundle, even with mobile compiled out. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI5
This moves ERLI's Orca from upstream v1.4.199 to v1.4.229, fixes the places where the merge silently undid ERLI's own changes, and adds a Windows installer next to the Linux .deb.
What Changed
Upstream sync. Merges
upstream/mainatde1f6e3d81, the commit v1.4.229 (2026-10-17) was cut from — about a week old, perSYNC.md. 4216 upstream commits. Upstream's release commit is cherry-picked so builds are stamped2.0.<run>-erli-upstream.1.4.229.Fork patches the merge undid, now restored (typecheck and the targeted tests were green throughout):
pty-exit-hibernate.ts)keepsUntouchedFreshPaneread the raw input timestamp instead of the input generation; upstream's PTY suite split (stablyai#29193) brought back the 5 assertions the fork inverts and dropped the fork's tests; the fork's guard readsession.connectionId, renamed upstream toworktreeConnectionId(untyped session, so alwaysundefined)pty-connection-failed-local-exit.test.ts; the connection guard dropped, since upstream removed it itself in stablyai#27489 (a pane is now local or remote-runtime)push.onorca.devwith mobile compiled outmobilecapabilityyolo-defaultcompiled outmax-lineselectron.vite.config.tsconfig/build-plugins/erli-defines.tsupdater.tssplit furtherupdater/updater-release-feed.tsandupdater/updater-setup.ts(added toFORK_OWNED_PATHS)Security fix past the cut point. The managed-server Node runtime pin moves to 24.22.1 (Node's October security release), taken from upstream
eb9d2f9a06b(stablyai#31687, 2026-10-21) — only the pin, its tests, and the test image they check.Release workflow.
erli-linux-release.ymlbecomeserli-release.yml: one dispatch builds the Linux x64 .deb and an unsigned Windows x64 NSIS installer from one commit and publishes both in one release, only once both succeed (separate releases would leave one platform's updater pointing at a release without itslatest*.yml). ERLI builds drop upstream's SignPathpublisherName, as upstream's dev channels do, so an installed build does not reject the next unsigned one. Both builds now also:node-server-tests.ymlexactly asrelease-cutdoes. Upstream deleted the SSH relay (refactor(relay): delete the SSH relay server, its build assets and tests stablyai/orca#27215); without the template an ERLI build cannot connect to any SSH host;mobile/node_modules, whichbuild:releasenow needs for the mobile web bundle even with mobile compiled out.Why
Cut-point evidence (
SYNC.mdstep 2):terminal_pane_owner_changedon pane reconnect; the fix A terminal pane that loses its reconnect to another connection attaches to the winner instead of showing terminal_pane_owner_changed stablyai/orca#30448 (84 files) landed 2026-10-21, after the cut;Linked Issue
N/A — fork maintenance.
Visual Proof
N/A — no UI change beyond what upstream shipped; the new defaults are covered by tests.
Testing
oxlint(0/0),audit:code-quality:native,audit:code-quality:type-aware,check:max-lines-ratchet,verify:skill-bundle-manifest,check:node-runtime-pinsession.*field fork lines read is still assigned (added toSYNC.md)pnpm test:node: 12 320 files pass. The 28 that fail fail identically on a pristine checkout ofde1f6e3d81(no Bun, git 2.43 without reftable,cloud/deps not installed).pnpm testitself now requires Bun.de1f6e3d81only in fork-owned files, fork tests, the version bump and the Node-pin cherry-pick2.0.9001-erli-upstream.1.4.229) and launched under xvfb with an isolated profile:app-update.ymltargetsERLI-SA, the capability list is in the asar, the updater checksERLI-SA/orcaonly, and no request reaches stablyai or onorca.devERLI releaserun (as a prerelease) is its testExpected noise from the smoke run:
[agent-state-rules] download failed: HTTP 404— the rules feed resolves throughORCA_RELEASE_REPOtoERLI-SA/orca, which publishes no rules release, so the app keeps the rules bundled in the package.AI Disclosure
Merge resolution, fixes and workflow written with Claude Opus 5.5 (Claude Code), reviewed by the author.
Notes
The audit baseline (
config/erli-upstream-audit-baseline.txt) is deliberately not moved; that happens when an audit round closes, perAUDIT.md.🤖 Generated with Claude Code