Commit Graph
15 Commits
Author SHA1 Message Date
Jinwoo Hong 5e342d7e1a fix(orchestration): a worker report during an Orca restart is not rejected as a changed identity (#41014)
* fix(orchestration): a worker report during an Orca restart is not rejected as a changed identity

* refactor(orchestration): share the startup bounded wait; skip long-poll checks

* chore(orchestration): drop casts in the restart identity wait

* fix(orchestration): only long-poll checks skip the restart identity wait

* fix(orchestration): ordinary mail never waits for the restart identity restore
2026-11-11 00:59:18 -05:00
Neil 83f8e6340d refactor(shared): organize file operations and storage owners (#39746) 2026-11-07 22:58:35 -08:00
Neil 3cb4853187 Keep dropped-macOS updaters on their last compatible build and explain why (#38777)
* Keep dropped-macOS updaters on their last compatible build and explain why

Stamp minimumSystemVersion into every mac update manifest from the built
app's LSMinimumSystemVersion, and refuse to publish an ungated release.
When the updater withholds a newer release for this macOS, show a one-time
notice and say so in Settings and the update card.

* Trim the unsupported-Mac notice copy
2026-11-05 18:29:16 -08:00
Neil 926f8bad13 refactor: organize terminal and runtime contract owners (#38011) 2026-11-03 19:56:34 -08:00
Neil 4b4c833e10 feat(window): working background opacity and blur on macOS, Windows and Linux (#36580)
* feat(window): working background opacity and blur on macOS, Windows and Linux

One window material model (opaque / translucent / blurred): macOS vibrancy without transparent, Windows 11 22H2+ acrylic, Linux transparent windows. Terminals paint their translucent background once, the transparent WebGL frame clears before drawing (#6491), and Reduce Visual Effects drops modal/backdrop blur and honors prefers-reduced-transparency.

* perf(window): drop hidden macOS vibrancy while a theme image covers the window

* refactor(settings): move Reduce Visual Effects into its own setting and search files
2026-11-01 01:41:07 -08:00
Neil 8f2e24f893 Revert "Warn macOS 12 users about upcoming support changes" (#36209) 2026-10-29 20:26:46 -07:00
Neil 3bae99a2bb Warn macOS 12 users about upcoming support changes (#36182)
* feat: warn macOS 12 users about upcoming support changes

* fix: use explicit border tokens in macOS support notice

* fix: route compatibility guides through the app link setting

* fix: balance support notice columns in narrow windows

* test: include macOS notice in suppressed feature-tip history

* Simplify macOS 12 notice and isolate compatibility checks

* Clarify Apple compatibility wording in macOS notice
2026-10-29 20:08:48 -07:00
den4ikandNeil 0afedab10d fix(lifecycle): keep UI listener failures from vetoing the shutdown checkpoint (#21029)
A throwing ui-changed listener (e.g. webContents.send on a destroyed
secondary window) propagated out of store.updateUI() during
app:stage-before-unload-sync and cancelled the shutdown checkpoint,
leaving the user unable to quit. notifyUIChanged now isolates each
listener, the ui:stateChanged broadcast skips destroyed webContents, and
the staging failure cause is returned to preload so the error toast
names it.

Fixes #20897

Co-authored-by: Neil <neil@stably.ai>
2026-10-26 09:15:45 -07:00
Jinjing a53c2a2a72 Add onboarding language selection (#31784)
* Add onboarding language selection and system locale detection

- Detect and synchronize native/browser language preferences safely
- Load catalogs before rendering onboarding and support recovery
- Let users choose a supported language or request another language

* Add onboarding language experiment cohorts and detection recovery

* Stabilize onboarding language detection tests

* Test persisted onboarding language cohort behavior
2026-10-21 19:43:22 -07:00
Neil 3f81541188 Support restarting Windows Orca as administrator (#28073)
* feat(windows): add administrator PowerShell terminal setting

* fix(settings): localize administrator terminal search keywords

* fix(windows): restrict elevated terminal host to Orca's runtime and requesting account

* fix(windows): harden administrator terminal routing, inventory and restore

* fix(build): build the Windows agent hook when electron-builder packages Windows

* fix(build): build the packaged Windows agent hook for the target architecture

* fix(windows): accept the development terminal runtime and test real elevation in CI

* feat(windows): show administrator status and restart instructions

* fix(settings): localize administrator mode search keywords

* test(settings): isolate the desktop permission section in shell picker tests

* Add Windows administrator restart and simplify Terminal settings

* Keep administrator restart silent and settings actions within narrow panes

* Keep Windows shell choices and permission guides usable at minimum width

* Prevent later restarts from replaying administrator terminal reset

* Fix CI route resolution and transient Windows fixture cleanup
2026-10-13 18:06:05 -07:00
Jinjing d997ef06f5 Warn on slow profile saves instead of failing them (#26447)
* Stop timing out slow profile-state writes; warn instead

Profile-state writes used to fault after 30 seconds. A stalled main loop or a slow disk could then drop the writer and show a "could not confirm your save" dialog, even when the write was still in progress. Slow requests now record a diagnostic breadcrumb and keep waiting for the worker's reply. Close waits for the worker to actually exit, and a termination request alone no longer counts as proof.

Pane-alias and migration-listener changes now save only their own sections, not a full state rebuild. Quit teardown also keeps the profile admission held until the final flush finishes, so a pending write is no longer released early at the deadline.

* fix tests

* Warn when profile saves run slow

Slow profile-state writes used to leave only a diagnostic log entry, so users had no way to tell that recent changes were not yet confirmed saved. The writer now reports when a save write passes the slow-warning threshold and reports recovery when the reply arrives. Writes are never failed or retried because of the delay.

- Main keeps the current delayed/healthy status and publishes changes to the renderer, so a reopened window gets the correct state.
- The renderer shows one persistent warning toast while a save is delayed and dismisses it on recovery.
- Observer errors are logged and do not interrupt saving.
- The web build reports saving as healthy because it does not use the desktop profile writer.

* Fix save-delay toast dismissal racing with a re-shown warning

The save-delay warning used one fixed toast ID. Sonner applies a dismissal
a frame late, so a dismissal could remove a warning that had just been
shown again with the same ID. The hook now tracks the ID of each delayed-save
warning it shows and dismisses only that toast. A new delay gets a fresh ID.

Add Sonner-level tests for remount, StrictMode cleanup, and recover-then-
delay races. Harden the e2e spec with a paused clock and a retry around
main-process evaluate.

* Report slow profile revision checks and exports as save delays

Revision checks and JSON exports run on the same profile-state worker as
saves, so a slow one holds up later writes just like a slow write does.
The save-delay warning only tracked write-* commands, so those stalls
went unreported. Every command except initialize and close now raises
the warning.

Tests cover the export-latest path and assert the delay signal fires
once with true before clearing.

* Clarify slow-save toast to name profile storage

The delayed-save warning said recent changes were not yet confirmed saved, which overstated the risk while Orca was still retrying. The real condition is a slow profile-state write, so the toast now names profile storage and says later saves may wait until that operation finishes. The copy is updated in every locale, and the unit and e2e tests that assert it are updated to match.
2026-10-08 11:01:04 -07:00
Brennan Benson 757736628f fix(native-chat): a paired server admits structured chat by client capability, not its own chat setting (#24203)
* fix(native-chat): a host admits structured sessions by client capability, not its own chat setting

A host's experimentalStructuredNativeChat decided whether any paired client could reach
agentSession.* at all, and whether session.tabs.* showed it structured tabs. That setting is the
host user's own launch preference: whether a new agent opens as a chat or a terminal is decided by
whoever launches it. Using it as admission control meant a client whose own preference was
"structured chat" was refused on a host whose preference was "terminal", and chats opened while
the setting was on were withheld from mobile once it was turned off.

The gate now asks one thing: did the client advertise agent-session.structured.v1 (in-process
callers negotiate nothing and are always admitted). Tab projection and restore follow the same
rule. With the setting no longer gating anything, the separate cleanup gate (close, cancel,
unsubscribe, release), which existed only so those kept working after the setting was switched
off, is identical to the main gate and is folded into it. The settings listener that republished
tabs when the setting changed is removed, since projection no longer depends on it.

The host setting still picks the default for launches that start on the host itself
(agent.launch from mobile, orchestration worker-start).

* fix(native-chat): negotiate client-chosen launch mode so released phones and old servers keep terminals

Hosts advertise agent-session.structured.client-launch-mode.v1: they admit
structured sessions by client capability alone. A remote client that does
not advertise it (phones released before agent.launch) asks createSupport
to pick the launch mode, so the host keeps answering that with its own
setting, exactly as before. Cleanup methods keep their own named gate so a
future admission condition cannot make close or cancel refusable.

* chore(native-chat): justify the two type assertions this change's lines touch

* fix(native-chat): chats that already exist keep showing whatever the chat setting says

The structured chat setting decides only what new agents open as. With it
off, this machine's structured chats used to be hidden while the host,
which no longer reads the setting, still reported them to the workspace
activation gate, so a workspace holding only a chat opened empty. The
local chat mirror and its startup restore now run whatever the setting
says, the continue-after-restart offer follows the chats that exist, and
the setting's copy says it applies to new agents.

* test(native-chat): pin that a host advertises the client-chosen launch mode

* fix(native-chat): mirror this machine's chats only where it holds them

Round 1 ran the local chat mirror for everyone so existing chats show
whatever the setting says. That gave every desktop a permanent
session-tabs listener, which turns on the runtime's phone replication
paths, plus two full session-tab censuses at startup, and made the
browser client mirror its remote host a second time.

The runtime now says whether it holds structured chats: its structured
host is built only when saved chats were restored at startup or a client
created one here, and it announces the moment one is built. The mirror,
the startup restore and the continue-after-restart offer run only when
the setting launches chats or the host holds some, and never in the
browser client. A chat a paired client creates here with the setting off
still appears at once. The chat behaviour settings show wherever chats
exist, and the setting's copy says it picks what new agents open as. The
toggle-off teardown this made dead is removed.

* test(native-chat): record install listeners without a cast

* fix(native-chat): mirror this machine's chats only once it holds one, not once its host is built

Session history, resume preparation, terminal resume commands and replay-safe phone launches all
build the structured host for users who never had a chat, which turned on the chat mirror and the
structured-only settings rows until the next restart. The signal is now derived from the host's
records (or a records file still owed its import) and pushed when the first chat is restored or
created. A throwing listener no longer fails the install that fired it.

* feat(native-chat): createSupport reports the saved selection a new chat on this host starts with

A chat on a paired server starts with the server's saved model and options, which the desktop could
not read, so its picker showed a guess. createSupport's answer, which the desktop already waits for
before a paired launch, now also carries that seed as a new optional field (older clients ignore it).
Create and createSupport read it through one resolver so they cannot drift.

* refactor(protocol): move the Electron remote client capability list into its own module

Merging main left protocol-version.ts one line over the max-lines limit on this branch. The list of
capabilities the desktop advertises to a paired host moves, unchanged, into
electron-remote-runtime-client-capabilities.ts, the module the next PR in the stack already uses
for it; importers point there.

* test(cross-version): stub the launch seed resolver createSupport now reads

* fix(native-chat): the desktop tells its own host it picks each launch mode, so retrying an existing chat works with the setting off

* docs(native-chat): name the real exit for the released-phone createSupport rule

* test(cross-version): a released client still gets the host-setting createSupport answer; a launch-mode client gets supported plus the seed
2026-10-01 18:55:32 -07:00
Neil b00ec20731 perf(startup): stop an unreachable SSH host from gating local terminal restore (#18164)
* perf(startup): stop an unreachable SSH host from gating local terminal restore

An asleep or unreachable SSH target held the terminal-restoration gate for the
full 15s reconnect timeout, so no terminal restored — local ones included.
Startup now awaits only the target that owns the active workspace's tabs and
lets the rest connect in the background, folded into the existing deferred path
that reattaches their PTYs on tab focus.

Also splits the renderer's git-environment fence out of the first-window PTY
services barrier: worktree hydration needs shell-PATH generation and the managed
WSL CLI registration, not a daemon PTY spawn or a hook-server bind. Terminal
restoration still fences on the first-window services via
app:prepareTerminalStartupRestoration.

Measured with tests/tools/benchmarks/startup-time-bench.mjs (382 restored tabs,
28k-file profile, medians of 3):
  unreachable SSH host: 17.27s -> 1.34s to renderer-startup-hydration-done
  all-local:             1.98s -> 1.33s

* fix(startup): restore the startup-ordering oracle and keep a connected background SSH target undeferred

app-startup-routing.test.ts pinned the old step names, so the two ordering cases
went vacuous-then-red when the barrier split. Repoint them at the steps that now
carry the same fences: 'git-environment-barrier-await' (shell PATH + managed WSL,
the fence host Git needs) before hydration worktrees, and
'prepare-terminal-startup-restoration' (which awaits firstWindowStartupServicesReady
in main) before terminal reconnect. Both still fail against main's hydration source.

Also: the timed-out-eager rewrite of the deferred list re-added background targets
that had already connected, undoing removeDeferredSshReconnectTarget and sending
fresh panes on a reachable host down the cold-restore path.
2026-09-02 13:10:02 -07:00
Neil 401664298f fix(preload): make a dropped bridge key a compile error
The split silently dropped jira.searchUsers and
runtimeEnvironments.retryControlConnection. Neither failed typecheck: the bridge
modules carried no satisfies annotation and the composed api object was
unannotated, so a missing key was only a runtime TypeError in the renderer.

Annotates each module against PreloadApi, the type window.api is already
declared as, so the contract supplies the shape rather than a parallel copy.
Deleting jira.searchUsers now fails with TS2741 naming the key.

Turning this on surfaced 106 places where a bridge locally annotated
Promise<unknown> or unknown[] over a contract that declares concrete types --
the bridge was erasing types the renderer relied on. Those annotations are gone.

Also exposes app.awaitBeforeUnloadCheckpoint, which was declared and called but
never actually on the bridge, so the lazy-chunk recovery reload optional-chained
to a no-op and navigated without joining the checkpoint. The missing key was
caught by the new annotation rather than by hand.
2026-09-01 18:24:49 -07:00
Neil d1abe28471 refactor(preload): split bridge API modules
(cherry picked from commit b77e31873b)
2026-09-01 00:57:54 -07:00