Commit Graph

67 Commits

Author SHA1 Message Date
Jinwoo Hong e83d92eede
Mobile: server-authoritative phone-fit state machine + race fixes + UX cleanup (#1518)
Co-authored-by: Orca <help@stably.ai>
2026-05-06 21:54:23 -07:00
Jinwoo Hong 087c00b02e
Mobile: stabilise connection + terminal-fit fixes + share one RpcClient per host (#1481)
Co-authored-by: Orca <help@stably.ai>
2026-05-05 18:58:13 -07:00
Brennan Benson 6f2e31afad
feat(telemetry): PR 4 — wire 7 core events to call sites (#1433)
Co-authored-by: Orca <help@stably.ai>
2026-05-05 11:57:51 -07:00
Jinwoo Hong 705be9e312
feat(status-bar): consolidate memory + sessions into Resource Usage segment (#1415)
Co-authored-by: Orca <help@stably.ai>
2026-05-05 11:38:18 -07:00
Jinjing 5ce9c3b481
feat(tasks): remember tasks page resume state across sessions (#1442)
Persist transient Tasks page position (GitHub mode, active preset/query,
Linear preset/query) in PersistedUIState so reopening Tasks restores the
user's working context instead of falling back to defaults. Source, repo
selection, team selection, and active project keep using their existing
settings paths.

Co-authored-by: Orca <help@stably.ai>
2026-05-05 11:19:50 -07:00
Neil 479f5c488d chore: move Autohand Code listing after Auggie in READMEs and agent catalog
Co-authored-by: Orca <help@stably.ai>
2026-05-05 00:27:36 -07:00
Igor Costa 38b77afb8d
Add Autohand Code agent support (#1382) 2026-05-05 00:25:37 -07:00
Jinwoo Hong d1b26e2eb7
Mobile improvements: scrollback hydration, keyboard layout, and worktree-creation polish (#1423)
Co-authored-by: Orca <help@stably.ai>
2026-05-04 23:24:22 -07:00
Jinjing 56b69f8d8f
docs: remove stale design docs (#1425)
Co-authored-by: Orca <help@stably.ai>
2026-05-04 23:05:05 -07:00
Neil 9f1ccf44d0
fix(readme): correct Kimi CLI link and swap Anthropic favicon for Claude glyph (#1405)
Co-authored-by: Orca <help@stably.ai>
2026-05-04 13:21:56 -07:00
Neil e7619b7334
fix(readme): replace Droid favicon with local black-bg SVG (#1404)
Co-authored-by: Orca <help@stably.ai>
2026-05-04 13:11:24 -07:00
Jinwoo Hong fc578f5ea9
feat(mobile): Expo companion app [beta] (#1245)
Co-authored-by: Orca <help@stably.ai>
2026-05-04 13:08:27 -07:00
Jinjing 375a3e6351
feat(sidebar): path-aware filter in SSH remote file browser (#1384)
Typing a path like `Documents/orca-internal` in the browse filter now resolves the path on the remote instead of producing "No matches". Supports `~`, absolute, and relative paths with live preview and Enter to navigate.

Co-authored-by: Orca <help@stably.ai>
2026-05-04 00:01:04 -07:00
Jinjing fd6abb5808
fix(cmd-j): rank empty-query worktrees by focus recency (#1383)
* fix(cmd-j): rank empty-query worktrees by focus recency

Persist a per-worktree focus-recency timestamp and use it as the primary
ordering signal for Cmd+J's empty-query Worktrees section, so SSH and
other quiet worktrees surface based on user focus rather than background
activity. See docs/cmd-j-empty-query-ordering.md.

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

* fix(tests): guard lastVisitedAtByWorktreeId and mock markWorktreeVisited

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-03 22:55:11 -07:00
Jinwoo Hong a638215729
fix(pty): release ptmx fd on natural exit + defuse SIGHUP-to-recycled-pid (#1327)
* fix(pty): release ptmx fd on natural exit + defuse SIGHUP-to-recycled-pid

Daemons accumulated ptmx fds over time because node-pty's UnixTerminal
only releases the master fd when destroy() runs. On the natural-exit
path (the common case — user closes a tab, shell runs `exit`) nothing
ever calls destroy(), so the fd leaks until GC. On macOS this
eventually hits kern.tty.ptmx_max=511 and all new terminals fail to
spawn.

Fix: release the fd synchronously on every teardown path (natural
exit, explicit kill, stale SSH spawn, daemon shutdown) and close the
concurrent SIGHUP-to-recycled-pid hazard inside node-pty's
UnixTerminal.destroy().

- src/main/daemon/pty-subprocess.ts: synchronous POSIX proc.kill
  neutralization inside proc.onExit; dead guards on forceKill/signal
  so they never target a reaped-and-possibly-recycled pid
- src/main/daemon/session.ts: new disposeSubprocess() for already-
  exited sessions (fd release only, no SIGKILL) — avoids sending
  SIGKILL to a recycled pid during daemon shutdown
- src/main/daemon/terminal-host.ts: dispose loop routes on isAlive —
  live sessions get forceKillAndDisposeSubprocess (SIGKILL + fd
  release), exited sessions get disposeSubprocess (fd release only)
- src/main/providers/local-pty-provider.ts: same POSIX kill
  neutralization at top of onExit for the legacy local path
- src/relay/pty-handler.ts: same neutralization in wireAndStore;
  disposed flag guards all public entry points; dispose() uses
  SIGKILL (not SIGTERM) before destroy since the relay is exiting;
  killTimer fallback + immediate-shutdown + stale-spawn cleanup all
  call disposeManagedPty + ptys.delete so wedged children (D-state,
  bad NFS) can't leak map entries against the 50-PTY cap

Windows is exempt everywhere — WindowsTerminal.destroy IS a kill()
call internally (closes the ConPTY agent), so neutralizing would
turn destroy into a no-op and leak the agent.

See docs/fix-pty-fd-leak.md for the full design.

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

* fix(pty): patch node-pty native off-by-one leaking /dev/ptmx per spawn

node-pty 1.1.0's pty_posix_spawn on macOS walks low_fds[0..2] in an
allocation loop that breaks at the first fd >= STDERR_FILENO, then
cleans up via `for (; count > 0; count--) close(low_fds[count])`. In
the typical case (break at count=0) the cleanup body never runs and
low_fds[0] — a /dev/ptmx handle — leaks per spawn. Fixed upstream in
microsoft/node-pty af053f2 (PR #882), not in any 1.1.0 release.

Backport the 3-line cleanup-loop fix as a pnpm patch. E2E validated
against a dev daemon: 200 spawn/kill cycles kept the daemon's ptmx
fd count flat at baseline; prior runs reproduced linear 1-per-spawn
growth. Also documents the native root cause as a status addendum in
docs/fix-pty-fd-leak.md — the JS-side destroy() discipline previously
landed is still load-bearing for the SIGHUP-to-recycled-pid hazard and
for synchronous fd release on daemon shutdown.

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

* fix(pty): capture stable kill spy ref in pty.test.ts

destroyPtyProcess reassigns proc.kill = () => {} on POSIX to defuse
the SIGHUP-to-recycled-pid hazard (see docs/fix-pty-fd-leak.md). After
that reassignment, proc.kill.mock is undefined and the assertions
crashed in CI. Capture a stable reference to the vi.fn() before it
gets reassigned.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-02 23:12:14 -07:00
Jinwoo Hong 827b84d27a
fix(runtime): add single-instance lock + owned-metadata clear (#1312) (#1326)
* fix(runtime): add single-instance lock + owned-metadata clear to prevent orca-runtime.json corruption

Closes #1312.

Every AppImage/.app relaunch was booting a fresh Electron main that clobbered
`<userData>/orca-runtime.json` and `agent-hooks/endpoint.env`. When the newest
instance quit, metadata pointed at a dead pid and `orca status` reported
`stale_bootstrap` even though the original Orca was still running. SIGKILL'd
predecessors also left orphaned `o-<pid>-*.sock` files in userData.

Three surgical changes:

1. `app.requestSingleInstanceLock()` in a new
   `src/main/startup/single-instance-lock.ts` helper, wired into
   `src/main/index.ts` after `configureDevUserDataPath(is.dev)` so dev and
   packaged runs lock in separate namespaces. Losing instances focus the
   primary's window via `second-instance` and quit without touching userData.

2. `clearRuntimeMetadataIfOwned(userData, pid, runtimeId)` in
   `runtime-metadata.ts` — compares both pid AND runtimeId against the
   current file before clearing, so the auto-updater handoff window never
   erases the replacement process's fresh bootstrap. Called from a rewritten
   `will-quit` handler that folds `runtimeRpc.stop()` + owned-clear into the
   same `Promise.allSettled([disconnectDaemon, …]).then(app.quit)` chain
   (inside the `!daemonDisconnectDone` guard so the second-pass re-entry
   can't re-invoke stop+clear).

3. `sweepOrphanedRuntimeSockets()` in `runtime-rpc.ts` runs at the top of
   `start()` on POSIX, using `process.kill(pid, 0)` to probe liveness and
   remove `o-<dead-pid>-*.sock` orphans left by SIGKILL/OOM-kill.

Tests (37 new/updated):
- `single-instance-lock.test.ts` (3): lock-failed does not register listener;
  lock-acquired registers exactly one; callback dispatches correctly.
- `runtime-metadata.test.ts` (+4): clearRuntimeMetadataIfOwned matched /
  pid-mismatch / runtimeId-mismatch / no-file branches.
- `runtime-socket-sweep.test.ts` (4): own-pid-skip / alive-retain /
  dead-sweep / regex-miss separated via synthetic ownPid=1; two
  regex-invariant tests assert the sweep regex matches the real
  `createRuntimeTransportMetadata` output (including the 'rt' fallback).

Design doc: `docs/fix-missing-single-instance-lock.md`.

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

* fix(runtime): focus hidden windows on second-instance event

focus() alone is a silent no-op when the primary window is hidden
(close-to-tray on macOS via Cmd+W, or on a different macOS Space) or
behind other apps on Windows. Call show() before focus() so a second
launch attempt reliably surfaces the existing window regardless of
state.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-02 23:05:14 -07:00
Jinjing 547448e15c
refactor: rename pet → sidekick across codebase (#1334)
Renames the experimental pet overlay to "sidekick" with themed character
names (Claude the Mage, OpenCode the Rogue, Gremlin the Trickster).
Covers IPC channels, preload API, persisted UI state, settings flag,
on-disk userData path, components, and types.

Deletes the standalone pet-overlay design mock.

Co-authored-by: Orca <help@stably.ai>
2026-05-01 18:40:52 -07:00
Jinjing d287342f99
feat: add experimental pet overlay (#1331)
* feat: add experimental pet overlay

Adds an opt-in 3D pet overlay pinned to the bottom-right. Gated behind
an experimental flag so three.js + GLB models stay out of the renderer
bundle for users who never enable the feature. Ships with four bundled
models plus user-uploaded custom GLBs via a pet:import IPC; a status-bar
segment provides model picker + hide toggle.

See docs/design/pet-overlay.md for the full design.

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

* refactor(pet): replace 3D GLB models with 2D webp images

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

* chore(pet): compress pet webp images and remove unused assets

Reduce resources/claude.webp, gremlin.webp, opencode.webp sizes; drop
the obsolete pet-overlay design doc and compress-pet-glb script now
that the GLB pipeline has been replaced by 2D webp images.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-01 16:18:21 -07:00
Neil 17110818c6
docs: fix README header alignment (#1320) 2026-05-01 12:46:56 -07:00
Neil 8d56823998
docs: localize README install updates (#1319) 2026-05-01 12:38:59 -07:00
Neil ff22944fd7
feat(release): publish Orca as a Homebrew cask (#1304)
Co-authored-by: Orca <help@stably.ai>
2026-05-01 00:33:21 -07:00
Jinwoo Hong 03e7284e3c
fix: prevent 401 errors from CLI-refreshed tokens being clobbered (#1286)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 22:24:10 -07:00
Jinjing be0e3c2fa7
fix: handle unhydrated store in file-explorer→terminal drop (#1296)
getConnectionId returns undefined during store hydration, which was
misclassified as remote by `!== null` check. Changed to `typeof === 'string'`
so unhydrated state falls through to client-OS quoting, consistent with
terminal-drop-handler.ts behavior.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 20:39:04 -07:00
Jinwoo Hong cb73b372ff
feat(file-explorer): support drag-and-drop file import over SSH (#1279)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 01:28:43 -07:00
Jinjing 572ed1a888
fix(terminal): inherit source pane cwd on split (Cmd+D) (#1243)
* Wip

* fix(terminal): make split-pane cwd resolution reliable on macOS

Coalesce and cache per-pid lsof calls in the main process, and raise the
renderer's IPC timeout to 1s so cold lsof lookups (typically 100–500ms,
occasionally ~1s) don't fall back to the worktree root.

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

* chore: remove stray screenshot and harden daemon getCwd test

- drop orca-before-split.png accidentally committed in the Wip commit
- accept null OR string from getCwd in the daemon test, since the new
  terminal-host fallback calls resolveProcessCwd(pid) and the mock pid
  55555 could resolve against a live process on CI

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-04-29 15:54:07 -07:00
Neil eb92ba9448
fix(terminal): advertise kitty keyboard protocol for Shift+Enter (#1247)
Orca's terminal already encodes Shift+Enter as the kitty CSI-u sequence
`\x1b[13;2u`, but without `vtExtensions.kittyKeyboard` xterm.js never
answers the `CSI ? u` probe. CLIs that gate enhanced input on that
handshake (Claude Code, Codex, etc.) therefore drop the extended bytes
and treat Shift+Enter as a plain Enter — most visibly when running
inside tmux, which strips extended-key encodings by default.

- Enable `vtExtensions.kittyKeyboard` in the default terminal options
  (matches VS Code's xtermTerminal).
- Lock in the flag with a regression test in pane-lifecycle.test.ts.
- Add docs/terminal-extended-keys.md explaining the Orca side and the
  tmux-side `set -s extended-keys on` + `terminal-features xterm*:extkeys`
  users need for nested Shift+Enter to reach a CLI.

Verified end-to-end in Electron: `cat -v` + Shift+Enter now prints
`^[[13;2u`, and `printf '\e[?u'` elicits the expected `CSI ? 0 u` reply
from xterm.js.

Co-authored-by: Orca <help@stably.ai>
2026-04-28 23:56:29 -07:00
Jinjing 374f821b70
improve remote folder picker UI (#1240)
- polish remote folder picker layout and button borders
- wip in improving remote folder picker

Co-authored-by: Orca <help@stably.ai>
2026-04-28 18:52:31 -07:00
Neil 8e5d19eae3
fix(agents): use Kilocode brand logo instead of illegible favicon (#1224)
Co-authored-by: Orca <help@stably.ai>
2026-04-28 12:38:17 -07:00
Jinjing bdf5f66ffd
feat(nav): back/forward traverses Tasks page visits (#1207)
Widens worktree nav history entries to string | 'tasks' so the titlebar
back/forward buttons and Cmd/Ctrl+Alt+Arrow shortcut work from the Tasks
page. openTaskPage records a 'tasks' entry; closeTaskPage rewinds the
index when parked on one; goBack/goForward dispatches Tasks entries via
a separate view activator to bypass openTaskPage side effects.

Co-authored-by: Orca <help@stably.ai>
2026-04-27 23:49:34 -07:00
Brennan Benson 812ca5488b
fix(preload): collapse index.d.ts into type-checked api-types.ts (#1197)
Co-authored-by: Orca <help@stably.ai>
2026-04-27 21:46:17 -07:00
Jinjing 099c4089a7
refactor(search): share rg/git-grep logic between main and relay (#1157)
Extracts rg and git-grep search logic into src/shared/text-search.ts so
the local main and SSH relay paths stop reinventing arg construction,
JSON parsing, submatch regex, and accumulator/truncation semantics.

Fixes silent truncation in the relay: searchWithRg used execFile with
a 50MB maxBuffer cap that rg --json easily exceeds on large repos,
dropping matches with no error surfaced to the user. The relay now
streams via spawn, matching the local path.

See docs/design/share-text-search.md for full rationale.

Co-authored-by: Orca <help@stably.ai>
2026-04-27 00:06:00 -07:00
Jinwoo Hong 6729825bc0
feat(ssh): persist and auto-restore SSH sessions across app restarts (#1026) 2026-04-25 20:15:02 -07:00
Jinjing 96d6354b0e
docs(readme): add Annotate AI Diff feature, SSH support, and Spanish translation (#1080) 2026-04-25 00:01:53 -07:00
Jinjing aa10811780
fix: address review findings (#1078)
- fix: address review findings
- wip
- wip
2026-04-24 21:58:21 -07:00
Jinwoo Hong bec6a5c508
feat(tasks): persist last-used task source (GitHub/Linear) (#1071) 2026-04-24 20:29:41 -07:00
Neil 2ae9392b72
Rename add repo copy to add project (#1014) 2026-04-23 19:02:36 -07:00
Jinwoo Hong 6c6416a949
feat(codex-accounts): shared runtime home for account switching (#768) 2026-04-17 21:51:06 -07:00
Neil 9962655492
docs: remove extra text 'X' from twitter badge (#781) 2026-04-17 17:02:51 -07:00
Neil bbadd1f12a
docs: match X (Twitter) badge styling with others (#780) 2026-04-17 17:01:01 -07:00
Neil f15341db97
docs: update x (twitter) icon in readme (#779) 2026-04-17 16:58:44 -07:00
Brennan Benson e4cdb29a01
feat: enable split groups renderer path (#669) 2026-04-15 13:12:54 -07:00
Jinwoo Hong f5b716a760
feat: add browser tab search to Cmd+J jump palette (#675) 2026-04-15 12:54:56 -07:00
Brennan Benson c889e95d65
refactor: gate split group surface ownership in Terminal.tsx (#642) 2026-04-14 20:19:11 -07:00
Ramzi fb5afc3aab
feat: add .mmd/.mermaid file viewer with rendered diagram toggle (#597)
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-04-14 19:26:55 -07:00
Brennan Benson 3b897d255d
feat: add split group UI with tab-bar context menus and resize handles (#646) 2026-04-14 19:01:11 -07:00
Brennan Benson cfe49ff404
fix: restore worktrees through tab group ownership (#645) 2026-04-14 17:01:58 -07:00
Brennan Benson c4460f8820
fix: harden terminal pane lifecycle for split groups (#641) 2026-04-14 16:23:01 -07:00
Brennan Benson 741974c59c
refactor: add split group model foundations (#644) 2026-04-14 14:39:01 -07:00
Jinwoo Hong 60a092686b
perf: systematic performance optimizations (#623) 2026-04-14 00:28:56 -07:00
Jinjing 28a1c93c8c
feat: allow dropping external files into the file explorer (#618)
Add support for dragging files from the OS into the file explorer sidebar.
Files are copied (not moved) into the target directory within the worktree.

- Preload detects native file drops via capture-phase listener and resolves
  the drop target (editor, terminal, or file-explorer) from DOM attributes
- New IPC handler `fs:importExternalPaths` copies files/directories with
  symlink pre-scanning, path-traversal protection, and dedup on conflict
- FileExplorer tracks native drag state separately from internal drag state
  to show correct drop highlights without interfering with tree reordering
- FileExplorerRow expands directories on hover during native drags
- useFileExplorerImport hook subscribes to preload IPC events and drives
  the import → refresh → reveal pipeline

Includes review fixes:
- Clear nativeDropTargetDir on row drag-leave to prevent stale highlights
- Clear native drag state on early return in useFileExplorerImport
- Extract row drag logic to useFileExplorerRowDrag hook
- Split import tests into dedicated filesystem-import.test.ts
- Use T[] syntax instead of Array<T> per lint rules
- Use ternary expressions for simple if/else per lint rules
2026-04-13 22:04:49 -07:00