Commit Graph
11735 Commits
Author SHA1 Message Date
Jinwoo-H ef8eb625ca fix(layout): tab reconcile and terminal reconnect stop writing tab structure (dark, layout-owner build only)
Main's frames draw the tab bar and rows: reconcile still returns its counts but writes nothing,
and reconnect still advertises restored terminals but leaves the rows to main.
2026-10-18 03:06:23 -04:00
Jinwoo-H 6bc1e5556f fix(layout): the save divergence detector becomes a report-only drift check behind its log (dark, layout-owner build only)
It no longer wraps the write: it compares the window's raw save with main's layout model, and
only when ORCA_LAYOUT_SAVE_DIVERGENCE_LOG is set.
2026-10-18 03:04:55 -04:00
Jinwoo-H 0c2fc15974 fix(layout): window saves keep main's layout and give it only the window's view and facts (dark, layout-owner build only)
windowViewSaveForMain/windowViewPatchForMain replace windowSaveForMain: main's own layout joined
with the window's view, facts and carried fields, written only into the records that change. A
paired server's partition passes through. A visited workspace main holds keeps its terminal row
(D1). The P10 pending case is on.
2026-10-18 03:00:49 -04:00
Jinwoo-H 672b641897 test(layout): the SSH binding test uses the shared spawn commit dependencies 2026-10-18 03:00:49 -04:00
Jinwoo-H beb2275b45 fix(layout): an SSH pane's terminal binds in its own session partition (dark, layout-owner build only)
Main keeps its own layout over a window save, so a binding only a save carries is lost. A window
or runtime spawn of an SSH pane bound in the local partition; it now binds where the pane's layout
lives.
2026-10-18 02:49:46 -04:00
Jinwoo Hong d4b3a65d52 fix(layout): main routes folders by the window's host rule and never stops layout frames (dark, layout-owner build only) (#30201)
* fix(layout): a folder spanning local and SSH repos routes to local and never stops layout frames (dark, layout-owner build only)

In a layout-owner build, main's router threw folder_workspace_connection_ambiguous for a
folder workspace whose project group mixes local and SSH repos. layout.apply for it was
rejected, and the same throw inside the layout stream failed the whole projection, so no
workspace got frames.

- Router (layout-owner build): a folder routes by its stamp, then its group's stamp (the
  window's save rule), else the shared resolveFolderWorkspaceHost; ambiguous maps to local,
  where the window already saves it. Terminal starts still refuse the ambiguity.
- Stream (layout-owner build): a workspace the router throws on is left out and logged once;
  every other workspace keeps its frames.

Window-owned builds are unchanged: the switch folds both branches away.

* refactor(folder-workspaces): move the window's folder host rule to shared (move only)

getFolderWorkspaceHostId moves unchanged from the renderer's folder catalog to src/shared/folder-workspace-execution-host.ts so main can route by the same rule. Its one renderer dependency, getProjectGroupHostId, is a direct alias of getRepoExecutionHostId, which the shared copy calls instead.

* fix(layout): main routes folders by the window's host rule and keeps a workspace's frame when routing fails (dark, layout-owner build only)

- Router: a layout-owner build routes a folder with the window's own rule (its stamp, its SSH
  target, then its group's host), shared since the previous commit. It reads no repos, so it
  cannot throw, and an SSH group holding a local repo now routes to SSH, where the window saves it.
- Stream: a workspace whose routing throws keeps its last published layout instead of being sent
  as removed, which would make the window drop its tabs.
- Stream: routing failures have their own logged-once flag, so they never hide a later
  projection or listener failure.
- One table of folder kinds is checked against both main's router and the window's save.
2026-10-17 23:32:41 -07:00
Jinwoo Hong 25fb579c12 fix(layout): refuse a layout change on a workspace a WSL move has paused (dark, layout-owner build only) (#30198)
* fix(layout): refuse a layout change on a workspace a WSL move has paused, and say why (dark, layout-owner build only)

* fix(layout): refuse without a toast; keep the move message in main
2026-10-17 23:26:38 -07:00
Neil 8209d301d8 test(runtime): record Electron vs orcad composition wiring and fail on undeclared differences (#30212) 2026-10-17 23:25:41 -07:00
Neil d4aa9dcadc revert: restore pinned npx skills installer (#30207)
Reverts #30185 so the separate installer project can proceed. The restored shared command already pins skills@1.7.2 for CLI, desktop updates, and setup commands.
2026-10-17 23:24:02 -07:00
Jinwoo Hong 95d6018323 Main keeps editor tabs under owned ids and in-place re-owns in step (dark, layout-owner build only) (#30206)
A restored tab re-owned inside its own workspace now tells main through
renameEditorFiles with the file's new record; main skips it for paired servers.
Main's load, save, close and tab-host read an editor tab's file by its owned id
as well as its path, behind the layout-owner switch.
2026-10-17 23:04:15 -07:00
Jinwoo Hong 31f766515d Main records when a workspace's default tabs were applied (dark, layout-owner build only) (#30176)
* feat(layout): main records a workspace's default-tabs mark from the window (dark, layout-owner build only)

* fix(layout): record the default-tabs mark after the tab creates it covers (dark, layout-owner build only)

* test(e2e): strict default-tabs mark and exact tab count across a crash (dark, layout-owner build only)
2026-10-17 23:02:05 -07:00
Jinwoo Hong b8fbfce3a6 Main repairs a terminal stored in two panes once at startup (dark, layout-owner build only) (#30178)
* fix(layout-owner): main repairs a terminal stored in two panes once at startup, after moving the dropped pane's owners (dark, layout-owner build only)

* fix(layout-owner): the load repair moves the dropped pane's records and skips the write when an owner move fails (dark, layout-owner build only)

* fix(layout-owner): the load repair leaves a paused WSL move's workspace untouched (dark, layout-owner build only)
2026-10-17 23:02:00 -07:00
Jinwoo Hong 483a17becc Reopening a file in its open tab sends the main process the changed file record (dark, layout-owner build only) (#30197)
* fix(layout): a reopen that rewrites an open tab's file record reaches main (dark, layout-owner build only)

* fix(layout): compare reopened editor records without a new renderer import
2026-10-17 22:58:06 -07:00
Neil 4baacca5c0 fix(startup): shell PATH probe falls back and retries when the shell cannot launch (#30204)
* fix(startup): shell PATH probe falls back and retries when the shell cannot launch

* chore: drop hydrate-shell-path from the process-host direct-import baseline
2026-10-17 22:54:54 -07:00
Neil ffb818bf61 Ship the locked skills installer instead of executing npx (#30185)
* security: ship a locked skills installer instead of running npx

* chore: remove retired skills process import exception

* test: include the locked installer in packaged layout fixtures

* test: reuse the real installer builder for package fixtures
2026-10-17 22:51:14 -07:00
Neil dbb84f4ad9 fix(ssh): move parked terminal history through the snapshot channel so a big saved buffer no longer blocks a host's move (#30126) (#30188) 2026-10-17 22:41:41 -07:00
Neil 1e95c037e0 fix(native-chat): say why the chat composer is locked and offer Take back when a phone holds the input (#30199) 2026-10-17 22:41:09 -07:00
Neil d93568368e fix(ssh): move the open workspace to the server's linked project when joining an existing server (#30189)
* fix(ssh): move the open workspace to the server's linked project when joining an existing server

* fix(ssh): follow the active repo and detected checkouts when rehoming a linked workspace

* fix(ssh): treat a missing server row as unknown, and keep watching for it
2026-10-17 22:40:20 -07:00
Neil b5fa888a93 fix(worktrees): stop CLI-created worktrees flashing into a filtered sidebar (#30194)
* fix(worktrees): keep a CLI-created worktree out of listings until its metadata is saved

A watcher-driven listing during `git worktree add` surfaced the new checkout as a bare
external row. The host's default-terminal request then made that stale row active, so it
slipped past Hide sleeping and Hide CLI-created until the next refresh hid it (~1s flash).

* fix(worktrees): hold canonical checkout paths during creation
2026-10-17 22:38:23 -07:00
Neil bbdbe72eba fix(runtime): paired clients list a folder-upgraded checkout under the host's id (#30190)
worktree.detectedList built its rows from the raw Git scan, so a folder project upgraded to Git
was published under Git's spelling (C:/x) while the host keyed its metadata and terminals by the
folder's (C:\x). Apply preserveFolderUpgradeWorktreePath at the runtime listing scan every
runtime listing reads.

Fixes #30150
2026-10-17 22:24:42 -07:00
Neil fa738f30bb fix(notebook): run cells only when the resolved owner is this computer (#30187)
A managed SSH or paired-server workspace has no SSH connection id, so the
notebook read it as local and ran its cells in the desktop's own Python
against a same-named local file. Derive the execution host from resolveOwner;
refuse remote, ambiguous and unloaded owners.
2026-10-17 22:19:55 -07:00
Jinwoo Hong b8264e860b Main drops the layout of workspaces the catalog no longer validates (dark, layout-owner build only) (#30177)
* feat(layout): main drops the layout of workspaces the catalog no longer validates (dark, layout-owner build only)

* rename the paired-host check so the switch-off bundle keeps its names

* a repo id two hosts register skips the listing purge
2026-10-17 22:19:35 -07:00
Jinwoo Hong e0abf71a62 refactor(layout-owner): one placement helper for drawn tab opens (dark, layout-owner build only) (#30174)
The chat, simulator, and browser tab recorders each computed where the window
drew a just-opened tab with the same lines. They now share drawnTabPlacement.
2026-10-17 22:19:16 -07:00
Neil 904259d122 fix(runtime): keep a restored unfinished agent unverifiable for the hydration window, not 30 minutes (#30186) 2026-10-17 22:14:38 -07:00
Jinwoo Hong aff4ee7ac7 feat(sidebar): main produces this host's workspace rows, checked against the window (dark) (#30184)
* feat(sidebar): main produces the local workspace rows, checked against the window (dark)

* fix(sidebar): workspace rows invalidate the listing only on metadata saves; prove it on the real cache

* fix(sidebar): workspace rows merge the listing fresh instead of invalidating the shared cache

* chore(sidebar): workspace rows comments say what the fresh merge reads
2026-10-17 22:10:09 -07:00
Jinwoo Hong b9b1b85261 test(layout-owner): an older session's moved editor tab gets its workspace's id on save and from the first frame (#30172)
Sessions saved before #29930 can hold a moved editor tab whose
worktree id still names the workspace it came from. Pin that the
saver writes the workspace's own id and that the window's tab carries
it after main's first snapshot. Tests only.
2026-10-17 22:09:10 -07:00
Max HsuandNeil c2188f66e4 fix(tasks): bound GitLab all-projects fan-out to avoid runtime queue overflow (#30157)
* fix(tasks): bound GitLab all-projects fan-out to avoid runtime queue overflow

The GitLab Tasks list started one listIssues/listMRs runtime RPC per selected repo at once. With 150+ projects this, combined with other callers on the same selector, overflowed the runtime RPC call queue and surfaced "Remote runtime call queue is full".

Fetch per-repo lists through mapSettledWithConcurrency with a limit of 6 (below the queue's foreground concurrency of 8), and stop starting new calls once the selection goes stale.

Fixes #30133

* test(tasks): assert merged GitLab rows without a type assertion

---------

Co-authored-by: Neil <neil@stably.ai>
2026-10-17 22:00:40 -07:00
Neil 6c45958c8c refactor(renderer): tighten the host-identity stack (#30124) 2026-10-17 21:34:47 -07:00
Jinwoo Hong 303c7c91ef fix(sidebar): main's temporal owner reads the catalog the way the window does (dark) (#30166)
* fix(sidebar): main takes its row baseline from the session's catalog and skips unchanged listings

* fix(sidebar): read catalog listings the way the window's merge does

* fix(sidebar): a seeding listing re-samples, and listings compare with the window's equality
2026-10-17 21:32:33 -07:00
Neil af056df751 refactor(projects): shrink twin-removal teardown to the attributed close actions (#30060) 2026-10-17 21:12:19 -07:00
Neil 98b4139e0b fix(sidebar): confirm before sleeping a workspace that another host's copy shares (#30047) 2026-10-17 21:00:08 -07:00
Jinwoo Hong bf97836ae0 Pane titles stay layout: the window stops writing tab names as pane titles, and main loads them as the window does (dark, layout-owner build only) (#30136)
* refactor(shared): move the pane title sanitizer to shared, unchanged

So main's layout Loader can apply the same rule the window applies on load.

* fix(layout): pane titles stay layout in a layout-owner build (dark)

The window stops writing a revealed terminal's tab name as its pane title,
and main's Loader drops a lone pane title that only repeats the tab's name,
as the window's load does. Both behind ORCA_LAYOUT_OWNER_IS_MAIN.

* fix(layout): the Loader compares a lone pane title with the tab bar's quick command label too (dark)

As the window's row hydration does when the row has no label.

* fix(layout): the Loader compares a lone pane title with the tab bar label, the live title (dark)
2026-10-17 20:59:57 -07:00
Neil 3d03c33f9d refactor(renderer): fold getExplicitRuntimeEnvironmentIdForWorktree callers into resolveOwner and delete it (#30059) 2026-10-17 20:47:18 -07:00
Jinwoo Hong 3aad2b17b0 feat(sidebar): dark phone feed of the sidebar inputs (sidebarInputs.read) (#30161)
* feat(sidebar): dark phone feed of the sidebar inputs (sidebarInputs.read)

* fix(sidebar): feed review: fresh read on ready, notices kept per revision, one flush owner, closed connections never subscribe

* fix(sidebar): feed skips values JSON cannot hold; a failed read forgets its notice

* fix(sidebar): name the feed batch key by where the batch starts from
2026-10-17 20:46:10 -07:00
Neil 1b3113de8e fix(ssh): a tab closed while a managed host is disconnected stays closed; deflake the shared-home spec (#30146)
* fix(ssh): a tab closed while a managed host is disconnected stays closed after Connect

#30130 made a user's Disconnect mark the host's managed server manually
disconnected, so the desktop now answers its calls itself with
runtime_manually_disconnected. The tab close path read that as the host's
answer and dropped the close instead of holding it for replay, so the tab
came back on reconnect. Treat it as an undelivered close, and route the
Disconnect sources to the managed-orcad Docker lane.

* test(e2e): close the disconnected host's tab the way a user does

The journey called the store's bare closeTab, which sends only terminal.close
and holds nothing; it passed only because the disconnected host used to be
redialed in the background, which #30130 stopped. Click the tab's X instead,
the path that holds and replays an undelivered close.

* test(e2e): the shared-home spec tells a host's own server from a PID that only collides

Each Docker host has its own PID namespace, so the PID host A records in the
login-home slot can belong to an unrelated live process on host B; kill -0
alone then read it as B running from A's slot. Count a recorded PID only when
its process runs from that slot.
2026-10-17 20:23:19 -07:00
Kelvin Amoaba 0c6e496613 feat(native-chat): mark each attached image as [Image #N] where it sits in the prompt (#28736) 2026-10-18 01:49:55 +00:00
Kelvin Amoaba 5c4c1edc64 feat(terminal): tell users once that the diff panel in a Claude pane is Claude's own (#29818) 2026-10-18 01:49:10 +00:00
Kelvin Amoaba 12f3089b9c feat(mobile): draw chat tool runs the way desktop does (#30135) 2026-10-18 01:48:36 +00:00
Jinwoo Hong ce2d60834c test(pty): the launch race join test no longer waits on real disk I/O (#30132) 2026-10-17 16:54:24 -07:00
Neil ba9c7eadbf Add Reveal in Finder to the file header menu (#30129)
* Add file location actions to the editor header

* Wait for the terminal spawn join before releasing race-test gates
2026-10-17 16:52:27 -07:00
Neil d71e3e9d45 fix(serve): orca serve on orcad serves the browser client and answers plain HTTP (#30120)
* fix(serve): orca serve on orcad serves the browser client and answers plain HTTP

orcad, the default local orca serve host since the compatibility launcher,
was never handed the app's web client directory, so its HTTP server had no
request listener: every GET hung and no Web client URL was printed (#30100).

The CLI now passes the app's unpacked out/web to orcad via --web-client-root,
a server without a web client answers plain HTTP with 404 instead of hanging,
and packaging fails when the unpacked web client or a file it loads is missing.

* test(serve): pin orca serve handing orcad the app's web client root
2026-10-17 16:51:37 -07:00
Jinwoo HongandClaude 0904ba0b8d fix(layout-owner): a background agent tab keeps its live title when another tab opens (dark, layout-owner build only) (#30131)
* fix(layout-owner): a frame rebuild keeps a background terminal's live agent title (dark, layout-owner build only)

The frame slice builder reuses restore's row hydration, which resets any
agent-activity title because a prior session's agents have exited. A
title main reports live for a running pane is not stale, so rows keep it.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(layout-owner): restore's row hydration skips the agent-title reset for live titles

Moves the live-title keep into the row hydration so the frame builder
adds no layout write of its own; restore passes nothing and is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-17 16:49:27 -07:00
Jinwoo Hong 45f7429600 Save-divergence detector: skip empty workspaces, see dropped tab-bar entries and kept pane trees (dark, layout-owner build only) (#30125)
* Save-divergence detector: skip empty workspaces, see dropped tab-bar entries and kept pane trees (dark, layout-owner build only)

- A workspace key that names nothing (or only places a stored closed-tab record) is no longer
  reported as "workspace added/removed" or "terminal row owner changed".
- A save that drops a terminal tab's tab-bar entry while keeping its row is reported, read from
  the stored session before the Loader rebuilds the entry.
- A pane tree main keeps over the window's (windowSaveForMain) is reported, so a window-side
  pane repair shows up.

* Detector: keep reporting empty-row flips, cover every overridden pane tree and one-sided closed tabs (dark, layout-owner build only)

* Detector: a save with no pane tree for a tab main keeps one for is reported too (dark, layout-owner build only)

* Detector: a closed tab record moved to another worktree in one save is reported (dark, layout-owner build only)
2026-10-17 16:49:24 -07:00
Neil 532cad2cb3 fix(renderer): destructive host callers refuse an ambiguous owner instead of reading it as local (#30035) 2026-10-17 16:42:43 -07:00
Neil 299dcb86fc fix(worktrees): a host-scoped purge leaves a surviving twin's tabs and edits alone (#30030) 2026-10-17 16:29:17 -07:00
Neil 27cfee6f7e fix(ssh): a Disconnect stays disconnected, and Settings and the status bar agree (#30130)
A user's Disconnect of an SSH host is now recorded for the session, and background
dials (a managed server's tunnel and status checks, census, host-resume recovery,
pane and automation restores) refuse it until an explicit Connect. Disconnecting a
managed host from Settings also stops its server's status checks, and the status
bar's Disconnect of a managed server also disconnects the SSH host it runs on, so
both surfaces read the same verdict.

Fixes #30086
Fixes #30085
2026-10-17 16:25:42 -07:00
Neil 965f88105e fix(sidebar): draw a project group once when two hosts publish it under one id (#30128)
* fix(sidebar): draw a project group once when two hosts publish it under one id

Moving a project to a managed server copies its project group there under the same id while the desktop keeps its copy. The row builder emitted a header per copy, so the second sat empty and both shared one virtual-row key.

Fixes #30045

* fix(cmd-j): search a same-id project group by the copy the sidebar shows

* fix(sidebar): reveal a same-id project group through the copy the sidebar draws

* fix(sidebar): reveal a folder workspace through the group parents the sidebar draws

* fix(sidebar): reveal from the host-filtered groups the rows were built from
2026-10-17 16:15:47 -07:00
Neil 8a3dd2866e fix(project-groups): say so when a project cannot join a group on another host (#30127)
A project's group membership is stored on the project's own host, and that host stores a group id it does not hold as 'no group' while still returning the row. Moving a remote-only project into a local group (menu or drag) therefore looked successful, and could even take it out of its current group.

The store now refuses a move into a group that only exists in another host's catalog, and reports failure when the host answers with the group cleared.

Refs #13699
2026-10-17 16:13:47 -07:00
Jinwoo Hong c2021ebc47 fix(layout-owner): main records a quick command tab's label on create (dark, layout-owner build only) (#30112) 2026-10-17 16:11:05 -07:00
Jinwoo Hong d9a61432c8 Main's layout Loader keeps one pane per terminal on restore (dark, layout-owner build only) (#30110)
* fix(layout): main's Loader repairs a terminal bound in two panes of one tab (dark, layout-owner build only)

* fix(layout): a window save stores main's repaired pane tree, so the duplicate-terminal repair survives the save (dark)

* test(layout): the SSH duplicate-terminal case builds an SSH-hosted tab
2026-10-17 16:03:56 -07:00