Commit Graph
6265 Commits
Author SHA1 Message Date
Jinwoo-HandOrca 09b68cbb12 Cut the hidden-restore flood feedback loop (A) + query carve-out on drops (B)
(A) Under a foreground flood, the hidden-output-restore loop re-fetched
snapshots endlessly: each synchronous applyMainBufferSnapshot starved ACK
processing, main pinned at the in-flight cap, dropped at the pending cap,
and every droppedOutput/modelRestoreNeeded marker re-armed another
restore until the flood ended (rc.7.perf DSR timeouts).
- Restore loop: a foreground live-chunk queue overflow now abandons the
  restore immediately (the stream is outrunning snapshot fetch+replay),
  with a 3-iteration hard cap + lifecycle warn as backstop.
- Re-arm gate: drop markers/sentinels and reconcile seq-gaps on a visible
  pane during its own in-flight/just-abandoned restore no longer re-arm;
  live bytes write through and ONE deferred repaint (2s after the last
  backpressure signal) heals the gap. Hidden-pane gate semantics are
  unchanged.
- Query salvage: discarding queued restore bytes (overflow/refetch) now
  extracts DSR/CPR/DA/OSC-color queries and replays them to xterm so
  replies still flow.

(B) Main-side: dropOversizedPendingPtyData carves reply-eliciting query
sequences out of the dropped buffer (and out of post-drop latched data,
bounded) and ships them on the droppedOutput sentinel, so DSR probes
survive bulk drops. Query scanning moved to
src/shared/terminal-reply-query-extraction.ts, shared verbatim with the
renderer's hidden-startup query extraction.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 22:45:02 -04:00
Jinwoo-H 1ce7f1b8cd Merge remote-tracking branch 'origin/Jinwoo-H/perf-update-click' into orca-performance 2026-07-03 21:57:20 -04:00
Jinwoo-HandOrca 04ca7c9508 Classify suffixed rc tags (rc.N.perf) as rc telemetry identity in release builds
The build-identity guard only knew vX.Y.Z and vX.Y.Z-rc.N, so suffixed
perf RCs cut fine but every platform build refused the tag and the
releases published empty.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 21:34:51 -04:00
Jinwoo-HandOrca 00ba563176 Count suffixed RC tags (rc.N.perf) in the shared rc counter — second suffixed cut collided with the first
Co-authored-by: Orca <help@stably.ai>
2026-07-03 21:25:35 -04:00
Jinwoo-HandOrca 24b135e74e Fix snapshot DECSC register loss (Bug D) and mid-escape boundary drop (Bug E)
Bug D: the serialized screen cannot carry the VT100 DECSC saved-cursor
register, so a hidden ESC 7 followed by a post-reveal ESC 8 restored to
home and clobbered live cells. The snapshot epilogue now re-saves at the
source's saved position before the final absolute CUP
(readSavedCursorRegister + serializeWithAbsoluteCursor; the active
buffer's own register, so alt screens carry theirs). Position-only by
design; never-saved terminals are left untouched.

Bug E: a PTY read ending mid-escape leaves the sequence in the emulator's
parser, so serialize dropped it and the racing tail's continuation bytes
rendered literally after reveal (~24% of the fuzz corpus). The emulator
now tracks the unparsed trailing partial at ingest
(terminal-partial-escape-tail.ts, committed post-parse like the mouse
mirror) and ships it as TerminalSnapshot.pendingEscapeTailAnsi.
applyMainBufferSnapshot writes it LAST, after POST_REPLAY reset — any
later ESC would abort the dangling sequence. Seq accounting is unchanged:
the tail is a suffix of bytes the snapshot seq already counts, so
reconcile slicing needs no adjustment.

Fuzz suites: unskip the Bug B/C repros (fixed on this branch) and the new
D/E repros; remove the B/C/E tolerance predicates so regressions fail
loudly. Only Bug A (upstream wrap null-cell) stays tolerated + counted.
Green at FUZZ_ITERATIONS=2000 (fidelity) and 1000 (reconciliation).

Co-authored-by: Orca <help@stably.ai>
2026-07-03 21:15:20 -04:00
Jinwoo-HandOrca 04e2d12899 Keep RC update checks off perf prereleases
Co-authored-by: Orca <help@stably.ai>
2026-07-03 21:11:44 -04:00
Jinwoo-H 32f7201b42 Merge remote-tracking branch 'origin/test/garble-differential-fuzz' into orca-performance 2026-07-03 20:52:22 -04:00
Jinwoo-HandOrca 8ab4afb2ab Gates: tolerate+count Bugs B/C in deep mode; drop inverse from reconciliation tail
- Fidelity suite: add snapshotHasSelfCancellingBoldReset (Bug B) and
  isMarginWrapPendingCursorOffByOne (Bug C) predicates so the corpus tolerates +
  counts them like Bug A. FUZZ_ITERATIONS=2000 is now green (~113s) and fails
  only on genuinely new divergences; each tolerance keeps its <50% degeneracy
  guard. Default 300 unchanged (~17s).
- Reconciliation suite: drop SGR 7 (inverse) from the append-only tail. Inverse
  marks trailing blanks with an inverse-fg the serializer round-trips slightly
  differently by capture depth — a Bug-B-class serialize nuance, not seq
  reconciliation. FUZZ_ITERATIONS=1000 is now green; default 200 unchanged.
- Notes updated: every bug class is both pinned (skipped repro) and tolerated in
  its corpus; combined default runtime ~19s.

Regex uses String.fromCharCode(27) to stay oxlint no-control-regex clean.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 20:50:53 -04:00
Jinwoo-HandOrca 28016b837d Fix two serialize round-trip bugs garbling hidden-terminal snapshot restore
BUG B (addon patch): @xterm/addon-serialize's SGR diff emitted bold/dim set
params before the shared intensity reset 22, so "1;22" wiped a freshly set
bold and a bare "22" dropped a still-set bold/dim. Patched via pnpm
patchedDependencies (config/patches) to diff bold+dim as one intensity
group with the clearing 22 emitted first. Other flag pairs (4/24, 3/23,
7/27, ...) have dedicated resets and were verified unaffected.

BUG C (Orca-side hardening): the addon restores the cursor with relative
moves computed from where it assumes replay leaves the cursor; a final row
filled exactly to the right margin leaves replay wrap-pending and the
restore lands one column short. New shared
serializeWithAbsoluteCursor appends an absolute CUP from the source
terminal's authoritative cursor at every restore/replay serialize site
(daemon/runtime HeadlessEmulator.getSnapshot, renderer mobile snapshot
serializer, shutdown layout capture). It skips empty snapshots and
wrap-pending sources so it never changes already-correct behavior.

Round-trip repros + non-regression coverage in
src/main/daemon/terminal-snapshot-serialize-roundtrip.test.ts (verified
failing with the fixes stashed). buildRehydrateSequences extracted to its
own module to keep headless-emulator.ts under the max-lines budget.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 20:42:00 -04:00
Jinwoo-HandOrca 6a3646e8f2 Suite 3: 25-cycle park/reveal drift e2e test
Extends terminal-hidden-view-parking.spec.ts with a deterministic 25-cycle
park->reveal test on a static rich alt-screen TUI frame (box drawing, SGR
colors, wide CJK/emoji). Baselines against the frame after the first snapshot
restore (so both sides pass through identical machinery — the alt-screen restore
correctly drops normal-buffer scrollback, which is contract not garble), then
asserts every subsequent reveal reproduces it byte-for-byte with no accumulated
drift and no hidden-skip banner. Exercises the real renderer teardown +
HeadlessEmulator snapshot restore + PTY reattach path the fuzz suites model in
isolation. Passes in ~29s (electron-headless, workers=1).

Co-authored-by: Orca <help@stably.ai>
2026-07-03 20:40:34 -04:00
Jinwoo-HandOrca 2fdf8ed39e Suite 2: hidden-reveal seq-reconciliation fuzz + two new snapshot bugs (D, E)
Property-tests the reveal seq-reconciliation byte-stitch (getChunkDataAfterSnapshot
/ reconcileChunkAgainstRestoredSnapshot in pty-connection.ts), mirrored exactly:
N=200 seeded hide/reveal scenarios with a rich agent-TUI hidden prefix snapshot
and an append-only racing tail, chunked with seq/rawLength meta, seq-domain
restarts, unmetered chunks and droppedOutput markers. Asserts snapshot-at-S +
reconciled tail == snapshot-of-everything (seq-neutral) and == always-visible
(end-to-end). Runtime ~5s at 200; FUZZ_ITERATIONS override documented.

Two NEW real snapshot-limitation garbles found while building it, both distinct
from suite 1's serialize bugs and pinned as standalone it.skip repros:
- Bug D: the DECSC saved-cursor register is not serialized. A hidden TUI that
  saves the cursor (ESC 7 / CSI s) and restores it on reveal (ESC 8 / CSI u)
  lands the restore at home. Repro: 'AB\x1b7\x1b[4;10HCD' + '\x1b8X' -> 'XB' vs 'ABX'.
- Bug E: a snapshot taken mid-escape-sequence (a PTY read split an escape) drops
  the partial sequence (it's parser state, not buffer), so the tail's
  continuation renders literal. Repro: 'AB\x1b[3' + 'mCD' -> 'ABmCD' vs 'ABCD'.
  Fired on ~24% of the corpus (tolerated + counted via prefixEndsMidSequence).

The append-only-tail design isolates seq reconciliation from these and the Bug C
cursor cascade. Full evidence + fix directions in notes. No production changes.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 20:34:09 -04:00
Jinwoo-HandOrca 821c8b69fb Add perf prerelease update check modifier
Co-authored-by: Orca <help@stably.ai>
2026-07-03 20:25:55 -04:00
Jinwoo-HandOrca f21db817ad Suite 1 findings: two new serialize round-trip bugs (B bold-loss, C cursor)
Scanned seeds 1..2000. Beyond the pre-documented serialize wrap-null-cell bug
(A, 27 seeds, tolerated), the fuzz surfaced two NEW real @xterm/addon-serialize
0.15.0-beta.287 round-trip defects, both of which garble a revealed hidden pane:

- Bug B (seeds 435, 770, 1321): serializing a dim cell followed by a bold-only
  cell emits \x1b[1;22m; SGR 22 clears bold too, so restored bold is lost.
  Minimal repro: '\x1b[2mA\x1b[22m\x1b[1mB' -> restored 'B' loses bold.
- Bug C (seeds 454, 1696): a final content row filled to the right margin leaves
  xterm wrap-pending; the serializer's relative cursor restore lands one column
  short. Minimal repro: '0123456789\x1b[3;5H' at cols=10 -> cursor x=3 not x=4.

Both isolated to pure serializer replay (no Orca preamble), confirming upstream.
Parity fixture verified faithful to the renderer pane's buffer options. Each is
pinned as a standalone it.skip repro; full evidence + classification in
notes/garble-fuzz-divergences.md. Seed 113 (handoff's DECSC/DECRC case) does not
diverge on the current harness. No production code changed.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 20:09:03 -04:00
m11yandClaude Fable 5 4c78440f70 Fix Codex hook trust hash for matcherless events (UserPromptSubmit/Stop) (#7110)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:07:42 -07:00
Jinwoo-H 7fc8db81b7 Merge remote-tracking branch 'origin/orca-performance' into orca-performance 2026-07-03 20:06:18 -04:00
Soichi Sumi 5e9db83c48 fix: add 'hooks' to CODEX_SYSTEM_RESOURCE_ENTRIES (#7120) 2026-07-03 17:06:09 -07:00
Jinwoo-HandOrca fd767fa72e Merge origin/main (browser copy, TOC, mobile IME, i18n, Windows startup) + add version_suffix input to release-cut
rc kind can now append an extra prerelease identifier (rc.N.perf):
sorts above its base rc.N but below rc.N+1, so perf-branch RCs are
identifiable by clients without outranking the main RC series.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 20:05:49 -04:00
haozhenfei 547afc2264 fix(rate-limits): route hidden Claude usage PTY through the configured proxy (#7245) 2026-07-03 17:04:25 -07:00
Jinwoo-HandOrca 623ec8680a Starting point: prior agent's garble differential fuzz harness
Three files recovered (were untracked) from a prior agent killed by API
outages, plus a trivial curly-brace lint fix in the op dispatcher so the
pre-commit hook passes:
- src/shared/agent-tui-ansi-fuzz-stream.ts (seeded agent-TUI byte-stream gen)
- src/shared/terminal-restore-parity-fixture.ts (renderer-parity fixture)
- src/main/daemon/headless-emulator-fidelity.fuzz.test.ts (suite 1: differential
  HeadlessEmulator vs @xterm/headless reference on identical bytes)

Co-authored-by: Orca <help@stably.ai>
2026-07-03 19:52:44 -04:00
2789a67604 feat(browser): add Copy to context menu when text is selected (#7159)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-03 16:52:08 -07:00
473c4e8680 fix(markdown): restore TOC navigation for h4 and h5 (#7063)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <charlie-eng@stably.ai>
2026-07-03 16:51:26 -07:00
e8c2b79a93 Fix mobile live input keyboard and Korean IME (#7273)
* feat: 모바일 터미널 한글 미러 스텝 순수 모델 추가

* feat: 미러 델타 순서 보장용 send 체인 추가

* fix: 모바일 터미널 한글 입력을 미러 모델로 전환

* fix: 탭 상태 지연 중 한글 조합 상태 소실 방지

* fix: 미러 가드와 send 체인 리뷰 지적사항 반영

탭 상태 지연으로 활성 탭 타입이 일시적으로 null이 될 때 runMirrorStep의 stale-handle 가드가 조합 중 음절을 버리지 않도록 pending-clear 효과와 동일한 null 허용 패턴 적용. 테스트 하네스가 ref와 prop을 동일 소스에서 파생하도록 결합해 실제 경로의 lag 프레임을 검증. queueTerminalLiveMirrorSend의 previousSend await를 catch로 보호.

* refactor(mobile): drop dead queueTerminalLivePendingFlush orphaned by the mirror model

The mirror model migrated all live-input sends to queueTerminalLiveMirrorSend,
leaving queueTerminalLivePendingFlush referenced only by its own tests. Remove
the dead function and its three tests.

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

* fix(mobile): expose live terminal keyboard target

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

* fix(mobile): refocus live keyboard after dismissal

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

---------

Co-authored-by: realitsyourman <wongil@demodev.io>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:47:59 -07:00
2c03133975 fix(i18n): apply persisted UI language at startup instead of OS locale (#7193)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: rubin <RubinCarter@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-03 16:44:56 -07:00
github-actions[bot] 0bc417e04d release: v1.4.121-rc.5 v1.4.121-rc.5 2026-07-03 23:41:58 +00:00
Jinwoo Hong 2f3c7e8660 Fix Windows slow startup and multi-minute UI freezes (#7225) (#7266) 2026-07-03 19:40:45 -04:00
4797cf81a4 fix(agent-hooks): stream hook payload to a temp file instead of inlining it on the curl command line (#4475)
The POSIX agent-hook script for every curl-based agent inlined the full
event payload via `curl --data-urlencode "payload=${payload}"`. Tool
output can be tens of KB, so the resulting process command line could be
multi-KB — which endpoint security tools (e.g. Microsoft Defender for
Endpoint) flag as an oversized/suspicious command line. That produced a
false-positive detection on Orca's own loopback (127.0.0.1) telemetry POST.

Stream the payload to an mktemp file and post it with
`--data-urlencode "payload@$payload_file"` instead. The urlencoded body on
the wire is byte-identical, so the agent-hook receiver is unchanged; the
payload simply never appears on a process command line. `trap ... EXIT`
removes the temp file on every exit path. Small bounded metadata fields
(paneKey/tabId/worktreeId/env/version) stay inline.

Applied to all curl-based agents: claude, codex, command-code, copilot,
cursor, droid, gemini, grok, antigravity. (amp/hermes/opencode post via
the HTTP request body and were never affected.) The Windows post-command
shares the same latent pattern and is flagged as follow-up.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:26:53 -07:00
a10e1d7584 fix(gitlab): recognize self-hosted GitLab on non-default ports over SSH connections; stop one project failing the whole issues panel (#5400)
* fix(gitlab): port-aware self-hosted host recognition

Use the URL host (including a non-default web/API port) as the GitLab
host identity instead of the port-less hostname, and match known hosts
port-aware:

- A known-host entry without a port matches any port of the same
  hostname (preserves legacy bare-host and gitlab.com recognition).
- A known-host entry WITH a port matches only that exact host:port, so
  two services sharing a hostname on different ports (e.g. a GitLab and
  a Gitea) are no longer conflated.
- For ssh/git remotes the port is a transport port (e.g. ssh :2222) and
  is dropped; for http(s) remotes the port is the endpoint and kept.
- Also capture an optional :port in parseGlabAuthStatusHosts so a
  self-hosted GitLab on a non-default port is discovered correctly.

* fix(gitlab): per-connection known-hosts cache + port-aware auth-status parsing

getGlabKnownHosts() was connection-blind and cached process-globally,
and on any failure it cached [gitlab.com] forever — so a repo on an SSH
connection never discovered its self-hosted host once a probe failed
before the tunnel was ready.

- getGlabKnownHosts(connectionId?) now caches per connection so a
  connected repo's authenticated hosts don't leak into the local
  context (or vice versa).
- The failure fallback (canonical default) is no longer cached, so a
  later probe can re-discover the real host once auth/tunnel is ready.
- parseGlabAuthStatusHosts captures an optional :port on both the
  'Logged in to <host>' and header-style lines, keeping two services on
  the same hostname distinct by port.

* fix(gitlab): isolate unresolvable projects instead of cwd-fallback that hits exit 128

listIssues/getIssue fell back to an unscoped 'glab issue list' / 'glab
issue view' that infers the project from cwd. For a repo on an SSH
connection cwd is not the repo dir, so glab runs git resolution in a
non-repo dir and fails with 'git: exit status 128'. In an 'All projects'
aggregate one such failure could sink the whole issues panel.

When a projectRef cannot be resolved, return a structured, isolated
per-project result (listIssues: { items: [], error: not_found };
getIssue: null) and spawn no glab subprocess. Behavior is unchanged when
a projectRef IS resolved (the scoped '-R' / 'api projects/...' path).

* fix(gitlab): recognize modern /-/work_items/<iid> issue URLs

Modern GitLab emits issue URLs as /-/work_items/<iid> in addition to the
legacy /-/issues/<iid>. The URL classifiers only matched /-/issues/, so
work-item-form issue links went unrecognized.

Extend the gitlab-links parsers (parseGitLabIssueOrMRNumber /
parseGitLabIssueOrMRLink, which also backs isWorkItemLookupText) and
isGitLabIssueUrl to accept /-/work_items/<iid>, mapping it to an issue
work item with the same project-path + iid extraction.

* fix(gitlab): thread connectionId into getGlabKnownHosts call sites

Follow the existing connectionId-threading pattern: pass the repo's
connectionId into every getGlabKnownHosts() call (client.ts,
work-item-details.ts, orca-runtime.ts) so the per-connection known-hosts
cache is keyed correctly and self-hosted hosts are discovered against
the right glab context.

* docs(gitlab): use generic example hosts in comments

* fix(gitlab): pass self-hosted host:port via GITLAB_HOST (glab --hostname rejects ports)

* polish: satisfy oxlint curly + oxfmt on merged gitlab port-recognition code

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

---------

Co-authored-by: Ptah-CT <auctor@xinfty.space>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:24:01 -07:00
Jinwoo-HandOrca 44624b5736 Merge fix/terminal-wake-ack-recovery: cumulative ACKs + solicited resync composed with producer flow control v19
Grafts the sleep/wake terminal-recovery rework (PR #7260) into the RC
perf line. Resolution principle: this branch's structure wins; the
rework's delivery-accounting semantics graft in.

Kept from orca-performance:
- Producer flow control v19: PRODUCER_FLOW_CONTROL_ENABLED kill switch,
  every updateProducerFlowControl call site where pendingData mutates
  (256KB/32KB watermarks, pause/resume daemon notifications), and
  producerFlowControl.releaseAll/release on destroy/exit. Flow control
  keys off pendingData only, so it composes with the new renderer
  delivery accounting untouched.
- PTY_BATCH_INTERVAL_MS = 2 with its daemon-stream-data-batcher pairing
  comment; merged resync tests adapted to the 2ms window.
- Chain structure: hidden-delivery gate (drop + restore markers),
  pending-output cap with droppedOutput sentinel, overflow marker set.

Grafted from fix/terminal-wake-ack-recovery:
- TCP-style cumulative delivery accounting (sentChars/ackedChars
  max-merge; legacy delta payloads still accepted) replacing the
  relative in-flight counter map — lost ACKs self-heal instead of
  becoming permanent gate debt.
- Solicited delivery resync (probe on data-arrival-while-fully-gated,
  verified-state reconcile on reply, 5s hygiene-only timeout).
- Renderer lifecycle reset zeroes the delivery gate; powerMonitor
  system:resumed wake IPC (merged cleanly, no conflicts).

Both test suites pass composed: pty.test.ts 243 (flow-control +
cumulative-ack/resync), full ipc/terminal-pane/daemon gates green with
only the pre-existing WSL env-import failure.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 19:16:24 -04:00
Jinwoo HongandOrca 25896f2cdb fix(mobile): keep Android release versionCode committed (#7271)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 15:26:11 -07:00
Jinwoo-H 30e9245f05 Merge remote-tracking branch 'origin/fix/terminal-wake-ack-recovery' into fix/terminal-wake-ack-recovery 2026-07-03 18:22:38 -04:00
Jinwoo-HandOrca 4647df86a5 Replace ack-stall watchdog with cumulative ACKs + solicited delivery resync
Design review: the 10s blind-reset watchdog decided correctness from a
wall-clock threshold. Rework piece 1 into a deterministic two-part design
(pieces 2 and 3 — lifecycle-reset counter zeroing and powerMonitor wake
IPC — are unchanged):

- Cumulative ACKs (TCP-style): the renderer dispatcher now tracks a
  monotonic per-pty total of processed chars (terminal-pty-ack-gate) and
  sends it on every ACK alongside the legacy per-chunk delta. Main keeps
  per-pty sentChars/ackedChars and max-merges received totals — idempotent
  and reorder-tolerant, so a lost ACK self-heals when any later ACK
  arrives instead of becoming permanent in-flight debt. Provider
  (SSH/daemon) backpressure is credited only the derived delta, clamped,
  never negative. Main tolerates both payload shapes keyed by field
  presence (dev hot-reload can mix renderer/main versions); totals reset
  on pty exit and renderer lifecycle reset on both sides.

- Solicited resync (replaces the blind reset): when new pty data arrives
  while that pty's delivery is fully gated and no probe is outstanding,
  main sends pty:requestDeliveryResync; the renderer replies with its
  cumulative totals and main reconciles via max-merge, then flushes held
  pendingData. Event-triggered, verified-state recovery — no wall-clock
  threshold decides correctness. The only timer is a 5s request/response
  hygiene timeout that clears the outstanding flag and logs one
  diagnostic warn per silent streak; it never mutates counters (a
  renderer that cannot answer has dead IPC — reload is the only cure).

The 10s corrective watchdog is deleted.

Co-authored-by: Orca <help@stably.ai>
2026-07-03 18:22:04 -04:00
Brennan BensonandOrca f4790e9fac Fix blank mobile terminal on Android devices with outdated WebViews or blocked CDN (#7186)
* fix(mobile): bundle terminal engine and show load errors instead of a blank pane

The mobile terminal WebView loaded xterm.js from cdn.jsdelivr.net at
runtime; old WebViews (< Chrome 85) fail to parse the modern bundle and
blocked-CDN networks fail to fetch it, and the resulting error was
silently dropped, leaving the pane permanently blank (#7030).

Bundle the engine into the app via exact-pinned npm deps + a postinstall
esbuild step (chrome74 target, guarded WeakRef/structuredClone/
replaceChildren shims) emitting a gitignored generated module, inline it
into the terminal document, and surface fatal engine failures as a
visible overlay with diagnostics and a Reload wired into the existing
resubscribe path. Non-fatal errors log without covering a live terminal.

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

* fix(mobile): add a native watchdog so a dead terminal document can't stay silently blank

CodeRabbit round: if the webview document dies before the glue can post
anything (or the RN message bridge never comes up), no error message and
no native handler fires. Arm a 15s foreground-gated watchdog per document
generation that paints the fatal overlay when web-ready never arrives;
first fatal diagnostics win over later cascades. Extract the watchdog and
the public contract types to keep TerminalWebView under the line cap, and
document the SVG xmlns percent-encoding transform.

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

* test(mobile): unmount TerminalWebView renderers so watchdog timers can't leak across tests

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-03 15:22:00 -07:00
github-actions[bot] f3e103ebe7 release: v1.4.121-rc.3 v1.4.121-rc.3 2026-07-03 21:28:43 +00:00
Brennan BensonandOrca 6213f43016 Wake hibernated agent panes on reveal instead of leaving an inert ghost (#7145)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:27:36 -07:00
Alexander 99d61b13b2 Bound generated release notes by previous tag (#5649)
Fixes #5579. Pass previous_tag_name to GitHub generate-notes so draft-release notes stop accumulating across releases; omit it safely on first release. Adds tag parse/compare + paginated tag fetch and regression tests.
2026-07-03 14:22:47 -07:00
332490e919 Fix stale GitHub repo avatars after owner changes (#6507)
* Fix stale GitHub repo avatars after owner changes

* Simplify avatar-refresh effect deps (repo covers its fields)

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

* Preserve known fork identity when live upstream lookup is inconclusive

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

* Remove dead avatar-icon wrapper; drop no-op update fallbacks

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

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:20:30 -07:00
5124b0d0ad fix(serve): install orca CLI in headless serve so orca claude-teams resolves (takeover of #5766) (#7267)
* fix(serve): install the orca CLI in headless serve mode

In headless serve mode the orca CLI command (~/.local/bin/orca on Linux,
/usr/local/bin/orca on macOS) is never created, so the in-app Claude Team
launcher (orca claude-teams) opened by 'Start new agent' fails with
command-not-found. CliInstaller.install() is only invoked from renderer/desktop
flows (onboarding, Settings 'Install CLI', feature tips) via the cli:install IPC;
headless serve has no renderer. Run the existing idempotent installer on the
serve startup path, best-effort so a failure never blocks serve startup.

Fixes #5763.

* fix(serve): install a bare `orca` dispatcher on Linux for Claude Team

On Linux CliInstaller installs the CLI as `orca-ide` (to avoid shadowing GNOME
Orca's /usr/bin/orca), not bare `orca`. But the Claude Team launcher (`orca
claude-teams`), composed client-side by both the desktop renderer and the
mobile app and written verbatim to the host PTY, invokes bare `orca` — which
is unresolved in the initial managed terminal (no agent-teams shim on PATH
yet). The serve-mode CLI install therefore fixed macOS but not Linux.

Add a bare-`orca` dispatcher in the serve branch (host-side, Linux only) that
execs the bundled CLI wrapper. ~/.local/bin is hardcoded ahead of /usr/bin on
the managed-terminal PATH, so it resolves. Plain file (not a managed symlink)
so CliInstaller.removeLegacyLinuxCommandIfManaged leaves it untouched.

* Restore ai-vault files to origin/main (drop stale pre-0.52 oxfmt merge artifact)

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

* Harden serve CLI install: AppImage-safe dispatcher, no-prompt macOS, skip Windows, conflict guard

- Gate CliInstaller.install() to macOS+Linux; Windows would only mutate the
  persistent user-registry PATH without helping the current serve's terminals.
- Inject a non-prompting privilegedRunner so headless macOS never pops an
  osascript admin dialog when /usr/local/bin isn't writable (skips instead).
- Linux dispatcher: exec the stable $APPIMAGE via buildAppImageCliWrapper when
  running from an AppImage (resourcesPath is an ephemeral FUSE mount); skip when
  the bundled orca-ide launcher is absent; never clobber a user-owned ~/.local/bin/orca.
- Single-quote the exec target; add coverage for all new branches.

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

---------

Co-authored-by: Daniel Rudaev <daniel@d1dx.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:12:33 -07:00
cede986d38 fix(browser): restore programmatic focus for CDP text insertion (#7041)
* fix(browser): restore programmatic focus for CDP text insertion

* test(browser): cover the DOM focus replay error path

* fix(browser): serialize DOM.focus replay against pipelined Input.insertText

* refactor(browser): consolidate pending-focus invalidation into one guard

Collapse the three per-handler deletes (Page.bringToFront, Page.captureScreenshot,
catch-all) of the pending DOM.focus replay into a single guarded delete keyed on
'not DOM.focus and not Input.insertText'. States the invariant in one place and
removes the trap where a future early-returning handler forgets to clear the
stale focus. Also clear the map on client teardown and shorten the field comment.

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

* test(browser): annotate mock webContents return type for portable declaration emit

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

* fix(browser): drop pending focus replay when the client disconnects mid-flight

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

* fix(browser): re-check active client after DOM.focus replay round-trip

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

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:12:18 -07:00
3614cbc40c Add default browser action for terminal links (#6129)
* Add terminal link browser context action

* Polish terminal link default-browser action

- Route Open in Default Browser through the shared openHttpLink funnel
  (forceSystemBrowser) so loopback dev-server links get the same
  worktree-label rewrite as shift+click's system-browser path.
- Translate the new menu label in es/ja/ko/zh (was en-only).
- Extract TerminalQuickCommandMenuItem to keep TerminalContextMenu under
  the max-lines lint after adding the link item.
- Hit-test the link only when the menu actually opens (skip on Windows
  right-click copy/paste path).
- Add scheme-safety unit tests (file:/javascript:/smb:/vscode: rejected)
  and a menu-item render/callback test; fix TerminalContextMenu.test
  props for the new required fields.

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

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 14:09:52 -07:00
42de074152 fix(browser): keep isolated profile storage on its partition (#6958)
* fix(browser): keep isolated profile storage on its partition

* fix(browser): keep cloned isolated tabs on their resolved partition

* fix(browser): thread resolved partition through UI profile switches

Keep the isolated-storage invariant universal: UI-initiated profile
switch/create now persist the resolved partition alongside the profile
id, matching the runtime path, so a tab stays on its partition even if
the renderer profile mirror is later stale (issue #6923).

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

* fix(browser): persist resolved partition through session restore

Add sessionPartition to the workspace-session zod schema so the resolved
partition survives persist->load; without it zod strips the field and a
restored isolated tab whose profile mirror is stale at startup falls back
to the shared default partition, reopening the storage leak (#6923).

Fold the webview teardown branches (parent drift or partition mismatch)
into one and re-resolve the viewport container once, matching the
pre-refactor null-guard behavior.

Split the sleeping-agent parse tests into their own file to keep both
under the 800-line cap.

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

* fix(browser): keep CLI-created tabs inheriting the default profile

browserTabCreate without an explicit profile was sending sessionProfileId:
null, which the renderer store treats as 'no inheritance' (its guard is
!== undefined). That forced CLI-created tabs onto the shared default
partition even when the user had configured a default browser session
profile, silently changing behavior a #6923 fix should not touch.

Leave sessionProfileId/sessionPartition undefined when no profile is named
so the renderer applies default-profile inheritance; thread the resolved
partition only when a profile is explicitly chosen.

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

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:58:40 -07:00
Jinwoo-H b0984f8e05 Merge remote-tracking branch 'origin/main' into codex/pr-7260-integration-test
# Conflicts:
#	src/main/browser/cdp-ws-proxy.test.ts
2026-07-03 16:43:43 -04:00
Brennan BensonandOrca d8921a22ad Bump mobile app.json to 0.0.22 (#7261)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:42:09 -07:00
Brennan BensonandOrca 133ebcee5d Update stale mobile Android download links to 0.0.21 (#7262)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:42:02 -07:00
97c30c5ccc fix: drop stale repos fetches so deleted projects don't reappear (#7020) (#7024)
* fix: drop stale repos fetches so deleted projects don't reappear

Deleting a project group with "Remove contained projects" could leave the
removed projects as stale, unusable sidebar rows until an app restart (#7020).
`repos:changed` fires once per removal and the renderer starts an unsequenced
repos fetch per event; an earlier fetch that read pre-removal state could
resolve last and overwrite the newer result, reintroducing the deleted repos.

Guard fetchRepos and fetchReposForAllHosts with a monotonic token so a fetch
drops its own result once a newer repos fetch has superseded it — only the
latest fetch, which reads the final persisted state, applies. Add a regression
test that a stale fetch resolving after a newer one can't resurrect a removed
repo.

* test: isolate stale-fetch race in a dedicated file; scope guard to fetchRepos

Move the #7020 regression test out of repos.test.ts into a focused
repos-stale-fetch.test.ts and add a reject-path case (a superseding fetch
that later rejects must still block the older stale fetch). Scope the
monotonic guard to fetchRepos only: the original shared-counter guard on
fetchReposForAllHosts let an unrelated fetchRepos bump the counter and
abort an in-flight all-host load, dropping every host's repos.

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

* chore: restore origin/main cdp-ws-proxy.test.ts (drop merge artifact)

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

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:40:17 -07:00
Jinwoo-HandOrca bb8e795eb5 Chain e2e specs 6/6 green — gate x drain validation debt paid
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:40:06 -04:00
2c0be62df6 Fix empty nested import folder fallback (#6719)
* fix: allow empty nested import as folder

* Track open-as-folder recovery action and localize its strings

Completes the empty-nested-import fallback: adds the open_as_folder action to the existing add_repo_nested_import_action funnel (integer counts only, no paths) so adoption of the recovery path is measurable, and lands the five-locale catalog entries the new UI strings require.

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

* Pin runtime-kind mock return to the literal union in nested import flow test

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

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:38:20 -07:00
Jinwoo-HandOrca a2037c8aa4 Fix PR CI and guard resume relay during shutdown
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:36:44 -04:00
Brennan BensonandOrca 700b492b1b Fix main typecheck: pin Buffer<ArrayBuffer> in cdp-ws-proxy mid-print test (#7263)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 13:30:55 -07:00
Jinwoo-HandOrca 56d4d6b2b0 Findings + tests: batch windows were the DSR-load gap (19->8.0ms dev); timing tests updated to 2ms windows
Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:30:51 -04:00
Jinwoo-HandOrca e67a91d7af Cut daemon and main PTY batch windows 8ms -> 2ms
At 9% pipeline utilization the DSR-under-load latency is fixed batching
windows, not queue depth (proved by the MessageChannel drain lever
moving nothing). Both hops charged an expected half-window per chunk;
2ms keeps burst coalescing at negligible IPC overhead (~500 msgs/s
worst case vs MB/s payloads).

Co-authored-by: Orca <help@stably.ai>
2026-07-03 16:28:36 -04:00