Commit Graph
592 Commits
Author SHA1 Message Date
Jinwoo-H d85b2667d6 fix(pty): retry rejected SSH cleanup safely 2026-08-13 00:41:13 -04:00
Jinwoo-H fed1041170 fix(pty): retain rejected SSH split cleanup owner 2026-08-13 00:41:13 -04:00
Jinwoo Hong de729d6067 Fix paired web creation failure handling (STA-4024, STA-4025, STA-4063) (#14100) 2026-08-12 21:35:35 -07:00
m4air b115f8d256 Add Windows golden E2E test for fresh-startup regression
Windows terminal rendering golden is flaky on CI runners. Re-enable
Windows in the golden E2E gate with a scoped test for the fresh-profile
startup regression from #14130. Terminal rendering continues on Linux
and macOS; Windows runs fresh-startup only.
2026-08-12 21:28:32 -07:00
Jinwoo Hong d3a2bf352f fix(terminal): preserve Fish readiness escape bytes (#14142) 2026-08-12 20:55:29 -07:00
NeilandOrca c86418eaad rm git shim (#14141)
* rm git shim

Drops the terminal git/gh PATH wrapper and its settings toggle. Renames the no-marker shell-ready launch config after what it does.

Co-authored-by: Orca <help@stably.ai>

* rm git shim: clear stale state from older installs

Deletes the orphaned wrapper dir and scrubs inherited env/PATH, so a daemon that outlives the upgrade cannot keep seeding it. Drops a now-unread spawn option.

Co-authored-by: Orca <help@stably.ai>

* rm git shim: cover the daemon and headless paths

Scrub after the PATH prepends (they re-read process.env on the sparse daemon env) and run the cleanup above the serve branch so remote hosts get it too. Retry a locked removal; match PATH case-insensitively.

Co-authored-by: Orca <help@stably.ai>

* rm git shim: keep the scrub final

Refuse to re-prepend a legacy entry during agent-teams PATH promotion, which runs after the scrub. Cover the removal guard.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-12 18:53:17 -07:00
Brennan Benson cb41f3c5f4 fix(terminal): require agent identity for guarded sends (STA-4028) (#14092)
* fix(terminal): require agent identity for guarded sends (STA-4028)

Quarter-circle spinner glyphs (U+25D0-U+25D3) started classifying a title
as "working" in #13925, and that status alone authorized guarded agent
sends — which auto-submit with Enter — into any pane whose TUI animates
those generic progress frames.

Keep the glyphs as an activity signal, but stop treating a title whose
only agent evidence is a quarter circle as proof an agent owns the pane:
send authorization now falls through to recognized-agent identity in the
title or a recognized foreground process. Braille-spinner behavior is
unchanged.

* fix(terminal): preserve verified managed busy identity

* fix(terminal): bind busy identity to process incarnation

* chore(test): avoid duplicate terminal gate suite
2026-08-12 16:22:06 -07:00
Jinwoo Hong e8350f1990 fix(browser): route remote terminal links to owning host (#14117) 2026-08-12 16:15:39 -07:00
Jinwoo Hong d349f9a972 Use provider-neutral Opus alias in orchestration guide (#14119) 2026-08-12 16:03:29 -07:00
Jinjing e4c278eb52 Extract AutomationTimeField component with improved digit input (#13975)
* Extract AutomationTimeField component with improved digit input

Moves time parsing and selection logic into a reusable component
with enhanced UX: arrow key stepping, auto-commit on 2-digit entry,
and improved validation. Refactors AutomationSchedulePicker to use
the new component, reducing code duplication.

* fix(renderer): stop mutating clockRef during AutomationTimeField render

Move the prop→ref sync into useEffect so React Doctor no longer fails static analysis on ref writes during render. patchTime still updates the ref immediately for concurrent digit commits.

* fix(renderer): improve AM/PM toggle accessibility in AutomationTimeField

- Aria-label now includes current period (AM/PM) so screen readers announce which is selected
- Add aria-pressed attribute to communicate toggle button state
- Move translation keys to AutomationTimeField namespace reflecting component extraction

* fix(ci): retry Electron install on HTTP/2 stream and Fetch 503 errors

CI shards failed before tests when GitHub release downloads refused HTTP/2
streams or returned Fetch Response.status 503, which were not classified as
transient and skipped retries.

* fix(ci): give Electron package downloads more retry headroom

GitHub release CDN still returned 503 after the short 3-attempt budget under
CI fan-out; extend the default backoff so install can recover.
2026-08-12 14:40:39 -07:00
Jinwoo Hong 90b8554fc9 fix(terminal): recover readiness after startup exec (#14027) 2026-08-12 14:31:42 -07:00
Jinwoo Hong 70ad65fc94 Fix paired remote HTML browser ownership and focus (#13876)
* Fix paired remote HTML browser preview

* Register paired HTML preview reliability gate

* Scope browser worktree selection guard

* Harden paired HTML preview ordering

* Simplify paired HTML preview ownership

* Record final paired HTML preview evidence

* fix(remote): simplify browser preview ownership

* test(remote): refresh HTML preview evidence

* fix(remote): reconcile browser create ordering

* fix(remote): guard browser focus through reconcile

* fix(remote): bound delayed browser focus

* fix(remote): guard browser focus context

* test(remote): record final HTML preview evidence

* fix(remote): keep HTML previews in background

* test(remote): cover browser focus modes

* test(remote): record focused browser contracts
2026-08-12 02:02:10 -07:00
Neil 9c091cf77e chore(perf): add renderer agent-status benchmark harness (#13905)
Splits run-idle-cpu-benchmark.mjs into a scale fixture, an in-page timing
probe, and process sampling, and records a measured origin/main baseline so
the agent-status batching slice has an auditable before.

The agent-status write workload is not included: it needs setAgentStatuses,
so it lands with the store slice.
2026-08-12 00:37:48 -07:00
Jinwoo Hong fd2afc16c8 Fix paired web Add Project folder browsing (#13885) 2026-08-11 23:25:50 -07:00
Jinwoo Hong 7319d59a10 Make worker completion and cleanup authoritative (#13927)
* fix: require authoritative worker completion verdicts

* Harden federated settlement replay

* fix(orchestration): reconcile dead retained workers

* docs: record SSH worker release coverage

* test(e2e): exercise worker settlement and release CLI

* docs: register combined orchestration CLI oracle

* test(orchestration): pin pre-ack attachment state
2026-08-11 23:06:12 -07:00
Jinjing 5bee7b5ce9 P1 STA 3887 design Preview Kitty IME (#13940)
* fix(terminal): carry kitty flags through Preview snapshots and pair rele

Preview was omitting the live kitty mirror from the IME bridge and dropping kitty flags from snapshots, so every commit was evaluated at flags 0. A TUI that negotiated bit-3 (report_all_keys_as_escape_codes) would receive the legacy raw text it declined.

Now the snapshot carries proven kitty flags beside their sequence boundary, the forwarder reads flags once per commit, and bit-1 (report_event_types) commits are paired with exactly one release regardless of keyup/insertText ordering. Snapshot authorities expose only the active screen's proven flags, so an old host's absent field stays unknown rather than downgraded to a manufactured zero.

* fix(terminal): sync kitty flags and IME releases across snapshots

* trim wordinesss

* fix(terminal): settle owed IME release before fresh same-key press

When a keyup is lost and the same key is pressed again, settle the stale
record's owed release instead of discarding it — this maintains correct
IME state during recovery. Also refine Kitty flag propagation to only
carry proven baselines across snapshots, and tighten related comments.

* fix(terminal): gate kitty flags on sequence boundaries

- Remote snapshots only include flags when seq is present
- Daemon uses parsed flags value when defined
- Ensures correct flag ordering in snapshot replay
2026-08-11 22:00:44 -07:00
Neil 991a3fe963 chore(lint): update oxlint to 1.77 and enable no-op cleanup rules (#13901)
Enable eleven oxlint rules that simplify code without changing behavior, and fix
every existing violation. Each candidate was gated on measured cost rather than
assumption, so rules that regressed runtime performance or type checking were
dropped instead of suppressed.

typescript/no-redundant-type-constituents is the largest addition: 113 sites, no
autofix. Dead constituents are deleted. Where the redundant literal existed to
document intent (`string | 'all'`), it is preserved as `(string & {})`, which
keeps the autocomplete hint the original code was reaching for instead of
flattening it away. The rule also caught a broken import —
remote-shared-control-retirement-probe.ts pulled RuntimeStatus from
src/shared/types, which does not export it, so the type silently degraded to
`any`; no tsconfig covers that file, so tsc never saw it.

oxlint stays at 1.77.0 rather than 1.78.0 because .npmrc sets
minimum-release-age=4320 and 1.78.0 is younger than that window.

Rules evaluated and rejected, with what disqualified each:
- prefer-string-raw: String.raw is a runtime call, not a literal (184x slower)
- prefer-string-replace-all: 26% slower
- text-encoding-identifier-case: ~5% slower, reproducible
- prefer-spread: [...str] is 110% slower than split('') and differs on surrogates
- no-implicit-coercion: `!!x` narrows types and `Boolean(x)` does not (22 tsc errors)
- prefer-arrow-callback: arrows are not constructible, breaking `new` on mocks
- object-shorthand: rewrites source text asserted by a tracked reliability gate
- switch-case-braces: pushes ten files past max-lines, which cannot be suppressed
- no-useless-switch-case: drops `case undefined:` that switch-exhaustiveness-check needs
- arrow-body-style: 115 violations have no fix, and it breaks max-lines
- newline-after-import: false-positives on the leading-semicolon ASI idiom

electron-vite-output-contract asserted on the literal
Object.prototype.hasOwnProperty.call text; retarget it to Object.hasOwn, which
rejects inherited keys identically.
2026-08-11 18:19:43 -07:00
OrcaWinandBrennan Benson f226fcfc4b fix(claude): make managed hook paths portable (STA-3348) (#13442)
* fix(claude): make managed hook paths portable

* perf(claude): keep portable hooks shell-native

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-11 14:03:16 -07:00
Jinjing 17c57b7d20 Unpack OpenCode SQLite worker entry from asar (#13853)
The scanner service runs under ELECTRON_RUN_AS_NODE and cannot access
packed files in app.asar. Without unpacking, the worker entry fails to
spawn, causing all OpenCode sessions to disappear in packaged builds.
2026-08-11 12:51:29 -07:00
Jinjing 4c69e45552 Strengthen plain-node-entry-guard with entry name validation (#12761)
* Strengthen plain-node-entry-guard with entry name validation

- Add buildStart hook to validate guarded entry names exist in rollup
  inputs, preventing stale names from silently stopping guards
- Extend electron require detection to subpaths (electron/main, etc)
- Improve smoke test signal/exit handling and use constants
- Add comprehensive tests for entry validation and new behaviors

* Add SIGKILL escalation to plain-node-entry-guard timeout

Switch from spawnSync to async spawn to properly handle daemons that trap
SIGTERM. spawnSync's timeout only sends the signal and waits, so a daemon
that ignores SIGTERM causes the build to hang. The new runDaemonEntry
function escalates to SIGKILL after a grace period to enforce the deadline.
Configurable timeouts and grace periods via SmokeTimings type; closeBundle
hook becomes async to support the change.
2026-08-11 12:20:20 -07:00
OrcaWin c96ded8dfd fix(startup): restore Windows PATH before shell changes (#13792) 2026-08-11 11:50:21 -07:00
NeilandOrca 33e8d89d48 [perf-remote] perf(renderer): park hidden remote browser screencasts (#13608)
* perf(renderer): park hidden remote browser screencasts

* test(renderer): pin stale-visibility term and parked-unmount teardown

Restores the WHY behind the '|| isDocumentVisibilityProvenStale()' term the
emulator-module dedupe dropped, and pins it plus the close-tab-while-parked
path with tests. Extracts the lifecycle harness so the spec stays under
max-lines without a suppression.

Co-authored-by: Orca <help@stably.ai>

* fix(ci): exclude test-support modules from the localization audit

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-11 01:27:02 -07:00
Neil 0345d71214 refactor(renderer): split oversized TabBar module (#13739) 2026-08-10 23:43:10 -07:00
Neil fdaafc93dd refactor(renderer): split SettingsFormControls below max-lines limit (#13747) 2026-08-10 23:37:40 -07:00
Neil 4bb7e7d050 refactor(feature-wall): remove retired onboarding preview (#13489) 2026-08-10 21:07:41 -07:00
Neil e33863b2a9 refactor(onboarding): remove retired repository step (#13484) 2026-08-10 20:42:43 -07:00
Neil 6964f75cd0 refactor(renderer): share metadata list request lifecycle (#13524) 2026-08-10 20:40:26 -07:00
Neil 1979f5a3e3 refactor(linear): remove replaced team combobox (#13506) 2026-08-10 20:25:16 -07:00
Neil 9359edc2b0 refactor(workspaces): remove replaced host combobox (#13507) 2026-08-10 20:25:13 -07:00
Neil 837ea3feec refactor(onboarding): remove retired capability checklist (#13509) 2026-08-10 20:25:09 -07:00
Neil 7d1a17465e perf(computer-use): skip unused accessibility summaries (#13559) 2026-08-10 19:56:08 -07:00
Jinwoo Hong c7850eb59c fix(terminals): prevent retired workers from cold-resuming (#13708) 2026-08-10 19:49:34 -07:00
Neil 600b0b1c15 refactor(renderer): split WorktreeCard (#13715) 2026-08-10 18:45:11 -07:00
NeilandBrennan Benson 868bfbe8ce fix(terminal): release retained output slice parents (#13402)
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 18:19:10 -07:00
Neil 96c2cebfa6 refactor(mobile): extract terminal settings styles (#13706) 2026-08-10 17:52:45 -07:00
Brennan Benson 2ee43bfc0d fix(agent-hooks): refresh existing Orca launchers when agent CLIs are unavailable (#13378)
* fix(agent-hooks): refresh existing shared hook scripts when the CLI is no longer detected

A CLI that falls off PATH (moved npm prefix, relocated shim) keeps its user-wide
config invoking Orca's launcher script under ~/.orca/agent-hooks, but the
presence gate skips install() with no removal — freezing the script at whatever
Orca generated last. Anyone in that state kept the pre-#11568 more.com-leaking
.cmd forever, because no launcher script is ever deleted and Windows startup
deliberately skips shell PATH hydration.

Reconcile before gating: every existing shared launcher/statusline script is
rewritten to the current template on each install pass. Creating scripts stays
behind the presence gate — an existing file is proof of a prior install; a
missing one means the gate did its job. Amp and Hermes are deliberately absent:
they write provider-native plugin code with its own install lifecycle, not
shared launchers.

- refreshManagedScriptIfPresent() in installer-utils (no-op unless the file exists)
- refreshManagedScripts() on the 11 launcher-writing services (openclaude via
  the shared Claude class)
- reconcile pass in installManagedAgentHooks before presence detection,
  filtered by the agents option, best-effort per agent
- coverage gate: a launcher written to ~/.orca/agent-hooks without a matching
  refresher entry fails the suite, in both directions

* perf(agent-hooks): refresh launchers off the main thread

* test(agent-hooks): keep refresh mode assertion POSIX-only
2026-08-10 16:34:15 -07:00
Brennan Benson 6b9852af2b perf(terminal): remove output-driven WebGL atlas resets (#13657)
* perf(terminal): stop clearing glyph atlas on output

* test(terminal): gate output atlas reset removal

* test(terminal): harden atlas recovery gates
2026-08-10 16:10:47 -07:00
Brennan Benson 8da362919e perf(runtime): batch legacy worker recovery persistence (#13649)
* perf(runtime): batch legacy recovery persistence

* fix(runtime): preserve concurrent recovery state

* fix(runtime): require durable recovery retry
2026-08-10 15:58:17 -07:00
Brennan Benson d50adec2d2 feat(ai-vault): isolate scanning from terminal workloads (#13411)
* feat(ai-vault): isolate scanning in service processes

* fix(ai-vault): retire idle service processes

* fix(ai-vault): discard unverified cache processes

* fix(ai-vault): clear relay sidecar cancel watchdog on acknowledgement

A cancelled relay call is settled before its 2s cancel watchdog is armed, so the acknowledgement path bailed out of settle() before clearing the timer. The watchdog then faulted a healthy sidecar two seconds after every aborted scan, killing whatever request had since become active.

* fix(ai-vault): clear the pending restart before scheduling another

recordFault overwrote this.timer, stranding a restart that dispose() could no longer cancel.

* refactor(ai-vault): drop the orphaned first-prompt IPC wrapper

session-first-user-prompt-handler.ts now owns this entry point and routes through the service; the copy left in the read module had no callers.

* fix(ai-vault): retry a faulted cold start before surfacing it

A slow first start surfaced a raw 'did not become ready' error to the caller even though the supervisor was already respawning. Requeue an unsent call once onto the scheduled respawn instead.

Also stop arming the cancellation watchdog for a call the child never received: no acknowledgement is coming, so it killed a healthy service and stalled the lane.

Invalidation bookkeeping and ready-waiter construction move to the state module to stay under the max-lines cap.

* fix(ai-vault): give relay title reads their own lane

Before this branch the relay read title files directly, concurrently with scans. Routing both through one sidecar lane put title resolution behind a list scan that may run up to 130s, so SSH tab titles could lag minutes behind.

Split cache and interactive lanes in both the relay client and the sidecar entry, mirroring the desktop service.

Also: clear the ready deadline on fault, so a sidecar that dies before ready cannot fault its healthy replacement five seconds later; retry an unsent call once across a respawn; and skip the cancellation watchdog for a call the sidecar never received.

Restart/circuit bookkeeping moves to its own module, mirroring the desktop policy, to stay under the max-lines cap.

* fix(ai-vault): degrade relay title resolution on sidecar failure

listSessions already returns a host issue when the sidecar is unavailable; titles propagated the raw RPC error instead. Return no titles so callers fall back to preview text, and keep cancellation propagating.

* fix(ai-vault): scrub the service child environment

The children are forked with a 384 MiB heap cap and no loader, but both
spawn sites handed them the full parent environment, so an exported
NODE_OPTIONS silently raised the cap or --require'd code into them.

Allowlist both, following the plugin worker. The desktop child keeps the
eleven agent-root overrides it resolves its own roots from; the relay
sidecar takes remoteHome and hostPlatform from its init message and so
needs none of them. Both children share one priority module while they
share this one.

* fix(ai-vault): soft-disable relay vault when the service is missing

A missing service threw out of the constructor, so a Vault wiring bug
would abort relay startup and take every PTY on the host with it. The
unsupported-platform branch three lines above already treats a Vault
failure as a soft disable; do the same here.

Threading the service through the two handlers instead of a field also
retires the definite-assignment assertion the throw was propping up.

* fix(ai-vault): drain consumed cache invalidations

invalidatedPaths was re-applied in every request's finally and never
drained, so once N paths had been invalidated every later request paid N
evictions for the life of the process; the 4096 cap only bounded how bad
that got.

The re-apply exists to cover a read that overlapped the invalidation, so
drain once nothing is executing. Clearing unconditionally would drop the
re-apply for a request still running on the other lane.

* fix(ai-vault): keep a busy child through slow invalidation acks

invalidate() reused the 5s ready budget as its acknowledgement deadline
and killed the child on expiry, so a delete issued during a large scan
could kill a healthy process mid-scan and burn a slot toward the restart
circuit.

Fault only when nothing is executing. Fork IPC ordering already puts the
invalidation ahead of any later request, so a busy child owes no ack
here, and the 130s/15s request deadlines still catch a wedged one.

The start-retry predicate moves to the state module to stay under the
line cap, matching the shape the relay client already uses.

* fix(ai-vault): report a failed local scan as a host issue

A local-scope scan let its error escape to the renderer, which paints it
over the session list. Service supervision now produces those errors, so
"AI Vault service restart circuit is open." replaced the list.

Route local scope through the degradation the all-hosts leg and every SSH
leg already use, so it lands as a retryable host issue row instead. Same
result shape either way, so no IPC or wire contract changes.

* test(ai-vault): cover the relay restart circuit transitions

The relay policy shipped without tests. Pin both circuit edges, the
aging-out case, the forced-refresh reopen the relay has and the desktop
does not, and the backoff schedule.

* fix(ai-vault): keep the OpenCode roots in the service child env

The scrubbed allowlist dropped XDG_DATA_HOME and OPENCODE_DB, which the child
reads to locate the OpenCode store and database. The pre-PR worker thread
inherited them, so a user who sets either lost every OpenCode session.

* test(ai-vault): anchor the service spawn env assertion
2026-08-10 15:52:59 -07:00
Brennan Benson 84bd306949 perf: Stop unchanged worktree refresh churn (#13662)
* fix: stop unchanged worktree refresh churn

* fix: preserve smart sort telemetry recomputations

* fix: preserve duplicate worktree host identities

* perf: skip reconciled catalog traversal

* test: strengthen worktree refresh regressions
2026-08-10 15:44:05 -07:00
Jinwoo HongandNeil ec7e3ea477 fix(terminal): prevent paired activity renderer starvation (#13508)
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-08-10 14:32:08 -07:00
Jinjing c0c893d171 fix(pty): bound cooked reply queue (#13422)
* fix(pty): bound cooked reply queue

* fix(pty): bound cooked reply queue

Implement bounded storage for cooked-echo-safe replies: 64 pending
replies and 4096 UTF-16 code units. Shed oldest replies on overflow,
never ordinary input. Add drain failure containment with generation
fencing to prevent stale operations from clearing fresh input after
clear() reuse.

* fix(pty): report pty id in drain failures

When the async drain yields, the owner may rebind to a different PTY
before the failure surfaces. Pass the failing pty id so the transport can
ignore stale failures from a rebound owner. Also tighten the pending
reply queue size bound to prevent half-written entries.
2026-08-10 12:17:21 -07:00
Neil 131010277c [Perf-LH] Serialize relay JSON payloads once per publication (#13516)
* perf(relay): reuse serialized JSON payloads

* Defer bulk relay payload preparation until admission
2026-08-10 01:17:14 -07:00
Neil 75f5e2d964 perf(renderer): reuse prepared native chat messages (#13519) 2026-08-10 01:00:20 -07:00
Neil c5023fa0ab perf(main): skip impossible advertised URL scans (#13514) 2026-08-10 00:29:26 -07:00
Neil 8859e73980 perf(main): retire stale worktree marker probes (#13437) 2026-08-09 22:24:33 -07:00
Neil f2b2ece831 perf(renderer): reuse locale collators (#13444) 2026-08-09 22:24:09 -07:00
Jinjing 3b1017c4fb Add nightly cut (#13410)
* Add daily macOS dev build release channel

Publish once-daily signed macOS builds from main at a dedicated cadence,
separate from hourly (too noisy) and release branches (too infrequent).
Builds are notarized and installable via the updater, but unvetted —
published to stablyai/orca-daily rather than the main repo to avoid
evicting stable/RC entries from the releases feed.

* fix lint

* fix commit

* Add third token mint to daily macOS build workflow

The upload step's 2x45m retry budget can outlive the one-hour token, so a third
is minted after it for verify and cleanup operations. Release notes are moved to
a file to ensure consistency between draft creation and publish. Daily channel
description updated with specific UTC release time.
2026-08-09 19:01:35 -07:00
JinjingandOrca b075a95b06 Strip liveness gate from AI Vault session delete (#13279)
* Strip liveness gate from AI Vault session delete

Delete now requires only path validation + user confirmation — no process
roster, no liveness check, no quiescence, no ownership ledger.

Co-authored-by: Orca <help@stably.ai>

* Remove obsolete AI Vault liveness delete reliability gate

Session delete no longer checks process liveness, so drop the
manifest entry that still referenced the deleted test files.

* minor fix

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-09 18:40:01 -07:00
Brennan Benson 5df2ddbc9c perf(ai-vault): isolate tab title resolution (#13377)
* perf(ai-vault): isolate tab title resolution

* fix(ai-vault): preserve background scan caches

* fix(ai-vault): resolve nested worker from chunks
2026-08-09 16:45:52 -07:00