Auto-generated workspace names walked the marine-creature list in order
and deduped only within the active repo (the default when workspaces are
nested), so the first auto-named worktree in every repo landed on
"Nautilus". That guaranteed identical branch names across repos, which
appear flat and indistinguishable in the sidebar.
The in-order walk also produced "Nautilus-2", "Nautilus-3", ... within a
single repo: the suggester ignores branches left behind by deleted
worktrees, so it kept re-proposing "Nautilus", and the create-time retry
loop suffixed it to dodge the lingering branch. Random selection now
yields a fresh creature each time instead of marching the same name.
- Dedup against worktrees in every repo, not just the active one
- Pick randomly from the unused pool instead of the first list entry
- Lowercase the result to match branch-name convention (fix/seahorse)
- Expand the corpus 260 -> 552 (more marine species plus public-domain
mythological sea creatures) so random picks rarely repeat
getSuggestedCreatureName drops the now-unused repoId/nestWorkspaces
params; the RNG is injectable for deterministic tests.
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Add agent enablement controls
Implements the Enable/Disable Agents Dashboard behavior described in docs/enable-disable-agents-dashboard.md, including persisted agent enablement state, filtered launch surfaces, and settings UI affordances.
* Clarify agent availability controls
* Respect disabled agents across workspace and AI defaults
- Filter disabled TUI agents from mobile and quick workspace selection
- Avoid implicitly choosing disabled agents for commit/PR AI settings
- Broadcast settings changes to open windows for disabled-agent updates
* rm design doc
* fix: complete agent enablement propagation
* fix: stop worktree jumping to top of sidebar on re-click
Returning to a worktree whose terminals had slept or disconnected
bounced it to the top of its repo group, as if there were activity.
The sidebar sorts by lastActivityAt, and click-driven activity is meant
to be suppressed via the pendingActivationSpawn tag. But setActiveWorktree
only applied that tag on a worktree's first activation. When the user
returned to a worktree with no live PTYs, the allDead branch bumped the
PTY generation, remounting the pane and fresh-spawning a PTY. That spawn
was untagged, so updateTabPtyId treated it as real activity: it stamped
lastActivityAt and bumped sortEpoch, floating the worktree to the top.
Tag the tabs whenever the allDead generation bump fires, not only on
first activation -- the respawn it triggers is always a click side-effect.
The flag is consumed on the next updateTabPtyId, so genuine later activity
still updates recency. This matches the intent already documented in the
terminals slice.
* fix activation spawn recency suppression
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* fix: prevent relay fs.rename from clobbering an existing destination
The remote file-explorer rename path (provider.rename -> relay
fs.rename) called fs.rename unconditionally, silently overwriting any
file/folder already at the destination. The local rename already
guards via assertFileExplorerRenameDestinationAvailable; apply the
same guard on the relay to restore local/remote parity (case-only
renames on case-insensitive filesystems still allowed).
Moved the collision helper from src/main to src/shared so both the
main process and the remotely-deployed relay share one implementation.
Closes#2926
* review: make SSH safe rename explicit
- keep relay fs.rename raw and add fs.renameNoClobber for user-facing renames
- route SSH file-explorer rename paths through renameNoClobber
- add relay/provider/runtime regression coverage and stale-relay fail-closed handling
- verified live SSH rename behavior on openclaw 2
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Multiline quick commands should behave like a shell command list, not a series of already-queued PTY lines. When a foreground command reads stdin, raw newline delivery can be consumed before the shell sees later cd/pwd lines; terminal paste avoids that but shows the whole block as pasted input before execution.
Flatten newline-separated quick commands into a semicolon-delimited command list before active-pane dispatch and new-tab startup queuing. The shell parses the list once, so later commands run after earlier foreground commands exit and directory changes remain in the active shell.
Fixes#2844
Co-authored-by: Prethish-Complyance <prethish@complyance.io>
Co-authored-by: Orca <help@stably.ai>
* Add per-file line counts to the source control sidebar
Show +N/-N (green/red) next to each file in the Changes, Untracked, and
Committed-on-branch sections so the magnitude of a change is visible at a
glance. Counts are computed per staging area via `git diff --numstat`;
untracked/new files count their full contents as additions and binary
files show no count.
Consolidate numstat parsing and binary-buffer detection into shared
modules reused by the local status path, the SSH/relay path, and the
existing branch-compare code. Include added/removed in the status-entry
equality check so the sidebar doesn't re-render on unchanged polls.
* fix: harden source control line counts
---------
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Fix shortcut dispatch so app commands follow the produced logical key for the active keyboard layout, while preserving intentional physical-code fallbacks for terminal byte paths and unavailable logical keys.\n\nCloses #2858
Adds Command Code hook installation, status normalization, launch seeding, and terminal-output fallback detection for working/done sidebar status. Includes review hardening for long-running tool repaint cadence and prompt sanitization across split ANSI chunks.
* fix(shell-ready): honor ZDOTDIR without breaking zsh scoping
Fixes#1866
This reimplements PR #1737 (reverted in #1864) with a safer approach
that preserves normal zsh startup semantics.
**Core fix**: Discover ZDOTDIR by sourcing user ~/.zshenv in a subshell
instead of inside a wrapper function. This preserves top-level zsh
scoping for common patterns like `typeset -U path` that broke in the
original implementation.
**Shell safety improvements**:
- Use `printf '%s\n'` instead of `echo` for capturing ZDOTDIR (handles
special characters in paths safely)
- Subshell isolates early returns and side effects from wrapper
**Code quality**:
- Extract duplicated zsh wrapper template to `src/main/shell-templates.ts`
- Both local-pty and daemon paths now share identical wrapper logic
**Test coverage**:
- Add live zsh subprocess tests that spawn real zsh to verify:
- XDG ZDOTDIR discovery works
- `typeset -U path` in .zshrc preserves top-level scoping
- Early returns in .zshenv don't crash the wrapper
- Vanilla (non-XDG) configs fall back to HOME correctly
- Template structure tests validate subshell discovery logic
Before (broken):
```zsh
__orca_source_user_zshenv() {
source "$HOME/.zshenv" # typeset becomes function-scoped
}
```
After (fixed):
```zsh
_orca_discovered_zdotdir=$(
unset ZDOTDIR
[[ -f "$HOME/.zshenv" ]] && source "$HOME/.zshenv" 2>/dev/null
printf '%s\n' "${ZDOTDIR}"
)
export ORCA_ORIG_ZDOTDIR="${_orca_discovered_zdotdir:-${_orca_spawn_orig_zdotdir:-$HOME}}"
```
The subshell sources .zshenv at top-level (preserving normal scoping),
captures only the ZDOTDIR value, then exits. User rcfiles (.zshrc, etc.)
are still sourced at the wrapper's top level, so all scoping works normally.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add shell-script-literal test framework and improvements
Adds a new declarative test framework for shell-ready tests that uses
literal shell scripts (copy-pastable into terminals) with inline snapshots.
Framework features:
- Shell scripts as string literals with # Run: marker to split setup/test
- Direct script execution (no brittle parsing) via temp files
- Path normalization for reproducible snapshots (<HOME>, <WRAPPER_DIR>)
- Auto-detects shell from command, supports bash/zsh/sh
- Inline snapshot testing with vitest toMatchInlineSnapshot()
Code quality improvements:
- Extract escapeRegex to shared string-utils.ts (deduplicates 2 copies)
- Refactor shell-templates.ts for readability (condense comments, add structure)
- Pre-compile regex patterns to avoid hot-path allocation
- Fix path normalization to sort by length (prevent nested path corruption)
- Fix actualUserHome handling to skip empty values
All tests passing (64/64 shell-ready tests, 55/55 affected tests).
Files added:
- src/main/providers/__tests__/shell-ready-framework/shell-script-test.ts
- src/main/providers/__tests__/shell-ready-framework/README.md
- src/main/providers/__tests__/shell-ready-framework-example.test.ts
- src/shared/string-utils.ts
Files modified:
- src/main/shell-templates.ts (readability cleanup)
- src/main/codex/config-toml-trust.ts (use shared escapeRegex)
- src/main/daemon/shell-ready.test.ts (updated for new framework)
- src/main/providers/local-pty-shell-ready.test.ts (updated for new framework)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(shell-ready): preserve zshenv semantics
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* Add Command Code as a supported CLI agent
Register Command Code (https://commandcode.ai) across the agent
catalog, launch config, telemetry kind, agent-status icon record, and
settings search. Detection uses the full `command-code` binary rather
than the shorter `cmd` alias that `npm i -g command-code` also
installs — agent-process-recognition normalizes process names by
stripping `.exe`/`.cmd` extensions, so using `cmd` would collide with
Windows' built-in `cmd.exe` shell.
Closes#2083
* Complete Command Code agent registration
---------
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Adds OMP as a first-class TUI agent and keeps Pi/OMP overlay state isolated across local and relay PTY paths.\n\nValidated locally with focused Vitest coverage, typecheck, lint, git diff --check, and Electron manual verification using installed omp (omp/15.3.2).