Skip to content

fix(setup): quote repo path in --spawn terminal commands (fixes #1035)#1037

Closed
kagura-agent wants to merge 1 commit intocoleam00:devfrom
kagura-agent:fix/setup-spawn-spaces
Closed

fix(setup): quote repo path in --spawn terminal commands (fixes #1035)#1037
kagura-agent wants to merge 1 commit intocoleam00:devfrom
kagura-agent:fix/setup-spawn-spaces

Conversation

@kagura-agent
Copy link
Copy Markdown
Contributor

@kagura-agent kagura-agent commented Apr 10, 2026

Problem

archon setup --spawn fails on Windows when the repo path contains spaces (e.g. C:\Users\...\GitHub Libraries\Archon). Both the Windows Terminal (wt.exe) and cmd.exe fallback paths pass the path unquoted, causing it to be split at the first space.

The user sees a Windows error dialog: "Libraries\Archon\packages\cli" could not be found.

Fix

Wrap repoPath in double-quotes before passing to wt.exe and cmd.exe:

  1. wt.exe path: Add explicit "..." quoting and switch to shell: true for consistent shell-level quoting
  2. cmd.exe path: Quote the /D argument so start receives the full path

Both paths now handle spaces, special characters, and parentheses in directory names.

Changes

  • packages/cli/src/commands/setup.ts: Quote repoPath in spawnWindowsTerminal()
  • packages/cli/src/commands/setup.test.ts: Add test for paths with spaces

Validation

  • bun test packages/cli/src/commands/setup.test.ts — 19 pass, 0 fail
  • bun run type-check — clean across all packages
  • bun run lint — clean

Note

The Linux terminal spawning functions have a similar potential issue with unquoted paths (--working-directory= concatenation), but that is out of scope for this PR.

Closes #1035

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where the CLI setup command would fail when repository paths contained spaces on Windows.
  • Tests

    • Added test coverage for handling filesystem paths containing spaces during terminal initialization.

…m00#1035)

On Windows, spawnWindowsTerminal passes the repo path unquoted to
wt.exe and cmd.exe. When the path contains spaces (e.g.
'C:\Users\...\GitHub Libraries\Archon'), the shell splits it at the
first space, causing a 'could not be found' error dialog.

Fix: wrap repoPath in double-quotes for both the wt.exe and cmd.exe
spawn paths. Also switch wt.exe to shell: true for consistent quoting
behavior across both paths.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

Updated Windows terminal spawning to correctly handle repository paths containing spaces by explicitly quoting the path before passing it to wt.exe and cmd.exe invocations. Added a corresponding test case to verify the function returns a structured result object when given spaced paths.

Changes

Cohort / File(s) Summary
Windows Terminal Path Quoting
packages/cli/src/commands/setup.ts
Modified spawnWindowsTerminal to construct a double-quoted version of repoPath and use it in both wt.exe (with added shell: true option) and cmd.exe start command invocations, ensuring shell argument parsing respects space-delimited paths.
Path Handling Test
packages/cli/src/commands/setup.test.ts
Added test case validating that spawnTerminalWithSetup returns a result object with a boolean success property when provided with a filesystem path containing spaces, confirming the function does not crash on such input.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A path with spaces caused dismay,
Windows terminals went astray,
Quotes around the route we place,
Now setup runs in every space! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(setup): quote repo path in --spawn terminal commands (fixes #1035)' directly and clearly describes the main change: quoting the repo path in Windows terminal spawning to fix paths with spaces.
Description check ✅ Passed The description covers the problem, fix, and validation with clear explanations of what changed and why. It follows the key points of the template (problem statement, scope, changes, validation evidence).
Linked Issues check ✅ Passed The code changes fully address the root causes identified in issue #1035: paths are now properly quoted for both wt.exe and cmd.exe fallback paths, handling spaces and special characters as required.
Out of Scope Changes check ✅ Passed All changes are scoped to packages/cli/src/commands/setup.ts and setup.test.ts, directly addressing the Windows terminal path quoting issue. No unrelated changes or scope creep detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/cli/src/commands/setup.test.ts (1)

365-374: This test is not actually validating quoting and is environment-dependent.

Line 369 spawns real terminal logic, and the assertions only verify { success: boolean }. This can pass even if quoting breaks, and may behave differently across developer/CI environments. Consider making this deterministic by asserting constructed Windows spawn arguments (without launching real terminals).

Based on learnings: Applies to **/*.ts : Prefer reproducible commands and locked dependency behavior in CI-sensitive paths; keep tests deterministic — no flaky timing or network dependence without guardrails; ensure local validation commands (bun run validate) map directly to CI expectations

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/commands/setup.test.ts` around lines 365 - 374, The test
spawnTerminalWithSetup currently invokes real terminal-spawn logic making it
environment-dependent and not asserting quoted Windows args; modify the test to
avoid launching real terminals by mocking/stubbing the platform/terminal
detection and the internal spawn construction path inside
spawnTerminalWithSetup, then call the function or the helper that builds the
command array and assert that for a path like join(tmpdir(), 'path with spaces',
'Archon') the returned/constructed Windows command/arguments include proper
quoting (e.g., wrapped in quotes) and that the function returns the expected
object shape; specifically locate and stub the spawnTerminalWithSetup code paths
that detect Windows vs POSIX and the internal command-builder, verify the
produced command string/args for Windows quoting deterministically, and remove
any real-process spawning from the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cli/src/commands/setup.ts`:
- Around line 1232-1239: The wt.exe launch currently uses shell: true to
preserve quoting (as added for `#1035`) which causes trySpawn to report success
even if wt.exe inside the shell fails; keep shell: true but change the logic in
trySpawn (and the call site that spawns 'wt.exe') to detect inner-process
failures by attaching to the returned ChildProcess: remove or adjust stdio:
'ignore' so you can listen for 'exit'/'error' and inspect the exit code and
stderr, and on non-zero exit or error fall back to spawning cmd.exe; update the
spawn handling around trySpawn('wt.exe', ...) and the ChildProcess listeners to
only treat the spawn as successful when the child exits with code 0 (or no
error) so the cmd.exe fallback runs when wt.exe fails.

---

Nitpick comments:
In `@packages/cli/src/commands/setup.test.ts`:
- Around line 365-374: The test spawnTerminalWithSetup currently invokes real
terminal-spawn logic making it environment-dependent and not asserting quoted
Windows args; modify the test to avoid launching real terminals by
mocking/stubbing the platform/terminal detection and the internal spawn
construction path inside spawnTerminalWithSetup, then call the function or the
helper that builds the command array and assert that for a path like
join(tmpdir(), 'path with spaces', 'Archon') the returned/constructed Windows
command/arguments include proper quoting (e.g., wrapped in quotes) and that the
function returns the expected object shape; specifically locate and stub the
spawnTerminalWithSetup code paths that detect Windows vs POSIX and the internal
command-builder, verify the produced command string/args for Windows quoting
deterministically, and remove any real-process spawning from the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 95a5198d-ea37-4d90-98e7-2d762bc8b729

📥 Commits

Reviewing files that changed from the base of the PR and between 95679fa and 8d91dde.

📒 Files selected for processing (2)
  • packages/cli/src/commands/setup.test.ts
  • packages/cli/src/commands/setup.ts

Comment on lines +1232 to 1239
// wt.exe parses its own command line, so we need shell: true
// with explicit quoting rather than relying on Node's auto-quoting.
if (
trySpawn('wt.exe', ['-d', repoPath, 'cmd', '/k', 'archon setup'], {
trySpawn('wt.exe', ['-d', quoted, 'cmd', '/k', 'archon setup'], {
detached: true,
stdio: 'ignore',
shell: true,
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Node.js child_process.spawn on Windows, when { shell: true } is used, can spawn(...) return a child PID even if the target executable (e.g., wt.exe) fails to launch, with failure only visible via quick shell exit?

💡 Result:

Yes.

With { shell: true } on Windows, spawn() first launches a shell (by default process.env.ComSpec, typically cmd.exe, using /d /s /c) and the ChildProcess you get back represents that shell process. So child.pid can be a valid PID as long as the shell itself started successfully—even if the command inside the shell (e.g., wt.exe) fails to launch, in which case the only sign may be that the shell prints an error to stderr and exits quickly with a non‑zero exit code. [1][2]

In other words, that PID can be “real” but correspond to the shell wrapper, not the target executable; this wrapper-vs-real-command PID distinction is a known/observed behavior when using shell:true. [3]

What to check instead: listen for error (shell failed to spawn) vs close/exit + exit code and stderr (command failed inside the shell). [2]

Sources: [1] (nodejs.org) [2] (nodejs.org) [3] (stackoverflow.com)

Citations:


🏁 Script executed:

# Find the trySpawn function definition
rg -n "function trySpawn|const trySpawn|export.*trySpawn" packages/cli/src/commands/setup.ts

Repository: coleam00/Archon

Length of output: 82


🏁 Script executed:

# Get full context around lines 1232-1239
sed -n '1220,1250p' packages/cli/src/commands/setup.ts

Repository: coleam00/Archon

Length of output: 1137


🏁 Script executed:

# Find the trySpawn implementation
rg -B5 -A15 "function trySpawn|const trySpawn\s*=" packages/cli/src/commands/setup.ts

Repository: coleam00/Archon

Length of output: 581


🏁 Script executed:

# Search for any comments or issues mentioning wt.exe and shell: true
rg -B2 -A2 "wt\.exe" packages/cli/src/commands/setup.ts | head -40

Repository: coleam00/Archon

Length of output: 598


🏁 Script executed:

# Check git history if available for context on this code
git log --oneline -n 20 -- packages/cli/src/commands/setup.ts 2>/dev/null | head -20

Repository: coleam00/Archon

Length of output: 137


🏁 Script executed:

# Look for any tests of spawnWindowsTerminal
fd -t f "setup" packages/cli/src/ --exec grep -l "spawnWindowsTerminal\|trySpawn" {} \;

Repository: coleam00/Archon

Length of output: 93


🏁 Script executed:

# Check the actual git commit to understand the fix for `#1035`
git show 8d91dde 2>/dev/null | head -80

Repository: coleam00/Archon

Length of output: 2579


🏁 Script executed:

# Search for issue `#1035` context in comments or docs
rg "#1035" packages/

Repository: coleam00/Archon

Length of output: 159


Removing shell: true will likely break path quoting for #1035; instead, detect wt.exe failure by listening to exit codes.

The issue is real: with shell: true, child.pid represents the shell process, not wt.exe. If wt.exe fails inside the shell, trySpawn() returns true anyway and the cmd.exe fallback never runs.

However, the suggested fix (removing shell: true) would revert the quoting behavior intentionally added in commit 8d91dde (issue #1035) to handle paths with spaces. The shell: true was added specifically so the shell parses the quoted path before passing it to wt.exe.

Instead, keep shell: true but detect when the command inside the shell fails. Add event listeners to ChildProcess for exit code checking, or remove stdio: 'ignore' temporarily to capture stderr when wt.exe fails. This preserves the quoting fix while properly detecting launch failure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/commands/setup.ts` around lines 1232 - 1239, The wt.exe
launch currently uses shell: true to preserve quoting (as added for `#1035`) which
causes trySpawn to report success even if wt.exe inside the shell fails; keep
shell: true but change the logic in trySpawn (and the call site that spawns
'wt.exe') to detect inner-process failures by attaching to the returned
ChildProcess: remove or adjust stdio: 'ignore' so you can listen for
'exit'/'error' and inspect the exit code and stderr, and on non-zero exit or
error fall back to spawning cmd.exe; update the spawn handling around
trySpawn('wt.exe', ...) and the ChildProcess listeners to only treat the spawn
as successful when the child exits with code 0 (or no error) so the cmd.exe
fallback runs when wt.exe fails.

skundu42 pushed a commit to skundu42/Archon that referenced this pull request Apr 10, 2026
… tool_results (coleam00#1037)

* fix(sse): extend buffer TTL beyond reconnect grace to prevent dropped tool_results

The SSE event buffer held events for only 3s, but the conversation
reconnect grace period is 5s — meaning events emitted during a
reconnect window could expire *before* the client even had a chance
to reconnect. When a tool_result happened to land in that gap, the
UI would show a perpetually spinning tool card with no recovery path.

This is one of the remaining causes from the 'tool cards stuck
running' investigation. The two biggest causes (Claude hook coverage
and Codex tool_result emission) were already fixed in coleam00#1031 and coleam00#1032.
This closes the last high-impact backend gap.

Changes:
- EVENT_BUFFER_TTL_MS: 3_000 → 60_000. Covers typical EventSource
  auto-reconnect delays on flaky networks (mobile, VPN, laptop sleep).
- EVENT_BUFFER_MAX: 50 → 500. Events are small JSON strings; 500
  bounds worst-case memory while giving real headroom for bursts.
- Warn when buffer cap evicts oldest (previously silent).
- Warn when events expire on TTL at replay time (previously silent).
  Both warnings give us observability if the new bounds are still
  ever insufficient.

Note: a full Last-Event-ID resume protocol would be more principled
but requires monotonic event IDs and client-side offset tracking —
a larger change with its own risks. The TTL bump alone closes the
vast majority of the window at near-zero cost.

* fix(sse): throttle eviction warns, reset cleanup timer, enforce TTL invariant

Address review feedback on the SSE buffer TTL bump:

- Reset the buffer cleanup timer on each new event so the buffer is held
  for TTL past the most recent event, not the first one. With the 20x TTL
  bump this gap became meaningful — a fresh event could be wiped by a
  cleanup timer scheduled when the first (now-stale) event was buffered.

- Throttle 'transport.buffer_evicted_oldest' warns to one per conversation
  per 5s. A runaway producer overflowing the cap by hundreds would
  otherwise flood logs.

- Fail-fast at module load if EVENT_BUFFER_TTL_MS < RECONNECT_GRACE_MS.
  Locks in the invariant the comment already documents.

- Add test covering the eviction-warn throttle.
Tyone88 pushed a commit to Tyone88/Archon that referenced this pull request Apr 16, 2026
… tool_results (coleam00#1037)

* fix(sse): extend buffer TTL beyond reconnect grace to prevent dropped tool_results

The SSE event buffer held events for only 3s, but the conversation
reconnect grace period is 5s — meaning events emitted during a
reconnect window could expire *before* the client even had a chance
to reconnect. When a tool_result happened to land in that gap, the
UI would show a perpetually spinning tool card with no recovery path.

This is one of the remaining causes from the 'tool cards stuck
running' investigation. The two biggest causes (Claude hook coverage
and Codex tool_result emission) were already fixed in coleam00#1031 and coleam00#1032.
This closes the last high-impact backend gap.

Changes:
- EVENT_BUFFER_TTL_MS: 3_000 → 60_000. Covers typical EventSource
  auto-reconnect delays on flaky networks (mobile, VPN, laptop sleep).
- EVENT_BUFFER_MAX: 50 → 500. Events are small JSON strings; 500
  bounds worst-case memory while giving real headroom for bursts.
- Warn when buffer cap evicts oldest (previously silent).
- Warn when events expire on TTL at replay time (previously silent).
  Both warnings give us observability if the new bounds are still
  ever insufficient.

Note: a full Last-Event-ID resume protocol would be more principled
but requires monotonic event IDs and client-side offset tracking —
a larger change with its own risks. The TTL bump alone closes the
vast majority of the window at near-zero cost.

* fix(sse): throttle eviction warns, reset cleanup timer, enforce TTL invariant

Address review feedback on the SSE buffer TTL bump:

- Reset the buffer cleanup timer on each new event so the buffer is held
  for TTL past the most recent event, not the first one. With the 20x TTL
  bump this gap became meaningful — a fresh event could be wiped by a
  cleanup timer scheduled when the first (now-stale) event was buffered.

- Throttle 'transport.buffer_evicted_oldest' warns to one per conversation
  per 5s. A runaway producer overflowing the cap by hundreds would
  otherwise flood logs.

- Fail-fast at module load if EVENT_BUFFER_TTL_MS < RECONNECT_GRACE_MS.
  Locks in the invariant the comment already documents.

- Add test covering the eviction-warn throttle.
@kagura-agent
Copy link
Copy Markdown
Contributor Author

Closing — this has been open for a week without maintainer review. Happy to reopen or resubmit if there's interest. Thanks! 🌸

joaobmonteiro pushed a commit to joaobmonteiro/Archon that referenced this pull request Apr 26, 2026
… tool_results (coleam00#1037)

* fix(sse): extend buffer TTL beyond reconnect grace to prevent dropped tool_results

The SSE event buffer held events for only 3s, but the conversation
reconnect grace period is 5s — meaning events emitted during a
reconnect window could expire *before* the client even had a chance
to reconnect. When a tool_result happened to land in that gap, the
UI would show a perpetually spinning tool card with no recovery path.

This is one of the remaining causes from the 'tool cards stuck
running' investigation. The two biggest causes (Claude hook coverage
and Codex tool_result emission) were already fixed in coleam00#1031 and coleam00#1032.
This closes the last high-impact backend gap.

Changes:
- EVENT_BUFFER_TTL_MS: 3_000 → 60_000. Covers typical EventSource
  auto-reconnect delays on flaky networks (mobile, VPN, laptop sleep).
- EVENT_BUFFER_MAX: 50 → 500. Events are small JSON strings; 500
  bounds worst-case memory while giving real headroom for bursts.
- Warn when buffer cap evicts oldest (previously silent).
- Warn when events expire on TTL at replay time (previously silent).
  Both warnings give us observability if the new bounds are still
  ever insufficient.

Note: a full Last-Event-ID resume protocol would be more principled
but requires monotonic event IDs and client-side offset tracking —
a larger change with its own risks. The TTL bump alone closes the
vast majority of the window at near-zero cost.

* fix(sse): throttle eviction warns, reset cleanup timer, enforce TTL invariant

Address review feedback on the SSE buffer TTL bump:

- Reset the buffer cleanup timer on each new event so the buffer is held
  for TTL past the most recent event, not the first one. With the 20x TTL
  bump this gap became meaningful — a fresh event could be wiped by a
  cleanup timer scheduled when the first (now-stale) event was buffered.

- Throttle 'transport.buffer_evicted_oldest' warns to one per conversation
  per 5s. A runaway producer overflowing the cap by hundreds would
  otherwise flood logs.

- Fail-fast at module load if EVENT_BUFFER_TTL_MS < RECONNECT_GRACE_MS.
  Locks in the invariant the comment already documents.

- Add test covering the eviction-warn throttle.
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.

archon setup --spawn fails on Windows when repo path contains spaces

1 participant