Skip to content

fix(watch): Windows shell:true, shared agent-spawn, round-level fetch - #927

Merged
tamirdresher merged 5 commits into
github:insiderfrom
tamirdresher:fix/watch-windows-shared-fetch
Apr 12, 2026
Merged

tamirdresher merged 5 commits into
github:insiderfrom
tamirdresher:fix/watch-windows-shared-fetch

Conversation

@tamirdresher

Copy link
Copy Markdown
Collaborator

Summary

Three fixes for the watch --execute subsystem, addressing Windows compatibility, API rate limiting, and code duplication.

Closes #920, #923


What changed and why

Fix 1: Windows shell: true for all execFile calls (#920)

Problem: On Windows, Node.js execFile() cannot resolve bare command names through PATH or execute .cmd/.bat files without shell: true. Every capability that spawns gh, copilot, git, or other commands fails with spawn EINVAL.

Fix: Added shell: process.platform === 'win32' to all 37+ execFile callsites across:

  • capabilities/board.ts (7 calls)
  • capabilities/self-pull.ts (9 calls)
  • capabilities/execute.ts
  • capabilities/fleet-dispatch.ts
  • capabilities/wave-dispatch.ts
  • capabilities/two-pass.ts
  • core/gh-cli.ts (6 calls)
  • watch/health.ts
  • watch/index.ts

A shared IS_WINDOWS constant (process.platform === 'win32') is exported from the new agent-spawn.ts module.

Fix 2: Shared agent spawn module (DRY)

Problem: buildAgentCommand() was copy-pasted 7 times across capabilities (execute, fleet-dispatch, wave-dispatch, decision-hygiene, monitor-teams, monitor-email, retro). Each copy had slight variations and none included the Windows shell fix.

Fix: Created watch/agent-spawn.ts with:

  • buildAgentCommand(prompt, context) — builds cmd + args from agentCmd config or defaults to standalone copilot CLI
  • spawnWithTimeout(cmd, args, cwd, timeoutMs) — execFile with timeout + Windows shell support
  • spawnAgent(cmd, args, cwd, timeoutMs) — same but resolves with {success, error} instead of rejecting
  • IS_WINDOWS constant

All 7 capabilities now import from this single module. ~150 lines of duplication removed.

Default change: The default agent command changed from gh copilot (deprecated) to standalone copilot CLI. The agentCmd config option overrides this.

Fix 3: Shared round-level issue fetch (#923)

Problem: Each capability independently called gh issue list and gh pr list, resulting in 6+ GitHub API calls per capability per round. With 7 capabilities enabled, that is 40+ API calls per round per repo. Running 4 repos simultaneously hits GitHub's 5000/hr rate limit within minutes.

Fix: Added RoundData interface to types.ts:

interface RoundData {
  issues: WatchWorkItem[];
  pullRequests: PullRequest[];
  fetchedAt: number;
}

The main round runner in index.ts fetches issues and PRs once per round and passes them via context.roundData. Capabilities that need issue/PR data read from the shared context instead of making their own API calls. This reduces API calls from ~40 to ~2 per round per repo.


Files changed (16 files, +245 -222)

File Change
watch/agent-spawn.ts NEW — shared spawn utilities
watch/types.ts Added RoundData interface
watch/index.ts Fetch once per round, populate roundData
watch/health.ts shell: IS_WINDOWS
capabilities/board.ts shell: IS_WINDOWS on 7 execFile calls
capabilities/self-pull.ts shell: IS_WINDOWS on 9 execFile calls
capabilities/execute.ts Uses shared spawnAgent() + roundData
capabilities/fleet-dispatch.ts Removed .cmd hack, shared spawn + roundData
capabilities/wave-dispatch.ts Uses shared spawnAgent() + roundData
capabilities/two-pass.ts shell: IS_WINDOWS + roundData
capabilities/decision-hygiene.ts Removed local copies, imports from agent-spawn
capabilities/monitor-teams.ts Removed local copies, imports from agent-spawn
capabilities/monitor-email.ts Removed local copies, imports from agent-spawn
capabilities/retro.ts Removed local copies, imports from agent-spawn
core/gh-cli.ts shell: IS_WINDOWS on all 6 execFile calls
test/cli/watch-execute.test.ts Updated expectations for copilot default

Testing

  • Unit tests: All 16 watch-execute tests pass (updated for new copilot default)
  • TypeScript build: Clean compile with TypeScript 5.9.3
  • E2E (manual): Ran local build across 4 repos on Windows:
    • ✅ No spawn EINVAL errors
    • ✅ No rate limit errors with shared fetch
    • ✅ Triage auto-routes issues
    • ✅ Execute spawns agency sessions for eligible issues
    • Pre-existing Windows test failures in storage-provider.test.ts (unicode paths), template-sync.test.ts (template content), team-root-resolution.test.ts (path resolution) — all unrelated to this PR

tamirdresher and others added 2 commits April 8, 2026 11:48
…ithub#920, github#923)

Three fixes for watch capabilities:

1. Shared issue fetch (github#923): Fetch issues + PRs ONCE at round start
   via new RoundData on WatchContext. All 4 capabilities that called
   adapter.listWorkItems() independently now read from context.roundData.
   Core triage (runCheck + checkPRs) also uses shared data.
   Reduces API calls from ~6 to 2 per round.

2. Windows execFile + shell:true (github#920): Added shell: IS_WINDOWS to
   every execFile/execFileSync call across the watch system, gh-cli.ts,
   and health.ts. Fixes 'spawn EINVAL' on Windows where bare commands
   like 'gh' resolve to .cmd wrappers that require a shell.

3. agentCmd default change: Default agent command changed from
   'gh copilot' (deprecated) to standalone 'copilot'. Extracted
   duplicated buildAgentCommand() and spawnWithTimeout() from 7 files
   into shared agent-spawn.ts module.

Files:
- NEW: watch/agent-spawn.ts — shared buildAgentCommand, spawnWithTimeout, spawnAgent, IS_WINDOWS
- watch/types.ts — added RoundData interface + roundData field on WatchContext
- watch/index.ts — fetch once in executeRound(), pass roundData through
- watch/capabilities/{decision-hygiene,monitor-teams,monitor-email,retro}.ts — use agent-spawn.ts
- watch/capabilities/{execute,wave-dispatch}.ts — use agent-spawn.ts + roundData
- watch/capabilities/{fleet-dispatch,two-pass}.ts — use roundData + shell:IS_WINDOWS
- watch/capabilities/{board,self-pull}.ts — shell:IS_WINDOWS on all execFile calls
- watch/health.ts — shell:IS_WINDOWS on gh auth check
- core/gh-cli.ts — shell:IS_WINDOWS on all 6 execFileAsync calls
The default agent command changed from 'gh copilot' to standalone
'copilot' CLI. Updated test expectations accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tamirdresher tamirdresher added the skip-version-check Skip prerelease version guard for this PR label Apr 8, 2026
tamirdresher and others added 2 commits April 8, 2026 19:18
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add resolveCopilotCmd() that tries standalone 'copilot' first, falls
back to 'gh copilot' if not found. Result is cached per process.

Addresses Q's review of PR github#927: hardcoded 'copilot' default could
break users without the standalone CLI installed.

Both buildAgentCommand (shared) and buildAgentCommand (legacy compat)
now use the same detection logic.

Tests updated to accept either resolved command.
…t-dispatch

- Remove unnecessary ChildProcess assignment in spawnAgent
- Fleet-dispatch now uses runtime copilot detection instead of hardcoding

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tamirdresher
tamirdresher merged commit cb57268 into github:insider Apr 12, 2026
tamirdresher added a commit that referenced this pull request Apr 21, 2026
… fetch (#920, #923)

* fix(watch): shared issue fetch, Windows shell:true, agentCmd default (#920, #923)

Three fixes for watch capabilities:

1. Shared issue fetch (#923): Fetch issues + PRs ONCE at round start
   via new RoundData on WatchContext. All 4 capabilities that called
   adapter.listWorkItems() independently now read from context.roundData.
   Core triage (runCheck + checkPRs) also uses shared data.
   Reduces API calls from ~6 to 2 per round.

2. Windows execFile + shell:true (#920): Added shell: IS_WINDOWS to
   every execFile/execFileSync call across the watch system, gh-cli.ts,
   and health.ts. Fixes 'spawn EINVAL' on Windows where bare commands
   like 'gh' resolve to .cmd wrappers that require a shell.

3. agentCmd default change: Default agent command changed from
   'gh copilot' (deprecated) to standalone 'copilot'. Extracted
   duplicated buildAgentCommand() and spawnWithTimeout() from 7 files
   into shared agent-spawn.ts module.

Files:
- NEW: watch/agent-spawn.ts — shared buildAgentCommand, spawnWithTimeout, spawnAgent, IS_WINDOWS
- watch/types.ts — added RoundData interface + roundData field on WatchContext
- watch/index.ts — fetch once in executeRound(), pass roundData through
- watch/capabilities/{decision-hygiene,monitor-teams,monitor-email,retro}.ts — use agent-spawn.ts
- watch/capabilities/{execute,wave-dispatch}.ts — use agent-spawn.ts + roundData
- watch/capabilities/{fleet-dispatch,two-pass}.ts — use roundData + shell:IS_WINDOWS
- watch/capabilities/{board,self-pull}.ts — shell:IS_WINDOWS on all execFile calls
- watch/health.ts — shell:IS_WINDOWS on gh auth check
- core/gh-cli.ts — shell:IS_WINDOWS on all 6 execFileAsync calls

* test: update buildAgentCommand tests for copilot default

The default agent command changed from 'gh copilot' to standalone
'copilot' CLI. Updated test expectations accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: add changeset for watch Windows fixes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(watch): runtime copilot CLI detection with gh fallback

Add resolveCopilotCmd() that tries standalone 'copilot' first, falls
back to 'gh copilot' if not found. Result is cached per process.

Addresses Q's review of PR #927: hardcoded 'copilot' default could
break users without the standalone CLI installed.

Both buildAgentCommand (shared) and buildAgentCommand (legacy compat)
now use the same detection logic.

Tests updated to accept either resolved command.

* fix(watch): remove unused _cp variable, use resolveCopilotCmd in fleet-dispatch

- Remove unnecessary ChildProcess assignment in spawnAgent
- Fleet-dispatch now uses runtime copilot detection instead of hardcoding

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-version-check Skip prerelease version guard for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant