Commit Graph
14915 Commits
Author SHA1 Message Date
Neil 8f86ccf764 fix(ssh): refuse a migration request too large for the host's sealed frame before sending it (#30249)
A manifest under the 768 KiB validation cap can still overflow the host's 1 MiB inbound
frame once sealed (base64 adds a third), more so when a commit carries its blob list. The
host answers such a frame by closing the socket, so the move failed with a lost answer.
The catalog client now measures the request against REMOTE_RUNTIME_MAX_INBOUND_REQUEST_JSON_BYTES
and refuses it with the existing 'too large' guidance, unsent.
2026-10-18 00:50:59 -07:00
Brennan Benson 29a43a73ed feat(antigravity): sign Antigravity chats in with the server's own Google sign-in (#28650)
* feat(antigravity): sign this host's Antigravity chats in with the server's own Google sign-in

Start spawns the Antigravity ACP server exactly as a chat start would (pinned
runtime, private temp, owner-only chat folder), behind the launch gate that
first stops this host's running Antigravity chats, and asks it to authenticate
with oauth-personal. A host without a pinned server build refuses Start, as it
refuses chats. The server's sign-in line now yields its link (validated as
Google's sign-in page back to a loopback port here) instead of ending the
connection signed out. Link long-polls the flow's state (25 s, early on change),
Cancel ends it, a new Start replaces it, and it expires after 300 s. All run on
the execution host behind accounts.antigravity-chat-sign-in.v1 and need
accounts-admin. List reports chatSignIn {saved, signingIn}; saved is a stat of
the server's own token file, which Orca never reads.

* Retain unclosed sign-in children and detach ended polls

* Narrow sign-in regression launch fields

* Keep fake sign-in fixtures independent of host support

* fix(antigravity): chat sign-in never installs the server and keeps its flow on the shared revisioned state

Sign-in resolves the server exactly as a chat start does and fails with the
not-installed reason when no copy is found, instead of downloading one. Its
flow state is a RevisionedState, the same publish-and-wait primitive the
runtime installer uses; replacement, close proof and the Link wire are unchanged.

* fix(antigravity): the chat sign-in status names the running sign-in, so a client that comes back can follow and cancel it

chatSignIn gains an optional flowId while a sign-in runs. Before, a sign-in nobody watched held the
chats' fence for up to 5 minutes and no client could see or cancel it.

* feat(antigravity): clients follow this host's chat sign-in by revision, as they follow an install

* fix(antigravity): name the sign-in state apart from the sign-in function so the module parses

* fix(antigravity): chat sign-in status is pushed to subscribers, failures read as plain sentences

accounts.antigravityChatSignInSubscribe (no params) sends the full sign-in
status as a snapshot on subscribe, then one frame per state revision, and
closes with the transport. It replaces the accounts.antigravityChatSignInStatus
long-poll, its long-wait lane and the bounded revision wait, as the install
status already did.

A failed sign-in now tells the person what happened in plain words (no
subscription, account not eligible, not approved, not installed, or a
generic retry) and logs the raw error instead of showing it.

Stopping the running chats before a sign-in waits for every close to settle
before it reports, so the fence never lifts while a close is still running.

* feat(antigravity): finish a chat sign-in from the address pasted by hand

When the browser runs on another computer than the host (SSH or a paired remote host), Google's last page points at a port on the host that the browser cannot reach, so the sign-in never finished. accounts.antigravityChatSignInComplete takes that pasted address, checks it is Google's answer to this flow's own link (same loopback origin and path, one matching state, one code or error, no userinfo or fragment, a Google issuer if any), and sends it once to the server's listener on the host with a single direct GET. The flow shows a new verifying phase while the server finishes, and refuses a second paste.

* fix(antigravity): Cancel answers once the sign-in has unwound, so a chat sent right after it is not refused

* fix(antigravity): the sign-in reads its launch sources through the shared helper, keeping the session create support within its line limit

Main's file already sits at the limit, and the runtime method only forwarded to the helper.

* fix(antigravity): a rejected pasted sign-in address says what is wrong with it

Every bad address used to get one sentence. It now gets the specific one:
too long, not a complete address, not this sign-in's, not exactly one
Google answer, or not from Google. The checks themselves are unchanged.

* fix(antigravity): chat sign-in follows the server's answers and belongs to the client that started it

The host's chat sign-in status was a check that the server's sign-in file
existed, which says nothing about whether the sign-in still works. The
link came only from one printed line, a new Start from any device
silently replaced a running sign-in, and a second link replaced the first.

- The server's BROWSER is now a one-line helper run by Orca's own
  executable in Node mode, which prints the link on error output; it is
  checked before every server start, and the printed line is still read,
  on standard output as well as error output. No browser opens on the
  host, Windows included.
- A sign-in belongs to the client that started it. Others see it in
  progress without its link and cannot start, cancel or complete it; it
  ends on its own after five minutes.
- After Google answers, a session on the same server must start before
  the sign-in reads as signed in.
- The host's status is the server's latest answer: signed in when a chat
  session or the sign-in's session starts, signed out when a chat hits
  the sign-in prompt or is refused for sign-in, and unknown until then.
  Nothing is read from the sign-in file and nothing is saved.
- A second, different sign-in link fails the sign-in.

* test(antigravity): the launch parity record shows the sign-in link helper as the server's browser

* fix(antigravity): a sign-in owns its work until it has unwound, and reads only whole, valid sign-in lines

Problems in the previous round: a sign-in could read as finished while its
server or pasted-address request still ran, a server refusing a sign-in
after a chat started left the host shown as signed in, the checking
session stayed saved in the server's own store, and a broken sign-in line
could count as the server asking to sign in.

- The browser helper is POSIX only, with Node mode set inside the BROWSER
  command; Antigravity chats are not offered on Windows.
- Sign-in lines are read by source: standard output carries the printed
  line, error output the printed line and the helper's. Only a whole,
  valid link is an answer; a malformed one on error output is dropped, and
  on standard output it ends the server. Standard output goes through the
  protocol's own line reader, including a last unterminated line, and
  error output keeps a whole link while its diagnostic tail stays small.
- Any request the server refuses for sign-in marks the host signed out.
- A sign-in is the host's one operation from Start until its work has
  unwound; a Start before then is refused, and Cancel or expiry also stops
  a pasted address on its way to the server.
- A different second link fails the sign-in at any point, including while
  it is being checked.
- The checking session's saved conversation is removed once the server is
  proven gone, only when its metadata names the sign-in's own folder.
- A pasted address is checked for length before it is trimmed.

* Preserve ACP auth answer ordering and sign-in cleanup

* Fix ACP settlement lint and await sign-in cleanup in fixtures

* test: update Antigravity browser launch snapshots
2026-10-18 00:46:43 -07:00
Neil 06618fd572 fix(ssh): a connection never redials a host the user disconnected before its teardown runs (#30245)
The Disconnect is recorded synchronously but the teardown that disposes the connection waits
behind the target's lifecycle; until then a drop's backoff, a wake retry or reconnect() could dial
the host again. SshConnection now consults the same per-host record the connection manager does.
2026-10-18 00:44:13 -07:00
Brennan Benson fc925c3e9b fix(native-chat): Claude, Pi and ACP chats are Working only while the agent holds the send (#30134)
* fix(native-chat): Claude, Pi and ACP chats are Working only while the agent holds the send

Each adapter reports the sends it still holds (Claude's dispatch waiters, Pi's sends until
settlement, ACP's unsettled prompt and steers). A late settlement's write runs inside the
per-send handover window, so a send reads held until its row lands, and a failed write
reads as doubt at once. Removes the idle-release API and its callers.

* Fix interruption reporting from held send ownership

* Simplify ACP reading control cleanup registration

* Preserve provider child identity when reattaching

* Replay original attach in recovery overlap regression
2026-10-18 00:40:10 -07:00
Neil e958614303 fix(orcad): SSH host management on a server without the desktop app refuses with an accurate message (D3) (#30242) 2026-10-18 00:37:51 -07:00
Neil 1e4d65ea51 ci: path-literal check scans live gate references; historical gate commands move to currentCommand (#30252)
Gate evidence prose and evidence runs record what ran then, so the check reads only each gate's
commands and test files (baseline 53 -> 14). Four evidence-pinned historical commands that named
deleted tests are removed from their gates' commands and their runs point at the successor via
currentCommand, the manifest's existing mechanism. One live command drops a deleted updater test.
The managed-SSH catch-all route is renamed remote-sources and its test joins the route contracts.
2026-10-18 00:35:33 -07:00
Neil ed3ee7e08a refactor: name the vm transcript and mobile pending-write caps for what they count (#30251)
Both cap UTF-16 string length for local display and memory, never wire bytes, so _BYTES misled readers into treating them as consumer byte budgets.
2026-10-18 00:35:30 -07:00
Neil dcfbec0377 refactor(execution-host): one isLocalExecutionHost in shared (#30241)
Replaces the agent-hooks copy, a private wrapper and five inline parseExecutionHostId(x)?.kind === 'local' checks.
2026-10-18 00:34:36 -07:00
Brennan Benson bf56095bdd Session History: the scan line under the search box no longer jumps during a refresh (#30158)
* fix(session-history): the scan strip and the lines under it stop jumping during a refresh

The strip under the Session History search box dropped out for a moment on
every rescan (main cleared the entry before the new scan took over, and the
panel hid a finished scan until its list landed), on every worktree switch
(the new scan key had nothing yet), and the warning and error lines under it
hid while a refresh ran. Each blink moved the whole list up and back down.

Now a new scan takes over its key at once, a failed one puts back the last
finished scan, the panel keeps following the previous key until the new one
has progress, banners stay while the list they describe stays, and the error
line clears only when a refresh succeeds.

* style(session-history): collapse the banner line

* fix(session-history): keep the refresh hook under its line limit

* test(session-history): scan listeners no longer have a sent hook

* fix(session-history): retain truthful scan presentation through retries

* test(session-history): brace scan cache eviction loop
2026-10-18 00:30:34 -07:00
Neil e5e9fcad35 refactor(agent-status): the renderer's hydration cutoffs read main's status retention window (#30248)
ui-slice-hydration-sanitizers kept its own 7-day literal while its comment requires it to track main's HYDRATE_MAX_AGE_MS; both now read AGENT_STATUS_HYDRATE_MAX_AGE_MS.
2026-10-18 00:28:54 -07:00
Brennan BensonandOrca Worker a54fd3830e Antigravity install: one clear message in the chat, with the message box staying in place (#30001)
* feat(native-chat): a chat whose host has no program to run shows one clear install message, with the message box staying in place, disabled

A new chat replaces its Start-a-chat copy with an install message (what it is, its size, one Install button, then steps, progress and Cancel). A chat with messages gets a slim strip above the composer instead. Settings' row is unchanged.

* fix(native-chat): the install message drops its Settings hint until that Settings row exists

* fix(native-chat): satisfy the not-found lint on the install card's phase lookup

* fix(native-chat): the install message follows the design system: a still full bar once the download is done, and a plain ghost Cancel

* fix(native-chat): the install card's size caption uses the download-size string main already has

Main's Antigravity work added the same "downloadSize" key to the install strings, so each locale
held it twice with slightly different text. The card now reads main's one string, so the hero's
caption under its button ends in a full stop like the Settings row's.

* refactor(native-chat): the install row keeps only its Settings layout

A chat now shows its own install card, so nothing renders the row's chat layout any more: Settings
> Chat > Providers and the Antigravity accounts section are its only users. The row and its view
lose the surface choice, the chat-only heading string goes from every locale, and the view always
says and offers what Settings did.

* fix(native-chat): the install message points to Settings › Chat › Providers again, now that main has that row

Only chats on this computer show it: that row installs here, not on an SSH or paired host.

* fix(native-chat): a disabled chat box keeps its placeholder and dims, so it says why it can't take a message

The editor drew its placeholder only while editable, so an install-blocked or held box looked
empty and enabled. The plain text box already dims and keeps its placeholder.

* fix(native-chat): keep setup reachable and honor composer input availability

* fix(native-chat): update picker availability after commit

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
2026-10-18 00:28:19 -07:00
Neil 0d74111ee8 test(remote-runtime): pin the 12 hand-kept error-code lists to their callers' policy (#30246)
Each list that decides delivered / undelivered / recoverable / definitive by code now has a
test naming its codes, the message fragments it relies on, and nearby codes it must not
treat the same. Includes the #30146 shape: a client-minted runtime_manually_disconnected
keeps a user's close for replay. Tests only; no production change.
2026-10-18 00:24:34 -07:00
Neil 1de30d8235 test(e2e): the Windows CLI matrix convert cell calls the convert helper that exists (#30231)
convertThenRetire was never exported, so the spec failed to load; convertAndRetain is what the other upgraded-profile cells use. Also narrows the deployment union so the helper typechecks.
2026-10-18 00:24:22 -07:00
Neil a912265d47 ci: start the SSH host lanes for the SSH transport, the WSL orcad lane for orcad's WSL boot code, and cross-version cells for the WebSocket transport (#30239) 2026-10-18 00:23:29 -07:00
Neil 9c726af77b fix(sidebar): say a Linear task-status skip was for a multi-host workspace (#30243)
A twin whose owner is ambiguous was reported as 'Could not sync Linear issue', which reads as a Linear error.
2026-10-18 00:20:38 -07:00
Neilandzhangxaochen 720f45c8f7 Fix mobile Source Control rendering for large branches
Render committed branch changes as virtualized SectionList rows for clean and dirty working trees, keeping all files accessible without delaying Back. Share the existing sleek scrollbar rules with mobile web pages and retain explicit hidden-indicator settings.

Fixes #30170. Review reference: #30171; thanks to @zhangxaochen for the diagnosis and initial proposed fix.

Co-authored-by: zhangxaochen <zhangxaochen@163.com>
2026-10-18 00:20:23 -07:00
Jinwoo Hong 559ece08d3 feat(sidebar): the host that owns a workspace stamps its Recent and Smart keys (dark) (#30235)
* feat(sidebar): the owning host stamps sort keys on its workspace records (dark)

* fix(sidebar): sort stamps title phase switch is exhaustive

* fix(sidebar): sort stamps reconcile seeded tiers, respect host and WSL move fence, follow PTY swaps

* fix(sidebar): one clock read per sort stamp event

* fix(sidebar): a first idle title is not Done; the WSL fence spares SSH records
2026-10-18 00:16:28 -07:00
Neil e1eef1f162 refactor(terminal): one isRemoteExecutionHostPtyId, on prefix semantics (#30232)
The shared copy parsed remote: ids fully, so a malformed or newer-format id read as local
to pty-running-work-probe. The renderer copy already used the prefix check; it is now the
only definition, in src/shared.
2026-10-18 00:15:22 -07:00
Neil 3767047db0 feat(telemetry): report a legacy relay host active once a day while it bridges terminals (#30229) 2026-10-18 00:14:49 -07:00
Neil e6eaabb587 test(files): the native-ignore watcher test waits on delivered events, not a fixed sleep (#30236)
It flaked on loaded CI shards when a single write never reached the watcher. Files are now rewritten until seen, readiness is proven before the storm, and a sentinel written after the storm replaces the 300 ms debounce sleep. Disabling the ignores still fails it.
2026-10-18 00:10:44 -07:00
Neil 262a61703a ci(e2e): start the managed-SSH lane for every helper only its specs import (#30233)
* ci(e2e): route every helper only managed-SSH specs import to their lane, by import graph

* ci(e2e): normalize import-closure paths to / on Windows
2026-10-18 00:06:24 -07:00
Neil d3d6162f5c test(orcad): orca serve's argv makes orcad serve the web client and 404 other paths (#30120) (#30222) 2026-10-18 00:05:29 -07:00
NeilandClaude Opus 5.5 5c66b2ef63 fix(ssh): a late relay-era attach releases only its own viewer, never a successor's (#30219)
The legacy relay bridge counted viewers per PTY id and released them by PTY id. A pane whose
attach answered after it left (or after a reconnect replaced the bridge) handed its viewer back
by PTY id, so the release landed on the current bridge and dropped a successor pane's viewer:
that pane stopped receiving output. Each attach now returns an acquisition id (in-app IPC only;
the relay wire is unchanged) and detach releases exactly that acquisition.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 00:03:25 -07:00
Neil 7ede32ec12 ci: fail when CI config, workflows or e2e code name a src/ file that no longer exists (#30224)
* ci: ratchet src/ path literals in CI config, workflows and e2e code that name no file

* ci(path-literal): resolve relative imports exactly

* ci(path-literal): resolve against tracked files only; read ./src imports

* ci(path-literal): scan src/packages and src/types references too

* ci(path-literal): skip paths quoted in comments

* ci(path-literal): keep a recursive glob's boundary

* ci(path-literal): strip comments with a string-aware scan; any import occurrence is exact

* ci(path-literal): imports need a module or index; relative globs and folders stay prefixes
2026-10-18 00:02:58 -07:00
Neil f47337d852 refactor(worktree): one worktree path equality; the ipc copy folded WSL ext4 tails (#30227)
src/main/ipc/worktree-path-comparison.ts kept its own areWorktreePathsEqual and
dedupeWorktreesByPath. Its Windows branch lowercased a WSL UNC path's ext4 tail, so two
case-twin WSL checkouts merged into one row in removal safety, folder-upgrade dedupe and
the SSH listing fallback. Every caller now uses git/worktree-path-comparison, which gains
the macOS /private/tmp fold the ipc copy had. worktreePathComparisonKey keeps its exact
bytes (retirement namespace keys persist it) in worktree-path-comparison-key.ts, and the
worktree-logic re-export goes.
2026-10-18 00:02:29 -07:00
Neil b21cda129f fix(ssh): say when a managed server may be behind this app, and retry a failed update once per launch (#30218) 2026-10-18 00:02:07 -07:00
Neil 9085c5bb87 build(packaging): fail when orca serve's serve-selection entry or a chunk it requires is left in app.asar (#27404) (#30228) 2026-10-18 00:01:46 -07:00
Neil f0a69625ae docs(agent-hooks): ORCA_FEATURE_REMOTE_AGENT_HOOKS now only gates the WSL hook relay (#30223) 2026-10-17 23:51:51 -07:00
Neil 6afbe49c17 chore: delete unimported SSH, renderer and orchestration modules (#30214)
Removes modules with no importers on main (and their tests), the unused
RELAY_DEPLOY_TEARDOWN_TIMEOUT_MS constant, and the ssh-connection-utils
re-export of ssh-auth-resolution that only its own test used.
2026-10-17 23:47:51 -07:00
Neil 993fd20223 test(preflight): freeze the clock in the explicit-binary timeout test (#30221)
The budget is deadline - Date.now(), so a millisecond tick between the two reads made it 4999.
2026-10-17 23:45:27 -07:00
Neil 932dc1be29 chore(runtime): delete the never-served TLS branch of the LAN WebSocket server (#30220)
No released build ever passed a certificate to WebSocketTransport or set the pairing TLS
fingerprint; only ws-transport's own tests used tls-certificate.ts. The tests now run over ws://.
2026-10-17 23:44:42 -07:00
Neil 9810a5cc92 refactor(worktree): one comparison-only worktreeIdentityKey replaces three key wrappers (#30217)
worktreeIdComparisonKey (nullable '::' key), runtimeWorktreeIdentityKey ('\0' key) and
runtimeWorktreeLookupKey (JSON tuple) all folded the same path spelling. They become one total
key in shared/worktree/id.ts; a malformed id keys as itself. Also fixes id.test.ts literals that
were missing a colon, which made the WSL/UNC parity assertions compare null to null.
2026-10-17 23:43:55 -07:00
Neil 9a86d271dc chore(updater): delete the rollout-flag module nothing reads (#30211)
The nudge request parsed and stored a rollout block, but no build ever read a flag from it.
Drops the module, its call site, its tests, and the e2e env that fed it.
2026-10-17 23:38:45 -07:00
Jinwoo Hong 2a8b4c31a5 Phone and old-client tab lists keep editor tabs under owned ids (dark, layout-owner build only) (#30216)
With the layout-owner switch on, the session-tabs projection and the windowless host's editor
projection matched an editor tab to its file by path only, so tabs under an owned id got no row
(or lost their tab id, color and pin). Both now use the shared editorTabShowsFile matcher, which
is path equality with the switch off.
2026-10-17 23:35:10 -07: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
Neil 1e29bd1907 ci(e2e): route remote product sources without a hand-kept route to the managed-SSH lane (#30210) 2026-10-17 23:15:50 -07:00
Neil 553bde347a ci: simplify CocoaPods pin validation (#30208) 2026-10-17 23:09:25 -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 dcfe8c9e6c perf(typecheck): pin Bun as a devDependency and typecheck with it (#30149)
* perf(typecheck): pnpm tc uses the pinned Bun checker when available

bun check (Bun 1.4.3, TypeScript 7.0.2 parity, already used by CI) checks the
node project in ~29 CPU-s / ~2 GB peak vs tsc's ~98 CPU-s / ~16.6 GB. tsc's
incremental cache rarely helps agents: noEmit builds store no declaration
signatures, so the first edit to any file after a cold check re-checks every
transitive importer (a comment in src/shared/constants.ts re-checks all 18k files).

pnpm tc / tc:node / tc:web / tc:cli now pick the Bun from config/.bun-version when
it is on PATH and fall back to tsc with a one-line hint otherwise;
--compiler=native forces tsc. The pinned-Bun probe is shared with the
localization extraction check.

* build: pin Bun as a devDependency and make it the only default checker

The PATH probe left anyone without the exact pinned Bun (including a 1.4.2
global) on tsc's expensive path. bun@1.4.3 is now a devDependency, its
postinstall is allowed, and pnpm tc / typecheck:ci run that binary. A missing
binary is an error pointing at pnpm install rather than a silent fallback;
--compiler=native still selects tsc. A test keeps the devDependency equal to
config/.bun-version.

* ci: link the pinned Bun after the script-free install

--ignore-scripts leaves node_modules/.bin/bun as bun's postinstall stub, so the
typecheck runner found no binary and any pnpm-run script calling bun would hit
the stub before setup-bun's copy. pnpm rebuild bun runs only that allowed build.
2026-10-17 22:43:00 -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