Commit Graph
132 Commits
Author SHA1 Message Date
NeilandOrca 0e8571b58d Tabbed Create Workspace dialog (Quick / Create from…) (#1191)
Co-authored-by: Orca <help@stably.ai>
2026-04-27 22:48:04 -07:00
Brennan BensonandOrca 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
Brennan BensonandOrca 76139f88a9 fix: support upstream remote as base ref for fork workflows (#1186)
Co-authored-by: Orca <help@stably.ai>
2026-04-27 13:51:19 -07:00
Jinwoo HongandOrca 75c6f25887 feat(linear): add create-issue button for feature parity with GitHub (#1185)
Co-authored-by: Orca <help@stably.ai>
2026-04-27 12:28:09 -07:00
JinjingandOrca 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
NeilandNeil Parker 98ba693481 feat(terminal): WSL shell support for Windows users (#1154)
Co-authored-by: Neil Parker <nwparker@anthropic.com>
2026-04-26 22:43:54 -07:00
NeilandOrca 193c6ecab3 fix(linear): defer keychain decrypt, cache viewer, add Test connection (#1151)
Co-authored-by: Orca <help@stably.ai>
2026-04-26 21:45:38 -07:00
Brennan Benson 8b87acd72d feat(memory): add Memory & CPU status-bar popover (#1146) 2026-04-26 21:42:06 -07:00
Jinwoo HongandOrca f11aacc795 feat(ssh): add port forwarding for remote workspaces (#1145)
Co-authored-by: Orca <help@stably.ai>
2026-04-26 19:21:26 -07:00
f5ad7aa249 feat(settings): import Ghostty config with preview, color overrides, opacity and blur (#1001)
* feat(settings): add Ghostty config import

Add safe one-shot Ghostty import with preview and success summary,
and probe documented Ghostty config paths before applying changes.

Refs #958

* chore(git): ignore atl artifacts

* feat(settings): map font-weight, cursor-blink and focus-follows-mouse from Ghostty

Adds three safe direct-mapping Ghostty keys that have clear equivalents
in GlobalSettings: font-weight, cursor-style-blink, and focus-follows-mouse.

Refs #958

* feat(settings): expand Ghostty import to support colors, opacity and option-as-alt

- Add TerminalColorOverrides type grouping 21 optional xterm ITheme fields
- Add terminalBackgroundOpacity, terminalPanePaddingColor, terminalPaddingBalance
  to GlobalSettings
- Extend parser to collect repeated keys as string[] (needed for palette lines)
- Map background-opacity, background, foreground, cursor-color,
  selection-background/foreground, palette (0-15), window-padding-color,
  window-padding-balance, macos-option-as-alt in mapper
- Merge terminalColorOverrides into xterm ITheme at theme resolution; apply
  opacity as rgba() with allowTransparency enabled
- Accept hex colors with or without leading # (Ghostty omits it)
- Fix preview diff to use deep equality for object values so already-applied
  color overrides no longer reappear on next import

* feat(settings): support background-blur-radius and window-padding-color extend in Ghostty import

- Map background-blur-radius > 0 to windowBackgroundBlur: true; apply
  vibrancy on macOS and backgroundMaterial acrylic on Windows at window
  creation (blur requires restart — no hot-reload IPC exists)
- Accept window-padding-color = extend/background as valid Ghostty values;
  both map to default Orca padding behavior (undefined field) instead of
  landing in unsupportedKeys
- Split mapper.test.ts into domain-scoped describes to stay under 300-line limit

* feat(settings): add Window section to Terminal settings panel

Expose terminalBackgroundOpacity, windowBackgroundBlur, terminalPaddingBalance,
terminalPanePaddingColor, and terminalColorOverrides in the settings UI so
imported Ghostty values can be viewed and changed manually.

- New TerminalWindowSection component (extracted from TerminalPane to stay
  under the 400-line limit)
- Collapsible color overrides sub-section with ColorField for all 21 xterm
  ITheme fields grouped as base, ANSI normal, and ANSI bright
- Reset button clears all color overrides at once
- Window blur toggle shows restart-required note (blur applies at window
  creation, no hot-reload IPC exists)
- Search entries added for all new controls

* feat(settings): expand Ghostty import with scrollback, padding, divider, cursor and word-chars keys

Map 9 additional Ghostty keys to Orca settings:

- split-divider-color → terminalDividerColorDark + terminalDividerColorLight
  (single value applies to both; Ghostty has no dark/light distinction)
- unfocused-split-opacity → terminalInactivePaneOpacity (direct float 0-1)
- scrollback-limit → terminalScrollbackLimit; applied to xterm scrollback option
- window-padding-x / window-padding-y → terminalPaddingX/Y; applied as CSS
  vars --pane-padding-x / --pane-padding-y in terminal.css
- cursor-text → terminalColorOverrides.cursorAccent (xterm ITheme field)
- bold-color → terminalColorOverrides.bold (persisted; xterm ITheme has no
  bold field yet — stored for future xterm upgrade)
- cursor-opacity → terminalCursorOpacity; blended into cursor rgba at theme
  resolution time
- selection-word-chars → terminalWordSeparator; applied to xterm wordSeparator
- mouse-hide-while-typing → terminalMouseHideWhileTyping field added; renderer
  application deferred (needs per-pane disposable + global mousemove listener)

* feat(settings): expose new Ghostty-imported settings in Terminal Settings UI

- Window section: scrollback limit, horizontal/vertical padding, hide mouse
  while typing toggle, cursor text and bold color in Color Overrides
- Cursor section: cursor opacity NumberField
- Advanced section: word separators text input
- Search entries added for all new controls
- terminalDividerColorDark/Light and terminalInactivePaneOpacity skipped —
  already present in Theme and Pane Styling sections respectively

* feat(terminal): implement mouse-hide-while-typing per pane

Register terminal.onData → cursor:none and mousemove → restore, scoped to
the pane container element. Uses the existing IDisposable per-pane pattern
(same as selectionDisposablesRef). Cleans up on pane close and effect teardown.

* refactor(settings): address ghostty import code review findings

- Centralize GhosttyImportPreview type in shared/types (remove duplicate from mapper)
- Fix parser to strip inline comments without breaking hex color values (#1a1a1a)
- Extract HEX_COLOR_RE to shared/color-validation to avoid duplication
- Remove redundant Number.isNaN checks after Number.isFinite (4 sites)
- Replace unsafe catch-all assignment with explicit font-family branch
- Migrate 280-line if-chain in mapGhosttyToOrca to FIELD_PARSERS registry
- Add human-readable setting labels in GhosttyImportModal via setting-labels map
- Add clarifying comment in index.ts re JSON.stringify undefined behavior

* fix(settings): harden ghostty import from judgment-day review

- Surface readFile errors in GhosttyImportPreview.error instead of
  showing misleading 'No config found' on permission denied
- Guard handleApply against double-apply when already applied
- Strip surrounding quotes from parsed config values (font-family)
- Return null from palette handler when all entries fail validation
- Inform user when background-blur-radius radius is not preserved
- Add valuesEqual key-order stability via stableStringify
- Normalize hex colors to #-prefixed format across all color mappers
- Reject blank values before numeric parsing (Number('') === 0 trap)
- Remove selection-word-chars mapping (inverted xterm semantics)
- Guard window-padding-x/y against negative integers
- Reactive mouse-hide-while-typing on existing panes when setting toggles
- Merge terminalColorOverrides on import instead of replacing

* fix(ghostty): drop broken imports, tighten parsing, prompt restart for blur

Review found three high-impact issues in the Ghostty import: scrollback-limit
semantics are inverted/rescaled (Ghostty is bytes with 0=unlimited, xterm is
rows with 0=disabled), and window-padding-color + window-padding-balance set
CSS custom properties (--pane-padding-color, --pane-padding-balance) that
have no consuming rule anywhere in the tree — so users confirming "changes"
to those keys would see nothing happen.

Because none of the three keys have a safe mapping today, drop them from the
import and remove the dead UI controls + GlobalSettings fields + CSS var
plumbing. The mapper now lists them as unsupportedKeys alongside the
existing window-decoration / keybind / custom-shader entries.

Other fixes in the same review:

- allowTransparency now clears when background-opacity returns to 1 (prior
  code only ever set it to true, leaving a stale flag with measurable render
  cost).
- background-blur-radius = 0 no longer emits a misleading "radius value not
  preserved" note (0 cleanly maps to blur=false with no radius to lose).
- Add a 1 MB size cap on the config read so a pathological or symlinked file
  cannot OOM the main process.
- Make handleApply async and surface IPC errors inline in the modal instead
  of flipping straight to "Import complete" on failure.
- Type settings.previewGhosttyImport as Promise<GhosttyImportPreview> in
  preload so shape drift is caught at compile time.
- Make stableStringify recursive so future nested settings round-trip
  cleanly through valuesEqual.
- Restrict window-padding-x/y and background-blur-radius to decimal ints;
  prior code accepted exponent notation (1e10 sails through Number.isInteger)
  and would have landed absurd values in the store.
- Window blur now shows a "Restart required" banner with a Restart now
  button when the setting differs from the mount-time snapshot, mirroring
  the ExperimentalPane daemon pattern. Blur only applies at BrowserWindow
  creation on macOS/Windows.

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

* feat(settings): move Ghostty import trigger to Terminal section header

Per review feedback: the "Import from Ghostty" row was taking its own slot
in the Terminal settings list alongside real configuration sections. Move
the trigger into the Terminal section's header (upper-right corner) as a
headerAction, next to the Terminal heading — it's a one-shot action, not a
setting.

- SettingsSection gains an optional `headerAction` slot rendered to the
  right of the section title/description.
- The useGhosttyImport hook is lifted from TerminalPane into Settings.tsx
  so the section header button (owned by Settings.tsx) and the modal
  (still rendered inside TerminalPane) share one state instance.
- TerminalPane drops its own "Import" section + the TERMINAL_GHOSTTY_IMPORT
  search entry group is no longer referenced there.
- Button carries the official Ghostty mark as a 16x16 icon so it reads
  clearly as a cross-app import even before users parse the label.

useGhosttyImport now accepts `GlobalSettings | null` so the parent can call
it above the pre-load spinner guard without violating hook ordering; the
apply path no-ops until settings arrive. Related test file updated to
pass the new `ghostty` prop and to assert the trigger is *not* rendered
inside TerminalPane anymore.

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-04-26 17:00:46 -07:00
Jinwoo HongandOrca 7720ed136c feat(tasks): server-side scope filtering, pagination, and draft bug fix (#1135)
Co-authored-by: Orca <help@stably.ai>
2026-04-26 12:30:22 -07:00
NeilandOrca ae9ddeab5c feat(cursor): first-class Cursor CLI agent status via hooks.json (#1108)
* feat(cursor): first-class Cursor CLI agent status via ~/.cursor/hooks.json

Give cursor-agent the same hook-driven status pipeline Claude/Codex/Gemini/
OpenCode already use so working/done/permission transitions show the proper
sidebar spinner instead of falling back to title heuristics — cursor-agent
only sets its OSC title to the literal string "Cursor Agent" during a turn,
so title-based detection cannot see working→done transitions on its own.

- New CursorHookService installs a managed shell script and registers it
  under ~/.cursor/hooks.json for beforeSubmitPrompt, preToolUse, postToolUse,
  postToolUseFailure, beforeShellExecution, beforeMCPExecution, stop, and
  afterAgentResponse (the subset that marks turn boundaries and surfaces
  in-flight tool context).
- AgentHookServer gains a /hook/cursor route and a normalizeCursorEvent
  mapping the camelCase cursor events to working/done/waiting, with tool
  previews for preToolUse/shell/MCP and lastAssistantMessage from
  afterAgentResponse. stop with status != "completed" surfaces as
  interrupted (matches Claude's is_interrupt behavior).
- cursorHookService joins the startup install loop alongside Claude/Codex/
  Gemini, and the IPC status handler is exposed via preload.
- 'cursor' added to WellKnownAgentType and to the renderer's
  WELL_KNOWN_LABELS so the dashboard prints "Cursor" rather than the raw
  'cursor' id.

Verified end-to-end against a real cursor-agent 2026.04.17-787b533 binary:
a mock hook receiver pointed at by ~/.cursor/hooks.json observes
beforeSubmitPrompt → stop for a live turn.

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

* feat(cursor): wire hook events into sidebar spinner + unread pipeline

The initial hook wiring landed behind AGENT_DASHBOARD_ENABLED, which is
still false. That meant cursor-agent panes lit up no spinner and no
unread indicator — cursor's native OSC title stays literally "Cursor
Agent" across a turn, so title-based detection cannot transition.

Plumb cursor's hook stream into the existing, shipped title-tracker
pipeline (the one Claude/Codex/Pi drive working/idle/unread off) by
synthesizing OSC title sequences in the main-process hook listener:

  - `working`  → `\x1b]0;⠋ Cursor Agent\x07`   (braille prefix → working)
  - `waiting`  → `\x1b]0;Cursor - action required\x07\x07`
  - `done`     → `\x1b]0;Cursor ready\x07\x07`

The two trailing BELs on done/waiting are load-bearing: the unread badge
keys off BEL (0x07 outside any OSC), and cursor-agent emits none on its
own. The first BEL is consumed as the OSC terminator; the second fires
the bell detector.

Also treats the bare native "Cursor Agent" title as a no-op in
`detectAgentStatusFromTitle` so cursor's own per-turn re-emissions cannot
stomp our synthesized working state back to idle. `isClaudeAgent`
excludes cursor-bearing braille titles so the Claude prompt-cache timer
doesn't fire for cursor panes.

Scope: the hook server + cursor install run unconditionally now, but
Claude/Codex/Gemini installs stay gated behind AGENT_DASHBOARD_ENABLED,
so only cursor events flow through the pipeline. No dashboard surface
is turned on.

Verified end-to-end in Electron (dev build): launched cursor-agent via
the Cursor menu item, submitted three prompts (including a tool-use
turn reading package.json). Observed tab title flip to "Cursor ready"
on done, and the tab + worktree both transitioned to unread
(unreadTerminalTabs[tabId]=true, worktree.isUnread=true). Parallel
Claude Code pane untouched.

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

* fix(cursor): animate spinner frames + filter bare native title so the spinner doesn't go solid mid-turn

cursor-agent re-emits its bare "Cursor Agent" OSC title on every internal
redraw, which was stomping the single synthesized "⠋ Cursor Agent" frame
in runtimePaneTitlesByTabId within milliseconds and flipping the sidebar
dot back to solid. Two-part fix:

- Main: drive an 80ms Pi-style braille spinner from the cursor hook
  channel, keyed by paneKey, torn down on pty exit via a new
  registerPaneKeyTeardownListener hook in ipc/pty.
- Renderer: drop bare "Cursor Agent" titles in pty-transport so cursor's
  native re-emissions cannot overwrite the synthesized working/idle
  titles.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-04-25 23:14:31 -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
555ab95d5a feat(shortcuts): add Ctrl+PageDown/Up to cycle terminal tabs only (#1094)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-04-25 18:45:21 -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 cc47cad95f feat(tasks): add Linear team selector (#1074) 2026-04-24 21:03:30 -07:00
Brennan Benson 6675138d80 feat(agent-hooks): shared types, renderer store, local hook server + Claude/Codex/Gemini/OpenCode wiring (gated) (#1019) 2026-04-24 15:13:58 -07:00
Jinwoo Hong fdb7ed6678 fix(linear): stop keychain prompt from appearing during app launch (#1058) 2026-04-24 15:01:44 -07:00
Jinwoo Hong 5315e87a81 feat: add Claude account switcher (#1050) 2026-04-24 14:05:26 -07:00
Jinwoo Hong 717f319a89 feat(ssh): detect remote-host CLI agents in quick-launch menu (#1027) 2026-04-24 13:21:34 -07:00
Jinwoo Hong faed904aae feat(issues): make issues page writable with inline editing (#1017) 2026-04-24 10:41:21 -07:00
Jinjing 8b0d8ea376 fix(fs): address symlink/delete/remote safety issues from review (#1012)
- Symlink delete/rename now preserve the link entry (new `preserveSymlink`
  option on resolveAuthorizedPath) instead of operating on the target.
- File-explorer delete force-saves dirty editors before trashing so undo
  restores the user's latest edits, not stale disk content.
- Thread `recursive` through preload → SSH provider so remote directory
  delete works end-to-end.
- Remote deletes now confirm (permanent `rm`, no Trash) and the toast
  reflects that no Trash/Recycle Bin is involved.
- Codex managed-home check canonicalizes the storage root before the
  prefix compare so macOS `/private/var` paths stop being rejected.
2026-04-23 16:58:17 -07:00
Jinwoo Hong e1270486cd feat: add Linear integration (#1007) 2026-04-23 14:54:32 -07:00
4f7b488d22 feat(cli): add terminal create, split, rename, focus, close, tui-idle wait (#734)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-04-22 17:51:32 -07:00
Brennan Benson 89b85b828b feat(nav): workspace back/forward navigation (#945) 2026-04-22 13:40:38 -07:00
Jinjing 0bbf2d7a8f feat: cross-repo issues view in new workspace page (#942)
* feat: cross-repo issues view with multi-repo selection

- Add multi-repo selection via RepoMultiCombobox with persisted defaultRepoSelection setting (null = sticky-all)
- Stamp repoId on GitHubWorkItem at the renderer fetch boundary; merge items from all selected repos with per-repo failure tracking
- Extract task-query helpers (tokenize/strip/parseTaskQuery) to src/shared and add unit tests
- Refactor NewWorkspacePage row to <div role=button> to allow nested interactive elements without invalid-HTML hydration errors
- fix(repo-combobox): toggle all-repos selection on repeat click

* fix(tasks): route Use CTA to item's own repo in cross-repo view

handleUseWorkItem previously referenced a removed 'repoId' state; use item.repoId so launching from a merged cross-repo list targets the correct repo.

* test(e2e): add tasks page smoke test
2026-04-22 10:58:18 -07:00
Neil ed32ca2c21 fix(worktrees): fail loudly when no default base ref is resolvable (#922) 2026-04-21 17:40:27 -07:00
Jinjing 89954334a3 fix: route Cmd/Ctrl+N through main-process shortcut allowlist (#895)
Ensures the new-workspace composer opens even when focus is inside a
contentEditable surface (markdown rich editor) or a browser-guest
webContents, both of which bypass the renderer's window-level keydown.
2026-04-21 10:32:31 -07:00
Neil d66d86645d feat(settings): Cmd+Shift affordances for RC channel and hidden experimental (#887)
Cmd+Shift-click "Check for Updates" (menu or Settings > General) opts
into the RC release channel by switching the feed to the github provider
with allowPrerelease=true for the rest of the process.

Cmd+Shift-click the Experimental sidebar entry reveals a "Hidden
experimental" group with an orange-tinted header and a disabled
placeholder toggle — the slot for future unfinished/staff-only options.

Also reword the Experimental description to something less alarmist:
"New features that are still taking shape. Give them a try."
2026-04-21 00:07:02 -07:00
Brennan Benson 933d59f165 diff-comments: copy-only flow in Source Control (#884) 2026-04-20 21:50:31 -07:00
Jinwoo Hong 7a9bc4ef6d feat: computer use via agent-browser CDP bridge (#856) 2026-04-20 20:56:14 -07:00
Jinjing 3a58a829f9 feat(editor): export active markdown to PDF (#882)
Adds File > Export as PDF... menu item (Cmd+Shift+E) and an overflow
menu entry that renders the active markdown preview through a sandboxed
Electron BrowserWindow and writes it to disk via printToPDF.

- New main-side IPC handler (src/main/ipc/export.ts) and html-to-pdf
  helper that loads a CSP-locked HTML document in a sandboxed, context-
  isolated window with javascript enabled only for image-ready polling.
- Renderer helpers clone the rendered markdown subtree, inline all
  computed styles through a curated allowlist, and ship the resulting
  HTML fragment over IPC.
- Ref-counted listener registration so split-pane layouts install
  exactly one IPC subscription and survive panel churn.
2026-04-20 19:41:12 -07:00
Jinjing 781bc9fd62 fix(quick-open): exclude sibling worktree files from Cmd+P results (#867)
When the active worktree is the repo root, linked worktrees are nested
subdirectories. rg --files listed files from every worktree instead of
just the active one. Pass sibling worktree paths as --glob exclusions.

Also wrap scroll-to-top in rAF so it runs after cmdk's scroll-into-view.
2026-04-20 12:27:08 -07:00
Neil 9d56108e89 fix(agents): detect all user-installed CLIs by hydrating PATH from login shell (#843)
* fix(agents): detect opencode/pi CLIs installed under ~/.opencode/bin and ~/.vite-plus/bin

Packaged Electron inherits a minimal PATH without shell rc files, so
agent install-script fallback dirs stay invisible to `which` probes —
the Agents settings page then shows OpenCode/Pi as "Not installed"
even when the user can run them from Terminal.

Add ~/bin, ~/.opencode/bin, and ~/.vite-plus/bin to the packaged PATH
augmentation so preflight detection matches shell behavior.

Fixes #829

* feat(agents): hydrate PATH from user's login shell + Agents Refresh button

Packaged Electron inherits a minimal launchd PATH that misses whatever
the user's shell rc files append — ~/.opencode/bin, ~/.cargo/bin, nvm
shims, pyenv, custom tool dirs. The preceding commit hardcoded two known
install locations; this replaces that whack-a-mole pattern with a
generic approach.

On packaged startup (non-Windows), spawn `${SHELL} -ilc 'echo $PATH'`
with a 5s timeout, parse the delimited PATH, and prepend any new
segments to process.env.PATH. The result is cached for the app session
so we pay the shell-init cost at most once.

Surface a Refresh button in Settings > Agents that forces a re-probe
and re-detects installed agents — handy right after installing a new
CLI, no restart needed.

Live-verified that a `zsh -ilc` spawn with a minimal launchd-style env
still resolves the user's full PATH (32+ segments including the
rc-appended dirs).

* refactor(hydrate-shell-path): simplify dedup with Set + Set.difference

Set preserves insertion order, so PATH first-match-wins semantics are
preserved without manual tracking. Set.prototype.difference (Node 22+)
expresses the new-segments calculation in mergePathSegments as the
set-difference operation it always was.
2026-04-19 14:36:30 -07:00
Jinjing 818a355098 feat(tasks): add New GitHub issue dialog to tasks page (#841)
Adds a + button on the tasks page that opens a dialog to create a new
GitHub issue in the selected repository. Wires createIssue through the
main/preload IPC using gh api, and refreshes the tasks list after
creation so the new issue shows up immediately.

Also clears a stray Radix pointer-events lock on GitHubItemDrawer mount
so Close/open-in-GitHub buttons remain clickable after the New Issue
dialog closes.
2026-04-19 12:52:24 -07:00
Brennan Benson 222d70e063 feat: add idempotent E2E test suite with headless Electron support (#671) 2026-04-19 12:09:32 -07:00
Jinjing 2688c0fee3 feat(editor): preserve Cmd+B for bold in markdown editor (#802)
* feat(editor): preserve Cmd+B for bold in markdown editor

Carve out bare Cmd/Ctrl+B from the main-process before-input-event
interceptor when the TipTap markdown editor is focused, so its bold
keymap can run instead of toggling the left sidebar. Focus state is
mirrored from renderer to main via a one-way IPC send, with default-deny
resets on crash/navigate/destroy and sender validation so only the main
window's webContents can mutate the flag.

* fix: add oxlint max-lines disable to createMainWindow.ts
2026-04-18 10:08:25 -07:00
Neil 3a67eb0f9c support orca 2026-04-18 00:10:27 -07:00
Neil 481bbeb985 fix(feedback): proxy submission through main process to bypass CORS (#791)
The packaged Mac build loads the renderer from file://, which makes a
cross-origin POST via renderer fetch() fail CORS preflight — causing
"Failed to submit feedback" in production while dev (http://localhost)
works. Route submission through a new feedback:submit IPC handler that
uses Electron's net.fetch in the main process (no CORS), mirroring the
pattern already used by updater-changelog/updater-nudge.
2026-04-17 22:47:44 -07:00
Neil 8d3494fe07 feat(composer): support drag-and-drop files and folders onto the composer (#787)
Files dropped onto the new-workspace composer (modal or full page) are
appended as attachment chips; folders are inserted inline at the textarea
caret with shell-style quoting so users can reference working directories
from the OS file browser without leaving the prompt.
2026-04-17 19:14:51 -07:00
Neil aa75adedf7 feat(settings): gate persistent terminal daemon behind experimental toggle (#774) 2026-04-17 16:00:16 -07:00
Jinwoo Hong fd4f986c59 feat: terminal persistence via out-of-process daemon (#729) 2026-04-17 01:42:41 -04:00
Neil 7df0d9686c feat: GitHub PR/issue drawer on new-workspace page (#744) 2026-04-16 21:14:24 -07:00
Jinwoo Hong 961f507ed3 feat: improve cookie import robustness and cross-platform support (#736) 2026-04-16 20:44:10 -07:00
Neil d2a53c8fcc New workspace create page (#710)
* New workspace page with agent catalog, composer modal, and terminal integration

* fix lint

* better blank state

* fix: resolve typecheck errors in new-workspace flow

- widen activateAndRevealWorktree's issueCommand to accept direct
  command shape used by NewWorkspacePage, not just the main-process
  runner-script variant
- use a ref object in pty-connection tests to dodge TS narrowing the
  captured callback to never across the mock closure boundary

* fix: bound worktree name auto-suffix loop to prevent OOM in tests

The auto-suffix loop in createLocalWorktree had no termination cap.
When tests (or a misconfigured env) mocked getBranchConflictKind /
getPRForBranch to always return a collision, the loop ran forever and
the vitest worker crashed with "Ineffective mark-compacts near heap
limit".

Cap the search at 100 suffixes, and if all fail, fall back to the
original specific error messages (branch already exists / PR already
owns the name) instead of a generic failure.

Update the two tests that asserted the old throw-on-first-conflict
behavior to verify the new auto-suffix path end-to-end.
2026-04-16 15:41:40 -07:00
Jinjing 3466e552d0 fix: return error objects from IPC repo handlers instead of throwing (#691)
* fix: return error objects from IPC repo handlers instead of throwing

Electron IPC does not preserve Error objects across the process boundary,
so throwing from main-process handlers can result in opaque failures on
the renderer side. Switch repos:add and repos:addRemote to return
{ repo: Repo } | { error: string } discriminated unions, and update all
call sites to check for the error variant.

* fix: address review findings

- Add explicit return type to repos:add handler for type safety
- Log errors in NonGitFolderDialog catch block (direct IPC call
  bypasses store toast handling)

* fix: show toast on remote folder add failure

The NonGitFolderDialog calls addRemote directly (bypassing the store),
so errors were silently swallowed. Show a toast so the user sees feedback.
2026-04-15 20:33:26 -07:00
Jinwoo Hong ae11e7fefb fix: position browser context menu at cursor with edge flipping (#682) 2026-04-15 16:55:27 -07:00
Jinwoo Hong 3632436ca6 feat: add Cmd+F find-in-page to browser pane (#668) 2026-04-15 00:47:05 -07:00
Jinwoo Hong 42e04268fb fix: harden SSH connection reliability and add passphrase prompt (#636) 2026-04-14 18:29:50 -07:00
Jinwoo Hong 170610d1b2 fix: resolve Windows freeze when switching worktrees with right sidebar open (#628) 2026-04-14 00:45:04 -07:00