Since #7473 the terminal daemon runs under a standalone node.exe.
Electron's bundled Node defaults windowsHide to true; plain node.exe
defaults it to false, so every child_process call in the daemon that
does not pass the flag - the periodic PowerShell CIM process probes,
node-pty's kill-path conpty_console_list_agent fork - now allocates a
visible console, which opens and closes a Windows Terminal window on
the user's screen every few seconds.
Fix: daemon-entry installs a child_process shim (first import, before
any module captures bindings like promisify(execFile)) that defaults
windowsHide: true across spawn/exec/execFile/fork and their sync
variants, restoring the Electron default the daemon has always relied
on. Explicit windowsHide from a caller still wins. Also adds
windowsHide to node-pty's console-list agent fork in the existing
patch as defense in depth.
Verified on Windows: reproduced the flash with the rc.5 production
daemon (WindowsTerminal windows, ~3s cadence matching the CIM probe
interval, conhost spawned visible-capable "0x4"); with the shim, a
node.exe-hosted daemon's children (OpenConsole, powershell, node
helpers) all run without a visible-capable console and session kill
still works end to end.
* Fix Peek References scrollbar stability
Keep faded Monaco Peek References vertical scrollbars visible while the widget remains open, and include docs/peek-references-scrollbar-stability.md as the design reference.
Also remove the now-unreachable repo override note switch fallback so lint stays green.
* rm unnecessary file
* rm unnecessary file
The node-pty native runtime is relocated to a per-app-version dir under
userData so live terminals survive NSIS updates. On every launch,
removeStaleRuntimeVersions() deleted every *other* version's dir, gated
on a "renameSync succeeds => unused => safe to delete" heuristic.
That heuristic is false on Windows: running .exe images and mapped .dll
files are opened with FILE_SHARE_DELETE, so both the directory rename and
the recursive delete succeed while a daemon adopted across the update is
still using them. Existing PTYs keep streaming via deferred-delete
handles, but the next spawn re-loads conpty.dll from the now-unlinked
version dir and fails with ERROR_PATH_NOT_FOUND (code 3) -- the
"Cannot find conpty.dll ... error code: 3" new-tab failure.
Gate cleanup on real daemon liveness instead: collectInUseRuntimeVersions()
reads the daemon-v<N>.pid files under userData/daemon and, for each live
daemon, protects the appVersion (runtime dir) it recorded. Deletion now
skips the current version and any in-use version, dropping the rename
dance. Every failure mode leaks a dir rather than deleting one in use.
Rewrites the misleading cleanup test (which modeled no live daemon) and
adds coverage for surviving/dead daemons, appVersion:null pin files,
multiple protocol versions, and malformed/non-pid files.
Co-authored-by: Neil <neil@stably.ai>
* Render launch prompts in native chat and refine initial view mode
- Seed and render the agent launch prompt as a synthetic, pending user
message in the native chat view until the transcript catches up.
- Refine initial view mode logic so native chat does not auto-open for
draft prompt delivery, unsupported agents, or when disabled.
- Add delivery failure tracking for the launch prompt, rendering an
error status in the message list if pasting into the terminal fails.
- Implement corresponding store actions, selectors, cleanup routines,
and extensive test coverage.
* Support native-prefill prompt delivery and fix chat message sorting
* Treat native draft pre-fills as successful deliveries instead of
marking the seeded launch prompts as failed.
* Group native chat messages into sorting tiers (real content, streaming
preview, optimistic echoes) so optimistic bubbles don't sort past
the streaming preview due to finite timestamps.
* Avoid auto-opening native chat for draft prompt followups
Followup paths paste the prompt as an unsubmitted draft. When prompt
delivery is configured as 'auto-submit', this previously opened the
native chat view with no actual submitted turn to render.
By gating the initial view mode using 'draft' delivery on followup
paths, we ensure the tab starts in terminal mode instead.
- Widen the resize handle hit target to 12px (straddling the edge) to
make it easier to grab, centering a thin 1px visual guide line.
- Highlight the divider line on hover and active states, and shade
the handle background during active dragging.
- Adjust the sidebar webkit scrollbar border to prevent a transparent
gap from appearing next to the drag handle.
- Update unit tests to match the new styling and sizing classes.
- Clear sent comments from selection queue when confirming AI resolution.
- Keep selection clear requests pending until the matching review context is
mounted, preventing them from being ignored on context changes.
- Fix calculation of skipped threads when comment resolution is launched.
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.
* 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>
* Hide redundant current worktree info in workspace vault scope
When the AI Vault is scoped to the current workspace, showing the
"Current worktree" status line or badge is redundant since the sessions
are already filtered to this workspace.
- Add helper to hide the worktree line and status badge when the vault
is in 'workspace' scope and status is 'current'.
- Improve alignment and metadata layout in session rows using CSS grid.
- Update tests to verify worktree line and badge visibility rules.
* Indent AI vault session worktree line
Add left padding to the session worktree line to improve its visual
indentation inside the AI vault session row.
* Refine Spanish and Chinese locale translations
- Update Spanish strings for developer tools, notifications, and session history scopes.
- Standardize Chinese terminology by converting "令牌" to "token" and correcting color translations (e.g., "橙子" to "橙色").
- Adjust Chinese UI phrasing, such as mapping issue states from "进行中" to "开放" and "资源管���器" to "文件管理器".
* test: update MR Open state filter expectation to 开放
The zh locale intentionally remapped the GitLab MR 'Open' filter from
进行中 to 开放; align the test expectation with the translation.
Co-authored-by: Orca <help@stably.ai>
* Improve Chinese and Spanish translations
- Translate "Current workspace" to Spanish.
- Correct the translation of "Atlassian" and expand "PR" to "拉取请求"
in Chinese locale.
- Fix spacing around English terms like "token" in Chinese text in Chinese.
---------
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): launch prior/default agent when a woken terminal can't resume
Waking a sleeping worktree (or restoring terminals after an app restart)
left an agent terminal as a BLANK shell while still showing the agent's
icon: `buildColdRestoreAgentResumeStartup` returned null whenever the
provider session couldn't be resumed, and the caller then spawned a bare
shell.
Now, when resume isn't possible, an agent terminal comes back as a FRESH
session of the agent it previously ran (live status -> sleeping record ->
persisted tab `launchAgent`); if that agent is unknown but the terminal was
an agent terminal, the configured default agent is used. A genuine plain
shell stays blank, and the existing resume path, SSH/remote, and WSL
behavior are unchanged.
Fixes#4557
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(terminal): assert default-agent cold restore is a fresh (non-resume) launch
Addresses CodeRabbit review on #6277.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix cold restore agent fallback
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Instead of showing a generic commit failure message during the Create PR
intent flow, leverage `summarizeCommitFailure` to extract the underlying
reason (such as pre-commit hook or lint failures) and present it clearly.
Also introduce `commitErrorsRef` to reliably track and retrieve the most
up-to-date commit errors across renders without stale closure issues.
* fix: focus new floating-workspace agent tab on launch
The default-agent button in the floating workspace titlebar created its
tab with { activate: false } and only called setActiveTabForWorktree,
which writes activeTabIdByWorktree. The floating panel selects its
visible tab from the unified group's activeTabId, so the new agent tab
was appended but never selected or focused. Add activateTab(tab.id),
matching the empty-state tab creators, so launching a new agent switches
to and focuses its tab.
* test: use top-level react type import in floating controls test
* test: lock queue-before-activate order and state updates for agent launch
Strengthen the FloatingTerminalWindowControls regression test per review:
- make the createTab mock append the new tab to the worktree (realistic store)
- seed an existing tab so append/order behavior is observable
- assert startup command is queued before activateTab (invocationCallOrder)
- assert setActiveTabForWorktree and tab bar order placement
---------
Co-authored-by: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com>
* Reflow and edit hard-wrapped prose within single paragraph blocks
Instead of splitting consecutive markdown source lines into multiple visual paragraph nodes during document initialization, preserve them as a single paragraph containing literal newlines.
- Use `white-space: normal` CSS to reflow soft breaks naturally.
- Introduce `deleteAdjacentEmptyParagraph` to handle Backspace/Delete without converting soft newlines to hard break elements.
- Update the cut handler to delete only a visual line on Cmd+X within hard-wrapped paragraphs.
- Avoid split-pane/sync phantom dirty states caused by structural block splitting.
* Document why normalizeEmptyListItems is used for paragraph reflow
Add comments to clarify that normalizeEmptyListItems preserves
hard-wrapped paragraphs as single paragraphs, allowing them to
reflow via CSS instead of being split on load or external sync.
* 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>
* Harden rate-limit PTY cwd and abort background usage probes on stop
Resolve a runaway CPU incident where background Claude rate-limit usage
probes could inherit a root working directory (such as `/` or `C:\`) and
index the entire disk.
- Force hidden Claude and Codex usage PTYs to spawn inside a small,
dedicated directory under user data or temp.
- Thread AbortSignal through rate-limit fetchers to immediately kill
and reap in-flight PTY processes when RateLimitService stops.
- Harden daemon and local PTY defaults to reject root-like working
directories for automated agent startups.
* Consolidate PTY path safety checks to prevent runaway CPU
Centralize `isRootLikePath` into a dedicated PTY path safety module
to prevent terminal launches and hidden usage probes from executing
in filesystem or drive roots, avoiding unbounded file discovery.
- Centralize path validation supporting POSIX, Windows, and UNC roots.
- Fail loudly if no safe default working directory is available.
- Enforce bounded directories for hidden usage PTYs and WSL probes.
- Check for aborted signals during rate-limit CLI repairs.
* Gate agent startup on the effective PTY cwd after default fallback
Co-authored-by: Orca <help@stably.ai>
* test(repos): verify origin/HEAD target in SSH base-ref tests
Co-authored-by: Orca <help@stably.ai>
* Pin HOME to assert exact default PTY cwd in spawn test
Pin `process.env.HOME` in the fallback test for LocalPtyProvider to
assert the exact resolved candidate rather than just checking that it is
non-root-like. This catches potential regressions where an unintended
home directory is picked, and uses a try/finally block to safely restore
the environment afterwards.
---------
Co-authored-by: Orca <help@stably.ai>
Older folder-based workspaces are tracked by `activeWorkspaceKey`
rather than the legacy `activeWorktreeId`. Deriving the active sidebar
workspace ID from the workspace key enables the "Reveal active
workspace" action to work correctly for both types of workspaces.
* fix(worktrees): fall back from stale default base refs (#7312)
* docs(worktrees): explain base fallback policy
* fix(worktrees): harden stale base fallback edge cases
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* Warn about and manage repository overrides for AI action recipes
This improves the user experience around overriding global AI action recipe
defaults with repository-specific settings:
- In global settings, display a note if repositories override a recipe,
with a shortcut to review those repository settings.
- In the agent launch dialog, show a warning if the repo overrides the
global default and default the save target to the repo.
- In repository settings, support saving and discarding recipe overrides
on a per-action basis.
* Memoize repo filtering and override summaries in recipe defaults
Avoid re-filtering all repositories and re-computing override summaries
on every keystroke in sibling textareas.
Also use an exhaustive switch check for override field labels, and add
a test verifying the overflow note indicator when overrides exceed the
visible limit.
buildWorktreePurgeState is the bulk worktree-removal reducer reached by the
authoritative-scan reconcile (CLI `git worktree remove`, another Orca window,
SSH), remove-project, and the hydration stale-purge. Unlike the single in-app
removeWorktree path — which runs shutdownWorktreeTerminals /
dropAgentStatusByWorktree / clearPaneForegroundAgentByWorktree — it never ran
terminal teardown, so it left every pane-scoped map untouched:
agentStatusByPaneKey, agentLaunchConfigByPaneKey, acknowledgedAgentsByPaneKey,
paneForegroundAgentByPaneKey, sleepingAgentSessionsByPaneKey,
unreadTerminalPanes, unreadAgentCompletionPanes, lastTerminalInputAtByPaneKey
(all keyed by `${tabId}:${leafId}`) and unreadTerminalTabs (keyed by tabId).
Result: one orphaned entry per agent pane of every externally-removed worktree,
retained for the whole renderer session (monotonic growth), plus a phantom +1
on the unread dock badge. This is a direct parallel to leaks the maintainers
already fixed in this same function (browserAnnotationsByPageId, editorCursorLine
— each carrying a 'the bulk reconcile path missed them' comment).
Fix: evict these maps by tab-id / `${tabId}:` prefix in the reducer, matching
the in-app teardown. retainedAgentsByPaneKey and runtimeAgentOrchestrationByPaneKey
are intentionally left out — both self-heal (pruneRetainedAgents on a
worktreesByRepo change; the runtime map is replaced wholesale each sync).
Leak-regression test drives purgeWorktreeTerminalState and asserts every map is
emptied for the removed worktree while a sibling worktree's state is preserved.
Reverting the fix fails both cases.
Co-authored-by: Orca <help@stably.ai>
* 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>
Translate various remaining English strings in Spanish, Japanese, Korean,
and Chinese locale files to provide better localized terminology for
common UI actions, settings descriptions, and toast messages.
* Use official OpenCode SVG icon instead of remote favicon
Replaces the remote favicon loading for OpenCode with a local SVG icon.
This avoids flaky external network requests and ensures the icon renders
properly across light and dark themes using theme-aware currentColor.
* Update OpenCodeIcon SVG geometry to use official 512 canvas
Update the OpenCode icon geometry and viewBox to use the official
512x512 canvas sourced from the opencode.ai favicon. Using a square
viewBox matches sibling glyphs.
- Resolve true work item identity (issue vs. PR) using the URL path to
override stale or incorrect cached payload types.
- Prevent invalid PR start point resolution when launching an issue
misclassified as a PR.
- Validate and reject mismatched URL types in the worktree metadata
dialog fields to avoid incorrect associations.
* Fix missing space in import-cookies "From <browser>" menu labels
The Import Cookies dropdown rendered browser entries as "FromGoogle Chrome"
and "FromSafari" — JSX collapses whitespace between the adjacent
{translate(…, 'From')}{browser.label} expressions.
Switch both settings menus to the 'From {{value0}}' interpolation pattern
already used by the other import-cookies menus, so the label is a single
translatable unit and renders with the correct space. Interpolation also lets
each locale position the browser name correctly: ja/ko use postpositions
("から"/"에서") that belong after the name, which the old concatenation placed
before it. Localized the new key in es/ja/ko/zh to match the existing catalog
style. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix browser use import source label
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Keep PetOverlay runtime keyframes out of localization so translated locales cannot invalidate sprite or bob animations.\n\nAlso adds regression coverage for translated-locale keyframe CSS and removes the stale generated locale entries.
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.
* feat(ghostty): import adjust-cell-height and dual-value window paddings
Two Ghostty config forms previously landed in unsupportedKeys:
- adjust-cell-height percentages (e.g. "35%") now map to
terminalLineHeight (1.35), the direct xterm equivalent. Pixel values
are still rejected because they depend on the rendered cell height.
- window-padding-x/y "top,bottom" / "left,right" pairs now import as
the rounded average, preserving the total padding along the axis.
parseStrictInt moves to numeric-config-values.ts alongside the new
pair parser to keep mapper.ts under the max-lines budget.
* fix(ghostty): tighten import edge cases
Co-authored-by: Orca <help@stably.ai>
* fix(settings): sentence-case account runtime copy
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* feat(ghostty): resolve theme references during config import
`theme = <name>` is how most Ghostty configs pick their colors, but the
importer treated the key as unsupported and silently dropped the entire
palette. Resolve the referenced theme file and merge its colors as
defaults, mirroring Ghostty's own precedence:
- Search user themes first (XDG, then the native macOS dir), then the
bundled themes inside the Ghostty install, and parse the file with the
existing parseGhosttyConfig (theme files are plain config subsets).
- Explicit config keys win over theme values; config palette entries are
appended after the theme's so per-index overrides apply naturally.
- Only color-bearing keys may flow from a theme into the import, a theme
file cannot smuggle font/window settings past the user's config.
- Theme names containing path separators are rejected (no traversal),
files over 256 KB are ignored, and light:/dark: pairs plus unresolvable
names surface as annotated unsupportedKeys instead of vanishing.
* fix(ghostty): align theme resolution with Ghostty lookup
Co-authored-by: Orca <help@stably.ai>
* test: stabilize ghostty import CI coverage
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* chore(i18n): refine Spanish locale copy
Why:
Improve the Spanish UI copy so developer-facing terms stay natural and technically accurate.
Changes:
- Keep core dev terms such as PR, worktree, branch, and runtime consistent.
- Preserve locale key parity and placeholder compatibility with English.
* chore(i18n): localize new Spanish strings
* chore(i18n): use rama for branch in Spanish
* chore(i18n): clarify Spanish repository copy
* fix(i18n): correct Spanish locale defects found in review
Post-review polish on the Spanish copy pass:
- Restore dropped/altered meaning: 'repo color' (was 'en el repositorio'),
'uploaded' (was 'sincronizado'), 'is behind {ref}' (was '{ref} atrás',
which rendered the ref name as a quantity).
- Translate leftover English over prior correct strings: 'Review from'->
'Revisión de', 'Agents'->'Agentes', 'workspace'->'espacio de trabajo',
'clone'->'clon', 'Skill de Agent'->'Skill de agente'.
- Grammar/register: 'para commit'->'para hacer commit' (x3), 'desde issue'->
'desde el issue' (x4), 'Cuando tanto...y'->'Cuando ambos...', unify tú in
the sidebar-tint description, 'obligatorio'->'obligatorias' (agrees with
approvals), 'desbloquear'->'descongelar' for 'unfreeze', de-Spanglish the
local-folder-drop message.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Bare repo-backed terminal creates now reuse Settings agent defaults for exact agent commands while preserving raw commands, disabled agents, and already-managed launches.
Validation:
- PR Checks / verify passed
- Local runtime tests, typecheck, lint, CLI build, and Electron CLI/runtime smoke passed