Commit Graph
2967 Commits
Author SHA1 Message Date
Brennan Benson de06dbb4f2 fix(sidebar): preserve folder workspace owner identity 2026-08-10 16:22:43 -07:00
Brennan Benson 0c9cbcb678 fix(sidebar): close remaining project group owner gaps 2026-08-10 15:45:54 -07:00
Brennan Benson dfdc6d1c63 fix(sidebar): preserve project group owner interactions 2026-08-10 14:51:25 -07:00
Brennan Benson 2e0c0c0332 fix(sidebar): reject stale folder owners 2026-08-10 13:13:38 -07:00
Brennan Benson cd7cf2fd17 fix(sidebar): fail closed on ambiguous folder owners 2026-08-10 13:00:54 -07:00
Brennan Benson 253f8c3f9e fix(sidebar): narrow owner-qualify same-id group identity
Disambiguate multi-host project groups and folder workspaces only at
catalog normalize, store CRUD, sidebar row keys, activation dual-read,
IPC, persistence, and filesystem-auth. Keep bare IDs when unambiguous
(including folder:folder-workspace-1); fail closed on collision. Leave
#13611 sticky geometry untouched and drop broad WorktreeCard/dashboard
session-routing propagation from the prior 66-file tip.
2026-08-10 12:30:33 -07:00
Neil 158b575680 perf(orchestration): coalesce drift probes per dispatch tick (#13592)
* perf(orchestration): coalesce drift probes per dispatch tick

* fix(orchestration): preserve capacity after drift refusal
2026-08-10 05:56:01 -07:00
Neil 6206945c07 fix(native-chat): harden paginated history metadata (#13573) 2026-08-10 05:55:29 -07:00
OrcaWinandOrcaWin fb3a3c5643 perf(native-chat): probe WSL transcript paths asynchronously (#13265)
* perf(native-chat): probe WSL transcript paths asynchronously

The WSL transcript resolvers probed `\wsl.localhost` UNC candidates with
existsSync. Those paths are served over 9P, so a stopped or unreachable distro
blocked the Electron main thread instead of falling through to the next
candidate.

- host-readable-transcript-path: the `pathExists` dep is now async, defaulting
  to fs/promises.access. The per-distro loop stays sequential — the ranked order
  exists so the owning distro wins, and probing every distro at once would fan
  9P calls out to ones the user deliberately left stopped.
- session-file-resolver: dropped the existsSync guard outright rather than
  converting it. walkSessionFiles already yields [] for a missing or unreadable
  root, so the guard was redundant as well as blocking.

* perf(native-chat): stop the resolve poll mkdir-ing the Codex runtime home

codexSessionsDirs() only needs the managed home's path to scan it, but called
getOrcaManagedCodexHomePath(), which mkdirSyncs. That put a synchronous fs call
back on the 500ms-5s resolve poll the surrounding async probe work just cleared,
and materialized the runtime home as a side effect of a read-only lookup.

Use the resolve-only variant the module already exposes for this case. A missing
root walks to no matches, so behavior is unchanged.

* perf(native-chat): gate WSL transcript fs access behind a shared queue

Serializes and dedupes WSL 9P filesystem probes (access/readdir) so a
stopped or slow distro can't exhaust the shared libuv threadpool or
block unrelated local filesystem work. Routes Codex session-tree scans
and path-existence checks through the new wsl-transcript-fs-gate,
while sharing in-flight scans across concurrent callers.

* perf(native-chat): prioritize exact WSL transcript probes over scans

- Add cancellation (AbortSignal) throughout session resolution and
  directory walking so an unsubscribed transcript watch stops
  in-flight WSL filesystem work instead of leaking it.
- Split the WSL fs task gate into exact vs scan priority lanes with
  per-route concurrency, so a live transcript access probe is never
  queued behind a directory scan on another distro/provider.
- Extract Codex WSL session path scanning into its own module that
  shares one root snapshot across concurrent session-id lookups and
  refreshes on a shared miss to see post-start file creation.
- Skip the async WSL probe entirely for local paths via existsSync.

* fix(native-chat): harden WSL transcript cancellation

* fix(native-chat): finish transcript cancellation

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-10 02:19:16 -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
d305e48547 fix(gitlab): guard against non-array API responses in MR/issue listing (#12911)
* fix(gitlab): guard against non-array API responses in MR/issue listing

fetchIssuesAsWorkItems and listMergeRequests parsed glab's JSON output
and called .map straight on it. When the GitLab API returns a JSON
object instead of an array (error body, unexpected shape) on a
successful exit, this crashed with a bare TypeError that got
misclassified as "Failed to load issues: JSON.parse(...).map is not
a function" instead of a useful message.

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

* fix(gitlab): cover listIssues and keep payloads out of error classification

The guard missed listIssues in issues.ts — the RPC-backed issue list that
produces the reported "Failed to load issues: JSON.parse(...).map is not a
function". Hoist the guard into glab-api-response.ts so both files share it.

The thrown message is fed to classifyGlabError, which substring-matches it.
A response payload is content, not a diagnostic: an MR titled "fix network
timeout" classified as network_error and the canned copy replaced the payload
the user needed. Report a GitLab error envelope by its own message, and mark
an opaque body so classification is skipped.

* test(gitlab): make the list-guard tests fail on the regressions they name

Two assertions were vacuous under mutation. The envelope test used a "403
Forbidden" message whose keyword matches earlier in the classifier chain than
its sibling payload, so leaking the payload into classification still passed;
it now uses a 404 envelope beside a "403 forbidden" sibling. No call-site test
carried a classifier keyword, so deleting the marker-error branch entirely
failed only one unit test; the MR API path now uses a keyword-bearing body.

Also give the non-list branch the same "Failed to load issues" prefix as every
other list error, cover the `{ error }` envelope field, and pin the thrown type.

* test(gitlab): pin the reported-payload bound

Removing the 300-char slice survived the whole suite, and the banner's
break-words now depends on it. Name the limit and assert both branches
truncate, plus the envelope falling through a blank message to `error`.

* test(gitlab): pin message-over-error envelope precedence

Swapping the lookup order passed the whole suite. Anchor the bound regex too
so it cannot match an incidental ": " near the end of a message.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 01:10:12 -07:00
ce3ec4d5ce fix(repo-icon): keep a renamed fork's own owner avatar (#12271)
* fix(repo-icon): keep a renamed fork's own owner avatar

Fork repos always took the upstream owner's avatar, so a renamed fork
showed its parent project's logo. Same-name forks (personal copies)
still prefer the upstream owner; renamed forks now keep their origin
owner across auto-detect, the startup backfill, and the settings
avatar refresh.

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

* fix(repo-icon): re-read repo state before backfill avatar write

The startup backfill computed icon updates from a pre-loop snapshot, so
an icon chosen in settings while the upstream/origin probes were pending
could be clobbered. Re-read the repo after the probes and only migrate
an icon that is still the auto-detected GitHub avatar.

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

* refactor(repo-icon): own the fork avatar rule in one shared selector

The renamed-fork rule was written out twice — once in the main-process
auto-detect and once in the renderer refresh — so the two copies could
drift. Move it next to `githubAvatarIcon` as `githubAvatarSlug`, which
collapses the renderer resolver to a single unbranched path.

Also stop swallowing a rejected origin probe: it cannot tell a renamed
fork from a same-name one, so degrading to the upstream owner would flip
a renamed fork's stored avatar back to the parent's. Letting it propagate
keeps the stored icon, matching how the non-fork path already behaved.

Adds coverage for the startup backfill, the third decision point the fix
claims, which had none.

* test(repo-icon): cover pending backfill icon change

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 01:06:32 -07:00
Neil c5023fa0ab perf(main): skip impossible advertised URL scans (#13514) 2026-08-10 00:29:26 -07:00
Jinjing f5d934a3f5 3c5f0060 (#13496)
* refactor(runtime): extract pure path-candidate, review-branch, and folder-workspace helpers from orca-runtime.ts

Mechanical move of three closed, pure module-scope clusters out of
orca-runtime.ts (37,608 -> 37,207 lines) into domain-named siblings:

- terminal-output-path-candidates.ts: PTY output path harvesting and the
  recent-candidate history bound (3 entry points + 15 private callees).
- selected-review-branch.ts: forge-agnostic selected-review predicates and
  lookup hints (GitHub/GitLab/Bitbucket/Azure DevOps/Gitea).
- runtime-folder-workspace.ts: folder-workspace id math and the repo+meta
  -> Worktree projection.

Bodies are token-identical to their previous form; the only production
changes are the moves, the new import statements, and `export` keywords.
The no-control-regex suppression travels with the path-candidate scanning
that needs it. No max-lines suppression was added and the ratchet is
unchanged.

Adds characterization tests for the two clusters that had no direct
coverage; the path-candidate cluster keeps its existing tests, repointed
at the new module.

* fix flaky timer on CI
2026-08-09 23:37:33 -07:00
Neil 73efab98f7 perf(orchestration): keep drift Git off main thread (#13440) 2026-08-09 23:26:28 -07:00
Neil 016df33f00 fix(github): complete PR reactions for CodeRabbit reviews (#13456)
* feat(github): add PR comment reaction controls

* feat(github): add full PR comment reaction picker

* fix(github): cover all reactable PR comment paths

* fix(github): reconcile comment reactions with main

* fix(github): preserve focus on failed reaction removal
2026-08-09 23:14:17 -07:00
Brennan Benson d6362deb04 feat(agent-hooks): support Prime Agent status in WSL (#13430) 2026-08-09 22:55:32 -07:00
Neil 7dce0442ab Add Caffeinate controls to the status bar (#13480)
* feat: add caffeinate status controls

* refactor: compact caffeinate status

* fix: harden caffeinate readiness
2026-08-09 22:52:11 -07:00
Neil 8859e73980 perf(main): retire stale worktree marker probes (#13437) 2026-08-09 22:24:33 -07:00
Jinwoo HongandJinwoo-H 158212b8b3 feat(github): add PR comment reactions (#13470)
* feat(github): add PR comment reactions

* fix(github): harden comment reaction updates

---------

Co-authored-by: Jinwoo-H <Jinwoo-H@users.noreply.github.com>
2026-08-09 22:11:54 -07:00
Jinwoo Hong d9e84d88ef fix(persistence): salvage corrupt workspace session entries (#13431) 2026-08-09 21:39:24 -07:00
OrcaWinandOrcaWin bdd763188f Fix Windows AI Vault resumes using the wrong shell (#13420)
* fix: use project shell for AI Vault resumes

* fix: preserve WSL cwd fallback semantics

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-09 19:52:16 -07:00
Neil f3ea376b6b refactor(rate-limits): share initial account target policy (#13428) 2026-08-09 19:06:07 -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
Neil 934faaec76 refactor: deduplicate Linear team readers (#13417) 2026-08-09 18:54:22 -07:00
OrcaWin 75650936f4 fix(source-control): hydrate Windows shell profile PATH (#13418) 2026-08-09 18:42:15 -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
Neil ced2719b26 refactor: remove unreachable code (#13400) 2026-08-09 18:29:32 -07:00
Brennan Benson b2e29a2247 Fix Ctrl+Z in Windows and Linux terminals (#13398)
* fix(terminal): preserve Windows undo chords

* fix(terminal): keep undo menu hints unregistered
2026-08-09 18:14:39 -07:00
Brennan Benson 1d3decdbc4 Fix native chat history across transcript formats (#13393)
* fix(native-chat): restore transcript history across formats

* fix(native-chat): preserve safe Codex history metadata
2026-08-09 17:19:54 -07:00
Brennan Benson c03c01ad15 fix(browser): stop impersonating the source browser's UA on cookie import (STA-3514) (#12849)
* fix(browser): stop impersonating the source browser's UA on cookie import (STA-3514)

Delete the import-time UA synthesis entirely instead of patching its version
detection. The session now always keeps the engine-derived UA the registry
sets at startup (clean or native), for imported and non-imported profiles
alike.

Why deletion is the fix:
- The synthesis read CFBundleShortVersionString, which on forks is a
  marketing version — Arc imports presented Chrome/1.x and sites rejected
  the browser as ancient (STA-3514).
- Its stated purpose (keep Google-bound cookies valid) is handled by
  isGoogleSourceBoundCookie excluding those cookies since #736, and #12884
  measured that Google rejects re-transplants regardless of UA identity.
- #12608 measured the synthesized Chrome-shaped UA reaching
  /v3/signin/rejected while the engine UA reached account lookup.

Persisted userAgent/userAgentByPartition meta is no longer read; legacy keys
drop off on the next meta write. The #12811 gate existed only to catch bad
synthesized values, so it leaves with the synthesis.

* test(browser): catch source UA impersonation regression
2026-08-09 17:05:00 -07:00
Brennan Benson 7aae88cd21 Fix terminal select-all and copy in Kitty-enabled TUIs (#13388)
* fix(terminal): handle select-all in Kitty TUIs

* fix(terminal): preserve popout native selection
2026-08-09 16:52:13 -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
Brennan Benson a1f61ef8c0 feat(agents): add Prime Agent status hooks (#13384) 2026-08-09 16:45:27 -07:00
Brennan Benson 774bbc788f fix(terminal): preserve OSC 8 links across cold parking (#13382)
* fix(terminal): preserve OSC 8 links across cold parking

* test(terminal): make OSC 8 e2e cross-platform

* test(terminal): focus OSC restore e2e on activation
2026-08-09 16:36:12 -07:00
Brennan Benson 44cccb8cd9 fix(agent-hooks): accept BOM-prefixed hook configs (#13383) 2026-08-09 16:35:57 -07:00
Jinjing d23dda6d48 Move Linear issue view to localStorage (#13391)
Prevent older paired hosts from discarding the entire taskResumeState
when they encounter the strict linearIssueView field, which was causing
silent loss of github and jira queries during remote pairing. Layout,
grouping, ordering, and per-workspace filters are now device-local.
2026-08-09 16:35:24 -07:00
Jinwoo Hong 6397668271 Add manual artifact sharing from HTML and Markdown views (#13369) 2026-08-09 16:11:16 -07:00
eacba6654f fix: pr-bug-scan validated finding from #4213 (#4311)
* fix: address pr-bug-scan validated finding from #4213

On per-file read/size error, skip the file and continue merging instead of returning found:false; preserve first error for the all-failed case.

* add tests

---------

Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-08-09 15:25:29 -07:00
EvgeniiandBrennan Benson 63af0bdd24 feat(agents): add Prime Agent as a supported TUI agent with session history (#12935)
* feat(agents): add Prime Agent as a supported TUI agent with session history

Wire Prime Intellect's prime-agent CLI (a Pi fork) into the desktop and
mobile agent catalogs following the Trae registration pattern, and into
the Agent Session History browser following the OMP pattern:

- types.ts, tui-agent-config.ts: register 'prime-agent' with argv prompt
  injection behind a `--` separator (its own help documents `--` as
  "treat all following arguments as messages"; without it, prompts
  starting with `help`/`agents`/`-…` dispatch as subcommands or
  flags), plus csi-u Shift+Enter encoding matching the Pi TUI it embeds.
- agent-kind.ts, telemetry-events.ts, agent-status-types.ts,
  agent-type-label.ts, tui-agent-display-names.ts,
  tui-agent-selection.ts, skills-cli-agent-keys.ts: standard per-agent
  registrations.
- agent-headless-command.ts: `-p/--print` one-shot runs share the
  print-mode matcher with Claude/Trae so they are not mistaken for live
  interactive panes.
- agent-process-recognition: the npm shim launches a generic bundled
  cli.js, so only the exact package path is an authoritative identity
  (same as Pi and cursor-agent). The three per-agent regex branches are
  now one table in agent-node-entrypoint-identities.ts — the module was
  at its max-lines budget and a table makes the next agent one entry.
- AI Vault: sessions are Pi's message-graph JSONL under
  ~/.prime/agent/sessions (override PRIME_AGENT_CODING_AGENT_DIR —
  Prime Agent brands Pi's env contract instead of sharing
  PI_CODING_AGENT_DIR); parsed by the shared message-graph parser with
  incremental append-resume; discovered locally, in WSL homes, and over
  remote SSH; resumes by absolute transcript path
  (`prime-agent --resume <path>`) like OMP, with session-id fallback.
- skill-discovery-sources.ts: ~/.prime/agent/skills home source.
- Catalog, i18n (en/es/ja/ko/zh), mobile registries, and a bundled
  64x64 favicon (required by mobile's offline-icon invariant).

Scanner-test fixtures for OMP and Prime Agent move into
session-scanner-test-fixtures.ts and the incremental fixture into its
own module, keeping every touched file inside its max-lines budget
without ratchet bumps.

* fix(ai-vault): map custom Prime Agent roots to their sessions child

PRIME_AGENT_CODING_AGENT_DIR is consumed verbatim by the CLI as its agent
config dir, with transcripts always in <agentDir>/sessions — unlike
PI_CODING_AGENT_DIR's <home>/agent/sessions shape the shared normalizer
models. A custom root with a non-special basename (or a `.prime` leaf)
was therefore scanned as-is instead of its sessions child. Dedicated
normalizePrimeAgentSessionsDir appends `sessions` to every configured
root, taking only an explicit `.../sessions` path as-is; the shared
Pi/OMP normalizer drops the `.prime` widening it no longer needs.

Raised in review on #12935.

* fix(ai-vault): guard degenerate Prime Agent roots and cover the remote source

normalizePrimeAgentSessionsDir stripped a filesystem-root value ('/' or '//')
to '', which then joined into the relative root 'sessions' and would walk the
main-process cwd. session-scanner-roots.ts already carries this guard for the
OMP variant; apply the same fallback here.

The remote SSH source had no test: deleting jsonlSource('prime-agent', ...)
left the suite green, unlike the local path which is pinned by the
AI_VAULT_AGENTS exhaustiveness assertion in session-scanner.test.ts. Add a
case that fixes the .prime/agent/sessions root segments, the .jsonl
extension, and parser routing.

Raised in review on #12935.

* fix(ai-vault): honor Prime Agent's sessions-root env and non-interactive modes

Verified against upstream PrimeIntellect-ai/prime-agent source rather than
inferred from the CLI's help text.

config.ts getSessionsDir() reads PRIME_AGENT_SESSION_DIR (and its legacy
PRIME_AGENT_CODING_AGENT_SESSION_DIR alias) ahead of the agent dir and uses it
verbatim; setting either left the vault silently empty. It also appends
`sessions` to the agent dir unconditionally, with no basename escape hatch, so
PRIME_AGENT_CODING_AGENT_DIR=/data/sessions writes to /data/sessions/sessions
while Orca scanned /data/sessions. getAgentDir() and the session-dir override
both run through expandTildePath, so a `~` value set outside a shell resolves.

cli/args.ts also spells the non-interactive runs `--mode json|rpc|acp|daemon`,
which the shared print-mode matcher does not know, so those panes were counted
as live interactive agents and the paste-submit path would write user text into
a JSON-RPC/ACP stream. Match upstream exactly: only the space-separated form,
since `--mode=json` is not parsed by the CLI and does start the TUI.

Raised in review on #12935.

* fix(ai-vault): keep Prime Agent roots absolute and remote segments posix

Two holes in the previous commit.

The degenerate-root guard only rejected pure-separator values, so a relative
env value still resolved against the main-process cwd:
PRIME_AGENT_CODING_AGENT_DIR='.' scanned '<cwd>/sessions' and, worse,
PRIME_AGENT_SESSION_DIR='.' scanned the cwd itself. Require an absolute path in
both branches and fall back to the default otherwise.

remotePrimeAgentSessionsSegments() built its segments with the local-platform
join, so on a Windows client scanning a posix SSH host it produced
'\.prime\agent\sessions' and split('/') collapsed it to one bogus segment —
remote discovery would have found nothing. Remote roots are posix regardless of
client platform, so keep them literal. Pi and OMP are unaffected: their
normalizer returns a '.../sessions' input unchanged and never joins.

Raised in review on #12935.

* test(ai-vault): pin Windows drive roots to the Prime Agent default fallback

'C:\' and 'C:/' strip to the drive-relative 'C:', which isAbsolute
rejects on every platform — assert they land in the default fallback so
a looser truthiness check can't reintroduce a 'C:sessions' scan root.

Raised in review on #12935.

* test(ai-vault): pin the drive-relative root form and state what the posix runner can assert

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-09 14:50:02 -07:00
Jinwoo HongandJinwoo-H 45c1cb979a fix(orchestration): release context-only dispatches (#13376)
* fix(orchestration): release context-only dispatches

Refs #13005

* test(orchestration): align PTY readiness timeout

---------

Co-authored-by: Jinwoo-H <Jinwoo-H@users.noreply.github.com>
2026-08-09 14:49:36 -07:00
OrcaWin 69ca0154b6 fix(git): bypass WSL login shells for status reads (#13207) 2026-08-09 14:41:40 -07:00
Brennan Benson 6858e072cf fix(terminal): agent pane auto-launch lost under fish + Starship (STA-3417) (#12840)
* fix(terminal): extend the shell-ready startup barrier to fish (STA-3417)

Fish never emitted the OSC 777 shell-ready marker, so agent launch
commands were written into the PTY while fish/Starship were still
initializing: the daemon path wrote them synchronously at session
create and the local path blind-wrote ~30ms after the first output
byte. The command was echoed by the kernel but never executed.

- shell-templates: shared fish --init-command that emits the marker
  once on the first fish_prompt event (the earliest point fish's own
  reader owns the PTY, mirroring zsh's zle-line-init marker)
- daemon shell-ready: fish joins the startup barrier so the launch
  command queues until the marker (timeout fallback unchanged)
- local-pty-shell-ready: fish launch config gains the marker wrapper
- codex-startup-delivery/tui-agent-startup: omp/pi/opencode plans now
  request shell-ready delivery (codex parity) so the SSH renderer path
  also waits for the prompt; plain payload-free codex stays on the
  markerless fast path

* fix(terminal): answer DA1 past the shell-ready barrier

The barrier queues all inbound input until the ready marker, including the
renderer's DA1 reply. A shell that withholds its first prompt until DA1 is
answered — fish waits 10s — therefore never emits the marker that would
release the reply it is waiting for. Measured: 10.37s to launch an agent,
versus 0.35s once the reply lands.

Answer DA1 from the daemon while the barrier holds, writing straight to the
subprocess so the reply bypasses the queue, and consume the query so the
renderer's xterm cannot also reply. Released on ready, timeout, or dispose,
handing DA1 back to the renderer for steady state.

Consolidates the identical DA1 handler the ConPTY override already used.

* fix(terminal): prevent duplicate startup DA1 replies
2026-08-09 14:29:14 -07:00
Brennan Benson 43bad61a93 fix(terminal): deliver SIGWINCH to the PTY foreground process group (#13164)
* fix(terminal): deliver SIGWINCH to the PTY foreground process group

A real window-size change is delivered by the kernel to the terminal's
foreground process group, but Orca signalled the pty's root pid. The root
is never in that group: the shell setpgid's away for job control, a
foreground TUI forms a third group again, and on macOS the root is
login(1), which neither handles nor forwards SIGWINCH.

So the explicit reattach repaint signal reached a running TUI on no
platform, and on macOS reached nothing at all. Resolve the tty's tpgid
and signal the negated group instead, pinned to the slave device captured
at spawn so a recycled pid cannot aim at a real terminal.

Scoped to SIGWINCH: destructive signals keep the narrower root-pid target
and the descendant-sweep identity machinery. POSIX-only, so Windows keeps
its current behavior where a negative pid is invalid and SIGTERM means
terminate. Applied on the relay too, so SSH hosts get it; that is
host-local with no wire change.

* fix(terminal): bound foreground group lookup latency

* fix(terminal): preserve SIGWINCH fallback on signal errors
2026-08-09 14:09:57 -07:00
Wooseong KimandBrennan Benson 9a6c5cddc9 fix(agent-hooks): exit Windows hooks when Orca env is missing (#11568)
* fix(agent-hooks): exit Windows hooks when Orca env is missing

* test(agent-hooks): pin the Windows missing-env exit as a deliberate stdin handoff

The Windows-only executable matrix still asserted every managed .cmd drains
its writer, which the missing-env fast exit intentionally stops doing. That
assertion never runs in CI (vitest is ubuntu-only), so it would only fail on
a Windows dev machine.

- Accept a broken writer for .cmd hooks on the missing-env path; keep the
  no-error contract for the PowerShell and Git Bash hooks that still read
  stdin first.
- Correct the drain-epilogue comment: claude-hook.cmd is the remaining
  in-script jump to it.

* docs(agent-hooks): cite #11549 and the stdin-ownership trade in the guard comment

* test(agent-hooks): stop overstating what the live matrix pins

runHookProcess always closes stdin, so the executable case cannot reproduce
the abandoned-pipe hang; say so and name the guard strings as the real gate.
Also record that the Devin skip guard still routes to the drain above these
guards, so #11549 stays reachable for Devin outside an Orca pane.

* docs(agent-hooks): record why Windows batch diverges from the POSIX stdin policy

The two templates now answer the same question opposite ways and nothing states
the rule, so name the constraint (batch has no bounded stdin reader) and the
evidence (POSIX callers have not shown the abandon; Windows callers have).

* test(agent-hooks): stop the live matrix name and comment from over-claiming

The renamed case covers two missing-script launchers that still read to EOF, so
'without stranding a reader' was false for them. Payload size was also the wrong
reason for the .cmd exit — the statusline script buffers the same size through
more.com; the real constraint is that any read-to-EOF hangs on an abandoned pipe.

Also record that the broken-writer relaxation is only sound because
hookEnvironment() strips every ORCA_* var, since the branch keys on .cmd.

* test(agent-hooks): gate the rule, not the three guards that exist today

The revert pin was three exact string denials, so a fourth ORCA_* guard — copied
from the nearest in-repo pattern, which still routes to the drain — would have
reintroduced #11549 with the suite green. Assert instead that no ORCA_* guard in
a generated .cmd routes to the more.com drain.

Verified both directions: reverting the source fails it, and adding a simulated
ORCA_TAB_ID guard that gotos the drain fails it too. Does not match the Devin
skip, which is not an ORCA_* guard and whose caller is a live Orca pane.

* docs(agent-hooks): name the exceptions so the stated rule is not self-contradicting

The previous wording set a rule that claude/statusline-script.ts breaks 25 lines
away in the same export surface, and said nothing about the Windows .ps1 and Git
Bash hooks. State the rule for generated .cmd, then name every hook that still
reads first and why — the read is the payload capture, not a drain. Batch is the
exception because it streams to curl, so owning stdin buys nothing there.

* test(agent-hooks): close the if-not-defined bypass in the drain gate

The guard-spelling regex only covered `if "%VAR%"==""`, but `if not defined VAR`
is equally house idiom here — every Windows hook opens with `if defined
ORCA_AGENT_HOOK_ENDPOINT`. A fourth guard written that way routed to the drain
with the suite green. Match the whole line instead of one spelling, which also
covers `goto` without its colon.

Probed all eight cases: the five bypass spellings are caught, and the Devin skip,
the endpoint refresh, and the fixed guard are correctly exempt.

* docs(agent-hooks): separate the two reasons a hook is exempt from the .cmd rule

The list conflated them. POSIX, copilot .ps1 and kimi .sh read first because the
read is the payload capture. claude/statusline-script.ts does route its guard to
the drain — it is exempt because its caller closes stdin, which the in-pane
capture already proves. Grouping them under 'the read is the capture' would let a
future author reach the right conclusion from the wrong premise.

* fix(agent-hooks): let the missing-Orca-env exit outrank the Claude/Devin skip

claude-hook.cmd checked DEVIN_PROJECT_DIR before the Orca env guards, and that
check jumps to the more.com drain. Outside an Orca pane the caller is not Orca's
PTY, so it can abandon stdin and leave more.com waiting forever — the #11549 hang
this guard reordering is meant to close.

Both branches end the hook, so the only behavior that changes is Devin outside an
Orca pane: it now exits 0 instead of parking in more.com. In-pane Devin still
reaches the skip and still owns stdin.

Depends on #11568.

* refactor(agent-hooks): cut the review additions back to house idiom

The three-line guard fix needed a three-line comment, not a thirteen-line
taxonomy adjudicating three other files. Swap the hand-rolled drain gate and
broken-writer set for the combinators already used repo-wide: not.toMatch
(94 uses) and toContain on a literal.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-09 14:00:46 -07:00
BingZandBrennan Benson 371cc26ca1 fix(settings): emit Windows font family names as UTF-8 (#12602)
* fix(settings): emit Windows font family names as UTF-8

Windows PowerShell 5.1 can write localized font names with the console
code page while Node always decodes stdout as UTF-8, which garbles
Korean and other non-ASCII family names in the font picker. Force
UTF-8 OutputEncoding before enumerating InstalledFontCollection (#12590).

* test(settings): assert UTF-8 pin precedes Windows font enumeration

Lock script order so OutputEncoding is set before InstalledFontCollection
enumeration, preventing a silent regression of the mojibake fix.

* refactor(settings): cut the Windows font UTF-8 pin to the standard shape

`$OutputEncoding` only governs bytes piped to a native executable's stdin;
this script pipes to ForEach-Object, so it was inert. Drop it, and drop the
script-builder export whose only consumer was a test — the one-shot
`-Command` shape now matches windows-foreground-process-rows and ssh-browse,
while the BOM-less `UTF8Encoding::new($false)` spelling matches
powershell-osc133-bootstrap and antigravity/hook-service.

The test reaches the script through the public listSystemFontFamilies path
and pins the assignment as the script's first statement, so it fails on
removal, on a stdout write above it, and on a swapped encoding.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-09 13:31:22 -07:00
JinjingandOrca 3ec48a74d5 Gate artifact publishing behind off-by-default capability (#13368)
* fix(artifacts): gate agent artifact publishing behind an off-by-default capability

Public artifact sharing was reachable by any agent through `orca artifacts
share`: the Artifacts settings toggle only controlled sidebar visibility, and
nothing in the main process checked a capability before minting a public URL.

Add `artifactSharingEnabled` (default off) and enforce it in
ArtifactCloudService.share/update — before auth, network, or the share-record
write — so the CLI, relay-forwarded remote CLI, and IPC paths are all denied.
The denial carries a stable `artifact_sharing_disabled` code plus next steps
through the RPC error allowlist, so the CLI prints actionable guidance.

list, unshare, and delete stay ungated: turning publishing off must not strand
already-published links. The capability is absent from the `settings.update`
RPC schema, so an agent cannot grant it to itself — only the desktop UI can.

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

* fix(artifacts): gate agent artifact publishing behind an off-by-default

Publishing is blocked until enabled in Settings → Artifacts. CLI preflights the capability before reading files to avoid unnecessary uploads. RPC surface rejects capability grants so callers cannot self-grant. UI shows opt-in workflow and recovery path when publishing is off. Web clients mirror the host's setting read-only.

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-09 13:19:08 -07:00
JinjingandOrca 2dc172f666 Support live toggle of agent status hooks with WSL relay gating (#13361)
* fix(agent-hooks): gate WSL relay reattach on agentStatusHooksEnabled

Spawn only ensures the guest relay distro when agent status hooks are
enabled, but reattach called ensureForDistro unconditionally — so a
disabled setting reinstalled guest hooks on every local WSL reattach.
Pass the same isAgentStatusHooksEnabled gate through all three reattach
call sites as a required argument so a new site cannot skip it.

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

* Gate WSL relay at manager level for live toggle support

- Move agentStatusHooksEnabled check from reattach call sites to centralized isWslHookRelayAllowed gate
- Add non-permanent dispose mode so manager can revive relays when setting is re-enabled
- Watch setting changes and dispose live relays when agent status hooks are disabled mid-session

* Restore WSL relays when re-enabling agent status hooks

Extract guest install logic to `wsl-hook-relay-guest-install.ts` for modularity
and add `resumeStoppedRelays()` to restart relays when hooks are re-enabled.
Track distros stopped during a hooks-off teardown, but skip resuming those the
user has shut down (which would unwantedly boot a stopped distro). Strengthen
the disposed check with state identity to prevent respawning untracked relays.
Abandon in-flight launches when hooks are switched off so no relay exists after
opting out.

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-09 12:53:13 -07:00
Jinwoo HongandJinwoo-H 394e4bf1c0 Polish Artifacts management UI (#13356)
* refactor(artifacts): polish artifact management UI

* fix(artifacts): address UI polish review

---------

Co-authored-by: Jinwoo-H <Jinwoo-H@users.noreply.github.com>
2026-08-09 12:11:33 -07:00
Neilandbbingz 34f2a62cda fix(pty): stop color-scheme 997 replies from painting cooked prompts (#13309)
Route cooked-echo-risk terminal replies through bounded echo-safe delivery across local, daemon, and SSH relay PTYs. Preserve repeated valid replies, bypass the daemon startup input gate, and keep ordinary input plus latency-critical replies on their existing paths.

Closes #13137

Co-authored-by: bbingz <zzb@gxsmjx.com>
2026-08-09 01:45:15 -07:00