Commit Graph
947 Commits
Author SHA1 Message Date
Jinjing 4cbf699360 fix: quote queued OMP resumes for Windows shells (#7628) 2026-07-06 18:41:32 -07:00
PP 0b4196fc17 fix(ssh): stop deleted ~/.ssh/config hosts from reappearing on sync (#7302)
Deleting a config-sourced SSH target had no lasting effect: the Manage-SSH pane
re-imports ~/.ssh/config on open, and the import was a pure upsert with no record
of deletions, so the just-deleted host was re-inserted verbatim from the config
that still exists on disk.

Persist a `deletedSshConfigAliases` tombstone set:

- Deleting a config-managed target (source 'ssh-config', or an adopted legacy
  import) records its alias; manual targets are never tombstoned.
- The passive on-open sync skips tombstoned aliases, so a deleted host stays
  deleted.
- Re-adding or editing a target reclaims its alias, and the explicit Import
  action (`reAdopt`) clears all tombstones to deliberately re-adopt config.

This also fixes the edit-then-reappear case: editing a config host to `manual`
already reserved its current alias, and reclaim covers alias changes.
2026-07-06 18:35:42 -07:00
f61500280b feat(ai-vault): add OMP sessions to the AI Vault session browser (#7618)
* feat(ai-vault): add OMP sessions to the AI Vault session browser

Adds OMP ("Oh My Pi") to the AI Vault/Agents catalog so historical
.omp/agent/sessions/**/*.jsonl transcripts are discovered, parsed, and
resumable from the right-sidebar session browser — locally and over SSH.

- Discovery mirrors Pi (OMP_CODING_AGENT_DIR env, WSL home roots, per-agent
  limit) in both the local scanner and the remote/SSH scanner.
- Parses OMP's message-graph JSONL via the shared graph parser (new
  MessageGraphAgent type), capturing the model from model_change.model (OMP's
  key, not Pi's modelId) or the assistant message, and tokens from usage.
- Routes OMP through the incremental parse cache so ~5s rescans resume from
  the last byte instead of re-reading whole transcripts.
- Resumes by absolute transcript path (`omp --resume <path>`) so it resolves
  regardless of which session-dir root (custom OMP_CODING_AGENT_DIR / WSL
  store) the file was discovered under; threaded through both the scanner and
  the renderer's local resume/copy rebuild.
- Renderer reuses the existing OmpIcon/catalog/grouping; adds overflow-x-hidden
  so long worktree chips never widen the sidebar.

Generalizes normalizePiSessionsDir -> normalizeAgentSessionsDir. Verified
end-to-end against 10 real ~/.omp transcripts and rendered in the app.

Co-authored-by: gatsby74 <166927047+gatsby74@users.noreply.github.com>

* fix: make AI Vault parse-cache agent switch explicit

---------

Co-authored-by: gatsby74 <166927047+gatsby74@users.noreply.github.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-06 18:03:36 -07:00
Jinwoo HongandOrca 417723411e perf(source-control): stop gh rate-limit storms and idle git-status spawn churn (#7595)
Co-authored-by: Orca <help@stably.ai>
2026-07-06 15:12:56 -07:00
NeilandOrca e33b2006f4 Remove stale max-lines lint disables from files under the limit (#7548)
110 files carried an eslint/oxlint-disable max-lines directive but are
already under the default max-lines budget (300 .ts / 400 .tsx / 600 .mjs
/ 800 test), so the suppression is dead. Removing it restores real
max-lines coverage on these files with zero behavior change.

Each removed directive had max-lines as its only rule; verified via a
full oxlint run (0 max-lines violations, 0 new errors). Diff is pure
deletions (200 lines, 0 additions) — no code touched.

Co-authored-by: Orca <help@stably.ai>
2026-07-06 02:12:32 -07:00
Brennan BensonandOrca eb8435950a Clear a worktree's merged pull request after it switches to a different branch (#7460)
Co-authored-by: Orca <help@stably.ai>
2026-07-06 01:26:10 -07:00
Brennan BensonandOrca 3826169c11 Keep Claude live-PTY refresh gate closed across restarts; recover wiped runtime credentials (STA-1246) (#7483)
Co-authored-by: Orca <help@stably.ai>
2026-07-06 01:16:23 -07:00
Jinjing 2b5f6af0e9 Respect terminalWindowsShell setting for local Windows agent launches (#7526)
Ensure agent CLI startup and draft launch commands use the correct quoting
format based on the user's configured local Windows shell (e.g., cmd.exe).
This avoids using host settings for remote/SSH targets where local shell
preferences do not apply.
2026-07-06 01:05:56 -07:00
NeilandOrca 88640ef4c6 docs(runtime): fix stale ps-snapshot factory comment after #7518 (#7529)
Co-authored-by: Orca <help@stably.ai>
2026-07-06 00:44:21 -07:00
Jinwoo HongandOrca d9103d08c1 Revert "fix(terminal): launch prior/default agent when a woken terminal can’t resume" (#7524)
Co-authored-by: Orca <help@stably.ai>
2026-07-06 00:27:32 -07:00
NeilandOrca 27ba95cf31 perf(runtime): cache parsed ps rows on POSIX so panes share one parse (#7518)
getProcessTableSnapshot deduped the ps fork (#6288/#6667) but cached only the
raw stdout string on POSIX, so every concurrent agent pane re-ran parsePsRows
over the identical output within each 500ms TTL window — O(M*P) redundant
tokenization + row allocation. The Windows reader already caches parsed rows;
this makes the POSIX default reader do the same by parsing inside the deduped
scan and returning ProcessTableRow[]. Collapses the duplicate parsePsRows in
the main and relay foreground resolvers into one shared parseProcessTableRows.

Co-authored-by: Orca <help@stably.ai>
2026-07-06 00:03:54 -07:00
Neil ce687221d3 lint(unicorn): enable prefer-number-properties, prefer-array-find, prefer-array-index-of (#7516)
Enable three unicorn rules — one correctness, two performance — and fix every
existing violation repo-wide so the rules pass as errors.

prefer-number-properties (76 sites)
- parseInt/parseFloat/NaN -> Number.* : safe aliases (autofixed).
- isNaN -> Number.isNaN (12 sites, hand-converted): global isNaN coerces its
  argument, Number.isNaN does not. Verified every call site already passes a
  number (Number.parseInt results, number-typed fields, Date.getTime()), so the
  conversion is behavior-preserving today and guards against a future non-numeric
  argument silently coercing.

prefer-array-find (26 sites)
- .filter(pred)[0] -> .find(pred); .filter(pred).at(-1) / .pop() -> .findLast(pred).
  Drops the intermediate array and short-circuits.

prefer-array-index-of (5 sites)
- .findIndex(x => x === v) -> .indexOf(v).

Verified: typecheck (node/cli/web) clean, 53 affected suites pass (1679 tests),
oxlint clean repo-wide. mobile/ uses findLast safely (already ships ES2023
.toReversed()); config scripts and e2e helpers run on Node 24.
2026-07-05 23:56:37 -07:00
Brennan Benson 7b7a21e3c7 Give agents access to inline Linear ticket screenshots and media (#7484) 2026-07-05 23:55:56 -07:00
Jinjing 2f52f0d665 fix(pty): deliver multiline agent-launch prompts via bracketed paste (#7487)
* fix(pty): deliver multiline agent-launch prompts via bracketed paste

Multiline agent-launch prompts (claude/codex/opencode argv injection) were
mangled when Orca typed the startup command into the interactive shell. The
command is single-quoted, but its literal embedded newlines survive quoting;
bash readline / zsh zle read every raw LF as accept-line (Enter), so the first
newline submits an unterminated single-quoted command, drops the shell into PS2
(>) continuation, and the rest executes piecemeal — backticks/$ evaluate, quotes
go unbalanced, and the agent never receives the intact prompt. Short single-line
prompts worked because they have no embedded newline.

Fix: when a startup command contains a newline, wrap the payload in
bracketed-paste markers (ESC[200~ … ESC[201~) before the trailing submit CR/LF
so the line editor inserts the multiline text literally and only the trailing
byte submits it. The single-line fast path is unchanged. Gated on the target
line editor having bracketed-paste mode active (Orca-wrapped bash/zsh) so shells
without it never echo the markers as garbage; Orca's bash rc wrappers now force
`enable-bracketed-paste on` (zsh has it on by default).

Applied consistently across every startup-command delivery path:
- src/main/providers/local-pty-shell-ready.ts (in-process / degraded local)
- src/main/daemon/terminal-host.ts (daemon host — primary local)
- src/relay/pty-handler.ts (SSH relay, remote host)
- src/renderer/src/lib/ssh-background-startup-delivery.ts (hidden SSH tab)
All share src/shared/startup-command-submission.ts. Windows cmd.exe and other
shells keep the current CR submit path (no regression); PSReadLine/POSIX
bash/zsh get the fix.

* Fix multiline detection for CRLF-terminated startup commands

Strip the entire CRLF terminator (or lone CR/LF) from startup commands
before checking if the body contains newline characters.

Previously, slicing off only the last character of a CRLF-terminated
command left a trailing CR in the body. This caused a single-line
command to be incorrectly categorized as multiline and wrapped in
bracketed paste.
2026-07-05 21:49:04 -07:00
Brennan BensonandOrca 72a23809fa Prevent OMP terminals from being mislabeled as Gemini (#7447)
Co-authored-by: Orca <help@stably.ai>
2026-07-05 13:39:38 -07:00
Jinjing e7d1fa4a21 Disable auto-merge for unstable GitHub PRs (#7415)
Prevent enabling auto-merge when a PR is in an UNSTABLE merge state.
GitHub auto-merge mutations reject UNSTABLE PRs directly instead of
allowing them to wait, so we should suppress the option.
2026-07-05 11:05:58 -07:00
Jinwoo HongandOrca 9981c3b827 Check for Updates: cmd/ctrl-click fetches latest perf-tagged prerelease (#7278)
Co-authored-by: Orca <help@stably.ai>
2026-07-05 02:53:17 -07:00
Jinwoo Hong 812f24bd19 fix(terminal): clear PTY-side buffers on Ctrl+K so the prompt stops repainting at a stale row (#7413) 2026-07-05 04:36:24 -04:00
JinjingandOrca a5cdb7711d Add MiniMax rate-limit tracking and secure cookie storage (#7411)
* Add MiniMax rate-limit tracking and secure cookie storage

* Securely store MiniMax session cookies using an encrypted envelope format and local file hardening.
* Fetch rate limits in an isolated session partition and clear the cookie jar before and after requests to prevent leakage.
* Add a default-on "minimax" status bar item to display subscription usage.
* Expose minimax configuration settings (group ID and models) in settings panes and sync them via the runtime client.
* Isolate MiniMax config resolver and decryption failures from affecting other rate-limit providers.

* Redact MiniMax secrets with whitespace around colons

Update redactMiniMaxSecret to allow and match optional whitespace
surrounding the colon when redacting quoted cookie values. This matches
the spacing tolerance used during parsing.

* Address PR review: harden cookie read, validate IPC, add tests

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-05 01:15:16 -07:00
guihirsch f11a2109c8 feat(rate-limits): add MiniMax token control (#7387) 2026-07-04 23:33:25 -07:00
Avichal DwivediandJinjing e94c83d164 fix(ai-vault): make SSH session history host-aware (#7367)
* fix(ai-vault): scan sessions by execution host

* fix(ai-vault): route history resume by host

* test(e2e): cover SSH AI Vault history

* Generalize remote session scanning for all AI Vault agents

Replace the Codex-only remote SSH session history scanner with a
unified scanner supporting all registered agents. This ensures remote
transcripts for Claude, Gemini, Devin, Droid, and others are scanned
and listed alongside local history.

- Propagate host metadata (host ID and platform) to scanned sessions
- Scope remote actions by host, disabling local OS path actions on
  remote session logs
- Resolve ambiguous project/worktree matching for overlapping paths
  by verifying matching host setup IDs
- Update tests and E2E specs to validate multi-agent remote scanning

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-04 22:56:55 -07:00
NeilandOrca 91323cf925 perf(windows): dedupe per-pane process-table scans in agent inspection (#7384)
* perf(windows): dedupe per-pane process-table scans in agent inspection

Windows agent foreground-process inspection forks a whole-process-table
PowerShell/CIM scan per pane on the same 750ms/2000ms cadence the POSIX path
uses. The POSIX side routes through getProcessTableSnapshot (500ms TTL + single
in-flight, #6288/#6667), collapsing N concurrent panes to ~2 scans/sec. The
Windows path (queryWindowsProcessDescendants) had no such dedup: K concurrent
agent panes forked K powershell.exe cold-starts, each enumerating the ENTIRE
process table then filtering per-pid in JS — ~10-40x heavier than `ps` (a
powershell cold start is ~150-400ms CPU + tens of MB RSS). The degraded/local
PTY provider path calls it with no per-pane throttle at all. This is the
Windows analogue of the idle-CPU churn #6288 fixed for POSIX.

Generalize the existing createProcessTableSnapshotReader factory to be generic
over its scan result (default T = string, so the POSIX path and its test are
byte-identical) and add a Windows singleton reader that caches parsed
WindowsProcessRow[]. queryWindowsProcessDescendants now reads the shared
snapshot and runs its own descendant walk; runWindowsProcessRows throws on total
enumeration failure so the miss is not cached and the prior null-fallback
contract (callers fall through to node-pty's name) is preserved.

Windows scan-volume regression test (mirrors the POSIX #6288 guard) drives
PANE_COUNT concurrent panes over the cadence window and asserts powershell.exe
spawns are bounded by ticks, not pane count, while every pane still resolves its
descendant. Reverting the dedup fails both cases. POSIX snapshot + volume tests
unchanged and green; node/web/cli typecheck clean.

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

* test: reset windows process-rows snapshot between agent-foreground cases

The new module-level Windows rows reader caches for 500ms with real
Date.now(), so one case's mocked process table was served to the next
case's assertions (7 CI failures in agent-foreground-process.test.ts).
Mirror the suite's existing POSIX resetProcessTableSnapshotForTests()
with the Windows reset in beforeEach.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-04 18:10:45 -07:00
Vladislav Meshkorudnyj fa3ca498c2 fix(secure-file): re-harden on coarse-ctime filesystems
Store POSIX mode bits in secure-file hardening cache entries so permission drift is detected even when ctime granularity is coarse.

Also clears inherited HISTFILE in the local PTY test harness for hermetic WSL history assertions, and adds a deterministic coarse-ctime regression test for directory and credential-file mode drift.
2026-07-04 14:38:05 -07:00
mehmet turac ccfd6727c9 fix(browser): route focused guest zoom shortcuts to page zoom (#6744)
Route focused browser guest zoom shortcuts to the browser page zoom path, including native Electron zoom-command fallback and wheel/native dedupe.
2026-07-04 08:17:55 -07:00
Jinjing 0d8205ae73 Validate terminal startup CWD paths against symlink escapes (#7334)
Resolve terminal CWD and worktree paths to their canonical form using
realpath before validating containment. This blocks symlink escape
routes for local terminal spawns, returning the default workspace
directory if a requested path attempts to escape the worktree.

- Local terminal paths are canonicalized using native realpath logic
- WSL UNC paths and SSH/remote terminals skip canonicalization
- Floating terminal startup directories bypass containment checks
- Missing or unresolvable workspace directories default safely
2026-07-04 01:31:09 -07:00
Jinjing 7c77ccab7d Fix notes send targets for manual agents (#7300)
* Fix notes send targets for manual agents

* Split agent title merging into manual and launch-agent paths

Separate the merging logic for terminal titles depending on whether the
tab has a launch agent or is a manually started CLI.

- Launch-agent tabs carry an owner bit, allowing their live titles to
  promote a stale status row on the same pane.
- Manually started agents have no owner bit, so they only ever add a
  row and must not override existing status evidence.
- Remove the temporary TitleHintAgentTarget type and the need to strip
  metadata when pushing targets.
2026-07-04 00:10:53 -07:00
Neil 3fdeec7c2f cleanup(renderer): drop dead code, dedupe helpers, skip wasted work, fix garbled comments (#7322)
Quality pass on renderer/shared PRs merged 2026-07-03:

- WorktreeTitleInlineRename: skip the truncation measure + ResizeObserver in `wrapTitle`
  mode, where wrapped titles never truncate — it could only churn unused state (#7307).
- editor slice: reuse the `removeEditorStateForReplacedPreview` helper this PR added
  instead of a hand-rolled copy of the same six-field eviction (drops ~50 lines) (#6476).
- useFileExplorerTree: extract `readWorktreeDirectory` so the connectionId/settings
  assembly for `readRuntimeDirectory` lives in one place, not three (#6321).
- comment-markdown-github-attachment-media: extract a shared `AttachmentFallbackLink`
  for the image/video error-fallback link (#6759).
- repository-icon-github: fold the two near-identical live resolvers into one
  parameterized `resolveRepositoryIdentityLive`; trim a 3-line comment to 2 (#6507).
- resource-usage-open-slices: delete the `shouldReadPopoverSlices` identity wrapper and
  inline `open` at the four call sites (#7275).
- BrowserPane: drop the pointerEvents assignment already applied inside
  `ensureBrowserPageWebview` for the reused-webview path (#6958).
- github slice: fix two garbled "…a commit main confirmed…" comments (#7277).
- runtime-file-client: trim the binary-file fallback comment to its whys (#6606).
- composer-branch-selection: drop the inline comment that restated the JSDoc (#6748).
- TabBarQuickCommandsButton: correct the stale "+ Command" comment (button shows no +).

No behavior change (the editor-helper reuse is behavior-equivalent, only more
conservative on an edge case); typecheck, oxlint, react-doctor, oxfmt, and touched
unit suites all pass.
2026-07-03 22:31:56 -07:00
Brennan BensonandOrca bdd8bb0a3b fix(agent-status): keep harness-injected turns out of sidebar prompt labels (#7274)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 19:49:17 -07:00
Brennan BensonandOrca b099e27703 fix(checks): keep a merged PR visible when the worktree sits behind its own PR head (#7277)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 19:30:10 -07:00
f7a4100bc7 Preserve slash branch names from branch composer (#6748)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <charlie-eng@stably.ai>
2026-07-03 17:33:22 -07:00
8796261eed feat: allow custom worktree branch names (#6454)
* feat: allow custom worktree branch names

* refactor(ui): render custom branch name field unconditionally under advanced container

* fix(composer): hide manual branch field when a work-item source drives the branch

A tracked PR/issue/MR/Linear source derives the branch itself, and a linked
GitHub PR re-resolves the branch name at submit — so an override typed in the
Advanced branch field was silently ignored. Only render the field for the
typed-name and base-branch flows, where the manual override is honored.

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

---------

Co-authored-by: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-03 17:21:50 -07: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
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
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
2153ef9456 Accept any hostname (and optional :port) in manual network address entry (#7223)
* Allow arbitrary hostnames in manual network address entry

parseManualNetworkAddress only accepted an IPv4 address or a Tailscale
MagicDNS (*.ts.net) hostname, so users behind a dynamic residential IP
who rely on a DDNS domain or self-hosted relay had no way to enter it
in the desktop UI short of bypassing validation via DevTools/IPC.

The main process already resolves any host: resolvePairingEndpoint
and parsePairingAddressOverride in src/main/runtime/runtime-rpc.ts
accept an arbitrary hostname and an optional host:port. This change
brings the renderer-side validation in line with what pairing already
supports: any RFC 1123 hostname (a superset that still covers
*.ts.net), optionally suffixed with :port (1-65535). IPv4 validation
is unchanged, including still rejecting malformed dotted-numeric input
instead of silently treating it as an all-digit hostname.

Updates the custom-address dialog copy in NetworkInterfacePicker.tsx
to describe the wider grammar.

* Polish manual-address takeover: fix bare-numeric guard, sync 5 locales, lint

- Require a dot in the IPv4-typo guard so a bare numeric label (`123`)
  validates as a legal RFC 1123 hostname, matching the code's own comment
  and the main-process resolver; add coverage.
- Update en.json + es/ja/ko/zh placeholder/hint to the broadened grammar
  (translate() reads en.json before the TSX fallback, so the copy change
  was previously inert; the other locales described the old ts.net-only rule).
- Replace indexOf(...)!==-1 with includes() to satisfy oxlint.

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

* Keep validator a strict subset of the backend resolver

Review surfaced two ways the renderer could accept an address the main
process handles differently:
- All-numeric hosts (bare `123` and dotted `256.0.0.1`) are now rejected.
  The WHATWG URL host parser downstream reinterprets a numeric host as IPv4
  (`123` -> `0.0.0.123`), so accepting one would validate an address the
  pairing resolver silently dials as a different host.
- Ports with leading zeros are rejected. `^[0-9]+$` let an arbitrarily long
  zero-padded string past the range check and inflate the returned address
  beyond the hostname length cap that the old whole-string check enforced.

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

* Reject any numeric final label, not just fully-numeric hosts

WHATWG URL host parsing treats a host whose last label is numeric
(`foo.123`, `foo.0x1`) as an IPv4 signal, so the pairing resolver would
fail to parse it and silently dial a fallback host. Widen the ambiguous-IP
guard to a single last-label check that subsumes the earlier all-numeric
case, keeping the renderer a strict subset of what the backend resolves
correctly. Normal hostnames whose last label merely contains digits
(`host2.example.com`) are unaffected.

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 12:52:55 -07:00
Dvitash 0ff2c09002 Fix typed OMP remote title flicker (#6954) 2026-07-03 00:26:37 -07:00
Neil 185b768609 Add rich Markdown spellcheck setting (#7103) 2026-07-02 21:59:41 -07:00
Brennan BensonandOrca c06507ee30 Open terminal file links on mobile (#7134)
Co-authored-by: Orca <help@stably.ai>
2026-07-02 18:17:47 -07:00
gatsby74 5da41d4ed6 [codex] Add file explorer open in terminal
Add an Open in Terminal action for file-explorer directories and preserve terminal startup cwd through restore/session paths.
2026-07-02 16:47:38 -07:00
Brennan Benson e44daf37a3 Match main terminal mirror character widths to the renderer (#7148) 2026-07-02 14:50:15 -07:00
Brennan Benson 4c03924618 Show Git-created worktrees in external discovery (#7078) 2026-07-02 11:24:07 -07:00
Neil 366746ad2b Support Claude weekly Fable usage meter (#7079)
* Support Claude weekly Fable usage meter

* Reference Claude weekly usage research

* Add distinct Claude Fable weekly meter

* Tighten Claude Fable usage parsing
2026-07-02 01:34:44 -07:00
4dbc9f3817 feat(ssh): add ControlMaster multiplexing for system SSH transport (#6922)
* feat(ssh): add ControlMaster multiplexing for system SSH transport

System SSH transport spawns a new OpenSSH process per exec command
(platform detect, relay install check, node resolution, relay launch,
socket probe). Each process pays the full SSH handshake cost — ~9s on
Uber devpods — making a typical relay connect take 54s+ and reliably
exceeding the 15s startup reconnect budget.

Add SSH ControlMaster multiplexing via a per-target socket in
$TMPDIR/orca-ssh-ctl/<hash>.sock. The first command establishes the
master; subsequent commands reuse it at ~100ms per exec instead of ~9s.
ControlPersist=300 keeps the master alive after commands exit so rapid
reconnects (e.g. on tab focus) also benefit. Windows is excluded since
OpenSSH's ControlMaster support there is limited.

* fix(ssh): address ControlMaster key collision and directory permission risks

- Use target.id in the socket key so distinct SSH targets can never
  collide even when configHost/port/user happen to match
- Switch from SHA1 to SHA256 and extend hash slice from 12 to 16 chars
- Stat the control-socket directory after mkdirSync to reject pre-existing
  dirs that are symlinks, foreign-owned, or have group/other write bits
  (mkdirSync mode is ignored on pre-existing dirs)
- Update two tests that used exact spawn-arg arrays; replace with
  ordering assertions (forward flags before --) that stay correct
  regardless of which extra ControlMaster options are injected

* fix(ssh): bind ControlPath identity to route and reject symlinked ctl dir

Fold proxyCommand/jumpHost/identity fields into the ControlPath hash so a
target whose route is edited no longer reuses a still-alive master built on
the old route. Switch the control-socket dir check from statSync to lstatSync
so a planted symlink fails the directory validation outright.

* test(ssh): drop tautological argv re-assertion in spawn checks

The toHaveBeenCalledWith re-passed the args array extracted from the same
mock call, making that argument position always pass. argv content is
already verified by the index-ordering assertions above; use expect.any(Array)
so the spawn check only claims what it actually verifies (binary path, stdio).

* fix(ssh): harden system ssh connection reuse

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

* test(ssh): isolate control socket runtime dir

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

---------

Co-authored-by: Test <test@example.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-01 21:29:48 -07:00
Jinwoo HongandOrca f8c1f0fdf8 Fix delayed TUI mouse wheel reports (#7060)
Co-authored-by: Orca <help@stably.ai>
2026-07-01 19:54:53 -07:00
Eddie JaoudeandJinjing e0a7f0eadd fix: reordered default columns in kanban board (#6934)
* fix: reordered default columns in kanban board

* Introduce dedicated flag to repair reversed default workspace statuses

- Add `_workspaceStatusesReorderedDefaultRepaired` to decouple the
  one-shot repair from the initial status order migration.
- Ensure the repair runs for users who saved the reversed default
  payload (with "Done" on the left) during a short-lived broken build.
- Support both "Completed" and "Done" labels when identifying default
  status shapes to migrate or repair.

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-01 13:17:52 -07:00
cbd06a7671 feat(tab-bar): add shortcut to open commands for active tab group (#6325)
* Add keyboard shortcut to toggle the Quick Commands menu

- New `tab.openQuickCommandsMenu` keybinding action (no default binding)
- TabBarQuickCommandsMenu listens for the binding and toggles open/closed
- Scoped to the active tab group naturally since the component only mounts when its group is focused

* Show keyboard shortcut in Quick Commands menu trigger tooltip

* Add tests

* expand tests

* Expand keyboard toggle to call handleOpenChange and skip repeated keys

- Replace `setMenuOpen` toggle with `handleOpenChange(!menuOpen)` so closing
  via keyboard runs the same reset logic (query, focus frame, value override)
- Guard against key-repeat events to prevent rapid toggling on held key
- Wrap `handleOpenChange` in `useCallback` so it's stable enough to include
  in the `useEffect` dependency array without causing spurious re-registrations
- Update tests to reflect that re-running the effect between presses is
  required for the close path, and add a repeat-event test

* Add docstring to withShortcutHint func

* review: harden quick commands menu shortcut

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-06-30 18:21:37 -07:00
Jinwoo HongandOrca 782eb12688 Make remote SSH terminals persistent by default (#6955)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 16:16:10 -07:00
Jinwoo HongandOrca d7010353ca Move per-workspace environments to Experimental settings (#6926)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 12:57:39 -07:00
Wolfie 62ab2d470e fix: keep floating tabs local with active runtime
Keep the synthetic floating workspace local while a remote runtime is active, including terminal/browser creation, activation, close, and remote snapshot handling.

Maintainer follow-ups:
- require worktreeId for runtime-session terminal create payloads
- add renderer-backed terminal create reply sender regression coverage
- merge current main and keep the WSL readDir breadcrumb test aligned with main's Windows-only handler coverage
2026-06-30 12:48:26 -07:00
Jinwoo HongandOrca 39964149c8 Per-Workspace Environments (on-demand disposable runtimes) + Add Project remote host setup (#6320)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 11:31:55 -07:00