Skip to content

fix(cli): protect dollar signs from PowerShell expansion in computer follow-up commands - #21868

Open
bbingz wants to merge 2 commits into
stablyai:mainfrom
bbingz:fix/21772-computer-followup-powershell-quote
Open

bbingz wants to merge 2 commits into
stablyai:mainfrom
bbingz:fix/21772-computer-followup-powershell-quote

Conversation

@bbingz

@bbingz bbingz commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

When Orca prints an inspect command on Windows, a folder name like $review stays the folder name. The same text is safe to paste into PowerShell or cmd.exe.

What Changed

  • Before: Follow-up commands wrapped every Windows argument in double quotes. PowerShell then expanded $review in a worktree selector such as path:C:/work/$review.
  • After: A selector with a dollar sign is written as path:C:/work/$"r"eview. PowerShell treats that as one argument and does not expand the dollar sign. cmd.exe joins the quoted r back onto the surrounding text, so it sees the same path. Arguments with no dollar sign stay in the old double quotes. macOS and Linux still use single quotes.
  • Mechanism: quoteCliCommandArgument no longer reads ORCA_TERMINAL_WINDOWS_SHELL or ORCA_WINDOWS_SHELL, and ComputerActionFollowUpTarget no longer has a shell field. Nothing in the CLI process set those variables, so the cmd.exe branch never ran and every Windows user got PowerShell single quotes. The pasted command is text for whatever shell the agent is using, so the generator emits one spelling that both PowerShell and cmd.exe accept.

Why

Detecting the shell from ComSpec would still say cmd.exe inside PowerShell. Single quotes protect PowerShell and split cmd.exe. A quote that starts the argument ends there in PowerShell, so "path"$"review" becomes two arguments. Breaking only the first character of the variable name keeps one argument in both shells.

Linked Issue

Fixes #21772

Visual Proof

N/A — CLI command text formatting change.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

Local checks on this revision, from the PR worktree:

  • vitest run --config config/vitest.config.ts src/cli/shell-command-quote.test.ts src/cli/computer-format.test.ts src/cli/format.test.ts — 3 files, 43 passed, 0 failed. The Windows cases mock process.platform.
  • node node_modules/typescript/bin/tsc --noEmit -p config/tsconfig.tc.cli.json (pnpm tc:cli) — passed.
  • oxlint on the changed CLI files — 0 warnings, 0 errors.

PowerShell and cmd.exe are not installed on this machine. The spelling was checked against the PowerShell tokenizer ($"x" stays in one generic argument) and CommandLineToArgvW (quoted text is concatenated). It was not executed in those shells.

AI Disclosure

Antigravity (Google DeepMind) drafted the first patch. This quoting revision was written with Grok.

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Ensure no issues in: Security, Cross-platform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance

An argument that cannot start a PowerShell generic token (a leading space, for example) is one backtick-escaped double-quoted string. cmd.exe then keeps the backtick. A $$( subexpression is stopped the same way. The reported path:C:/work/$review selector does not use that fallback.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Full pnpm lint, pnpm test, and pnpm build were not run locally. pnpm tc:cli and oxlint on the changed files were run. CI covers the rest.

@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

Walkthrough

Windows argument quoting now protects dollar signs while retaining the existing form for values without them. Tests cover shell quoting and verify the formatted computer action output for a worktree selector containing a dollar sign.

Fixed issue severity: <fixed_issue_severity>Medium</fixed_issue_severity>

Priority: ➖ Normal

Merge Risk: 🔵 Low · up to a2fbe

Generated commands have not been verified in both Windows shells, and an uncommon app name can produce the wrong selector in cmd.exe. The remaining risk is bounded but warrants owner awareness.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed For #21772, quoteCliCommandArgument emits path:C:/work/$"r"eview on Windows, so the dollar sign is not followed by the original variable name. The formatter test verifies that this spelling appear…
Out of Scope Changes check ✅ Passed The changes to Windows argument quoting and the formatter and quoting tests directly support #21772. No unrelated changes are present in the reviewed diff.
Title check ✅ Passed The title clearly identifies the Windows PowerShell dollar-sign expansion fix in computer follow-up commands.
Description check ✅ Passed The description covers the required sections, links issue #21772, explains the change and rationale, marks visual proof as not applicable, and reports testing and limitations. The Review section is bl…
  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The cmd quoting branch this PR adds is unreachable in normal operation, so the Windows shell detection does not actually do what the description claims. ORCA_TERMINAL_WINDOWS_SHELL / ORCA_WINDOWS_SHELL are read but assigned nowhere in the repository, so resolveCliShell always resolves to powershell on win32. A user whose terminalWindowsShell is cmd.exe therefore now gets single-quoted arguments that cmd does not treat as delimiters — a regression from the previous double-quoted output.

Reviewed changes

  • PowerShell quoting for CLI follow-up commands. quoteCliCommandArgument now resolves a shell family (powershell/cmd/posix) and quotes accordingly, so $ in selectors is no longer expanded when the suggested command is pasted into PowerShell.
  • Shell detection helper. resolveCliShell reads ORCA_TERMINAL_WINDOWS_SHELL ?? ORCA_WINDOWS_SHELL through resolveWindowsShellStartupFamily, defaulting to powershell when unset.
  • Follow-up command plumbing. ComputerActionFollowUpTarget gains shell?: AgentStartupShell, threaded through formatComputerFollowUpCommand.
  • Tests. shell-command-quote.test.ts covers the new win32 default, explicit shell selection, env-based detection, and embedded-quote doubling; computer-format.test.ts asserts the rendered --worktree argument end to end.

ℹ️ Nitpicks

  • ComputerActionFollowUpTarget.shell is set by no production caller — getComputerCommandTarget returns only { app, worktree | session } and the handlers spread { ...target, ...observeFlags }. It is the natural place to thread the real terminal shell, but as written only the tests exercise it and production depends entirely on the env fallback above.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/cli/shell-command-quote.ts Outdated
if (platform !== 'win32') {
return 'posix'
}
const configured = env.ORCA_TERMINAL_WINDOWS_SHELL ?? env.ORCA_WINDOWS_SHELL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ORCA_TERMINAL_WINDOWS_SHELL and ORCA_WINDOWS_SHELL are read here but assigned nowhere in the repository, so on Windows this always resolves to powershell and the cmd branch below is dead in production. A user whose terminal is cmd.exe then receives single-quoted arguments — cmd does not treat ' as a delimiter, so the selector arrives with literal quotes — a regression from the previous double-quoted output.

Technical details
# Windows shell signal is never populated

## Affected sites
- `src/cli/shell-command-quote.ts:16` — reads `ORCA_TERMINAL_WINDOWS_SHELL ?? ORCA_WINDOWS_SHELL`; neither is ever set.
- `src/cli/orchestration-mutation-recovery.ts:191` — the analogous `resolveRecoveryShell` reads the same vars but also falls back to `ComSpec ?? COMSPEC`, so it reaches `cmd` quoting; this helper deliberately omits that fallback.
- `src/main/daemon/shell-ready.ts:99` — third reader of the same var, also with no writer.
- `src/cli/computer-format.ts:201` — `ComputerActionFollowUpTarget.shell` was added but no caller populates it.

## Required outcome
- The `cmd`/`posix` branches must be reachable when the user's terminal shell is not PowerShell, or the limitation must be stated explicitly instead of implying cmd is handled.

## Suggested approach (optional)
- Populate a shell-family env var in the PTY spawn env (`buildPtyHostEnv`) from the resolved `terminalWindowsShell`/per-tab override, so the CLI child inherits the real shell; or
- Thread the resolved shell into `ComputerActionFollowUpTarget` from `getComputerCommandTarget`/the handlers.

## Open questions for the human (optional)
- Is a `ComSpec` fallback wanted here? Note `ComSpec` is set to `cmd.exe` on every Windows process, including PowerShell sessions, so it would misclassify the PowerShell default.

bbingz added 2 commits October 7, 2026 17:36
The Windows shell env vars were never set, so cmd.exe users got
PowerShell single quotes. Emit one spelling that keeps $ literal
in PowerShell without splitting cmd.exe, and drop the unused shell field.
@bbingz
bbingz force-pushed the fix/21772-computer-followup-powershell-quote branch from ae2c461 to a2fbec5 Compare October 7, 2026 10:34
@bbingz

bbingz commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Pullfrog is right. ORCA_TERMINAL_WINDOWS_SHELL and ORCA_WINDOWS_SHELL are never set in the CLI process, so the cmd.exe branch never ran and the single-quote spelling would have split cmd.exe. ComputerActionFollowUpTarget.shell had no production caller. Both are removed.

Windows follow-up arguments are now one spelling both shells keep as a single argument. path:C:/work/$review is printed as path:C:/work/$"r"eview: PowerShell does not treat $" as a variable name, and cmd.exe concatenates the quoted r. Arguments with no $ stay in the old double quotes. macOS and Linux stay single-quoted.

Worktree checks: vitest on shell-command-quote.test.ts, computer-format.test.ts, and format.test.ts — 3 files, 43 passed, 0 failed. pnpm tc:cli passed. oxlint on the changed files: 0 warnings, 0 errors. PowerShell and cmd.exe are not installed on this machine, so the spelling was not executed in those shells.

Head: a2fbec5f3c998f6201a98c2956e48dfcf43dadce

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/cli/shell-command-quote.ts (1)

14-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a Windows shell round-trip test for the existing quoting vectors.

The tests assert only the strings returned by quoteCliCommandArgument. They do not check the arguments received by PowerShell or cmd.exe. Run the eight existing vectors through both shells and compare the argument-reporter output with the original inputs. This small matrix is proportionate to the helper’s dual-shell behavior.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8883889a-9dc9-4b83-a556-e03e9cbd0b72
📥 Commits

Reviewing files that changed from the base of the PR and between ae2c461 and a2fbec5.

📒 Files selected for processing (3)
  • src/cli/computer-format.test.ts
  • src/cli/shell-command-quote.test.ts
  • src/cli/shell-command-quote.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Computer follow-up commands expand dollar signs in worktree selectors on PowerShell

1 participant