* implement h1 and text toggle
* Review:
- Details parsing is now depth-aware, so nested <details> blocks are not partially consumed.
- Existing details blocks with raw HTML inside the summary/body now fall back to Orca’s raw HTML passthrough instead of
becoming editable toggle nodes and escaping tags.
- Simple supported details blocks still become editable rich toggle nodes.
- Added regression tests for raw HTML inside details and nested details.
* placeholder and fix enter behaviour
* review findings
* Review: align toggle commands with grouped slash menu
Co-authored-by: Orca <help@stably.ai>
* Review: finish toggle command rebase fixes
Co-authored-by: Orca <help@stably.ai>
* Review: preserve unsupported details HTML
Co-authored-by: Orca <help@stably.ai>
* Review: delete toggle body back into summary
Co-authored-by: Orca <help@stably.ai>
* Review: make empty toggle backspace two-step
Co-authored-by: Orca <help@stably.ai>
* Review: make empty toggle enter exit
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Improve node-pty spawn diagnostics
* Preserve original error stack when adding node-pty recovery hint
Mutate the existing Error's message instead of replacing the object so
the original stack trace and custom fields survive into telemetry/logs.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
Run pnpm update in root + mobile to pull patched versions of vite, hono,
@hono/node-server, dompurify, uuid, picomatch, lodash, brace-expansion,
path-to-regexp, postcss, @xmldom/xmldom, and other transitive packages
flagged by Dependabot.
Co-authored-by: Orca <help@stably.ai>
* 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>
* chore: update .gitignore to include stackdump and .serena, enhance pre-commit script
* fix(win32): resolve EPERM on userData writes and batch-file spawn failures
Three Windows-specific issues prevented Orca from running correctly on
machines where Chromium resets the userData DACL during startup:
1. **EPERM on userData writes** — Chromium's BrowserWindow constructor calls
SetNamedSecurityInfo on the userData folder with a Protected DACL. When
propagated to child directories the ACEs carry the Inherit-Only flag,
meaning they apply to children-of-children but NOT to the directories
themselves. Any file write inside codex-runtime-home, agent-hooks, or
similar subdirectories fails with EPERM.
Fix: grant an explicit Full Control ACE (OI)(CI)(F) on userData and all
existing children before BrowserWindow is created (icacls /T /C).
Explicit ACEs survive future DACL propagation from the parent. Per-write
EPERM retries in fs-utils and installer-utils serve as the backstop for
directories created after startup.
2. **Batch-file spawn failures** — resolveCodexCommand() can return a .cmd
or .bat path (e.g. codex.cmd installed via npm). Node's spawn() cannot
execute batch scripts directly without shell:true, but shell:true with an
args array triggers DEP0190 because args are concatenated rather than
escaped. Both service.ts and codex-fetcher.ts were affected.
Fix: detect .cmd/.bat paths and route through cmd.exe /c explicitly,
which is equivalent to what shell:true does internally but avoids the
deprecation warning and arg-escaping hazard.
3. **Native dep rebuild failure** — electron-builder install-app-deps does
not expose the ignoreModules option. On Windows dev machines without the
full VC++ / Python toolchain, cpu-features (an optional dep of ssh2) fails
to build with node-gyp, aborting the entire postinstall step.
Fix: replace electron-builder install-app-deps with a thin wrapper script
(scripts/rebuild-native-deps.mjs) that calls @electron/rebuild's JS API
directly with ignoreModules: ['cpu-features'] on Windows. ssh2 detects
the missing native module and falls back to pure-JS automatically.
Refactoring: extract shared win32-utils.ts with getIcaclsExePath(),
getCmdExePath(), isWindowsBatchScript(), isPermissionError(), grantDirAcl(),
and getSpawnArgsForWindows() to eliminate five instances of duplicated
SystemRoot path construction and two near-identical EPERM retry blocks.
Reduce startup icacls calls from three sequential blocking /T invocations
to one, removing up to 20 s of potential startup delay.
* fix(win32): address review feedback on ACL and spawn helpers
- Fall back to SID via `whoami /user` when `USERNAME` is unset so
`grantDirAcl` works under services, CI, and hardened envs instead of
silently no-op'ing.
- Use a 60s timeout for recursive `icacls /T` walks; the 10s cap could
starve on large userData trees and silently fail the startup grant.
- Pass `windowsHide: true` to `icacls` and the cmd.exe-routed Codex
spawns so no console window flashes in the packaged GUI app.
- Add `/d` to `cmd.exe /c` invocations to disable AutoRun registry
commands — safer default for background spawns.
- Drop unused `createRequire`/`require` from rebuild-native-deps.mjs.
- Add `@electron/rebuild` as an explicit devDependency; relying on the
electron-builder transitive was brittle under pnpm.
- Fix two misleading "Re-enable inheritance" comments that describe
behavior opposite to what the code actually does (explicit ACL grant).
- Add unit tests for `isWindowsBatchScript`, `getSpawnArgsForWindows`,
and `isPermissionError` to lock in Windows batch detection + cmd.exe
routing.
Co-authored-by: Orca <help@stably.ai>
* fix(win32): unify PTY spawn through /d and document cmd.exe safety
- fetchViaPty now uses getCmdExePath() and /d /c, matching the rest of
the codebase instead of hand-rolling 'cmd.exe' + ['/c', ...].
- getSpawnArgsForWindows gains a SAFETY note: when the .cmd/.bat branch
is taken, cmd.exe re-parses the combined command line, so callers
must only pass trusted/literal args.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Anchor-only links (#heading) now scroll to the matching heading in both
the markdown preview and rich editor. Preview uses rehype-slug to stamp
heading ids; the rich editor walks headings with the same stateful
GithubSlugger for parity (including duplicate-heading suffixes).
* wip in the design doc
* fix: use Ctrl+Shift+J for worktree palette on non-darwin platforms
To avoid colliding with Ctrl+J (Line Feed) on Windows/Linux, we now
use Ctrl+Shift+J for the worktree jump palette on those platforms,
leaving Cmd+J for macOS.
* refactor: migrate QuickOpen to cmdk and unify overlay state
- Migrated `QuickOpen.tsx` to use `cmdk` (`CommandDialog`) for visual and
behavioral consistency with the new worktree jump palette, while keeping
the existing custom fuzzy match algorithm.
- Unified the overlay state systems (`activeModal`, `quickOpenVisible`,
`worktreePaletteVisible`) into a single `activeModal` union type.
- This automatically handles mutual exclusion without boilerplate
toggle logic spread across components.
* fix: forward QuickOpen and worktree shortcuts from browser guests
Added main-process interceptors for `Cmd/Ctrl+P` and `Cmd/Ctrl+1-9`
so that QuickOpen and numeric worktree jumping continue to work
even when an embedded browser guest (webview) has keyboard focus.
* fix: address review findings
- Set spawnEnv.SHELL before pty.spawn() in the fallback loop so the
child process inherits the correct SHELL value instead of the stale
original.
- Remove dead Cmd+P and Cmd+1-9 renderer keydown handlers from App.tsx;
these are now handled via IPC from createMainWindow.ts before-input-event
(the IPC handlers in useIpcEvents.ts have the same view-state guards).