Context
PR #11769 repaired #11767 / #10684 by removing the direct cross-spawn dependency and owning the Windows .cmd dispatch path inside ai/scripts/resumeHarness.mjs. The operator explicitly called out that this should not grow #11769: the active PR should remain the Antigravity dependency-removal fix, while reusable helper work belongs in a separate ticket.
Pre-creation duplicate sweep:
- Knowledge Base ticket search for
Windows batch spawn helper cross-spawn cmd.exe quoting reusable subprocess helper ticket found related historical Windows/subprocess issues (#7795, #10795), but no equivalent ticket for a reusable batch-spawn helper.
- Exact repo sweep over
resources/content/issues and resources/content/discussions for cross-spawn, cmd.exe, spawn helper, windows batch, batch spawn, and .cmd found related mentions but no equivalent ticket.
The Problem
The repo-owned Windows batch quoting logic now exists in one script because #11769 needed a contained fix. That is correct for the PR scope, but it leaves follow-up risk:
ai/scripts/resumeHarness.mjs owns isWindowsBatchCommand(), quoteWindowsBatchArgument(), buildWindowsBatchCommandLine(), and createSpawnRequest() locally.
- Other agent/build subprocess surfaces still have their own platform handling or raw child-process calls.
- Future Windows
.cmd fixes could reintroduce ad hoc quoting, shell: true, or another direct dependency if there is no reusable local primitive.
The Architectural Reality
Current evidence from the code sweep:
ai/scripts/resumeHarness.mjs now contains the repo-owned helper functions used by #11769.
test/playwright/unit/ai/scripts/resumeHarness.spec.mjs contains adversarial coverage for the current helper behavior.
buildScripts/build/all.mjs selects npm.cmd on Windows and uses spawnSync(..., {shell: true}) across several build steps.
buildScripts/webpack/buildThreads.mjs uses spawnSync(..., {shell: true}) for webpack command dispatch.
buildScripts/webpack/development/webpack.config.appworker.mjs and buildScripts/webpack/production/webpack.config.appworker.mjs pass a composed copyFolder.mjs -s ... -t ... string through a shell path.
ai/scripts/heartbeatLock.mjs, ai/scripts/bridge-daemon.mjs, ai/daemons/SwarmHeartbeatService.mjs, and ai/services/neural-link/ConnectionService.mjs have generic subprocess call sites that may need consistent Windows batch-wrapper behavior later.
ai/daemons/services/PrimaryRepoSyncService.mjs already has explicit npm.cmd handling through injected execFileSyncFn test seams.
This is not a request to rewrite every subprocess caller in one PR. The immediate substrate is the helper primitive and its first consumer migration.
The Fix
Create a small repo-owned Windows batch spawn helper and migrate the current resumeHarness implementation to consume it.
Expected shape:
- Extract the Windows batch detection, quoting, command-line construction, and spawn-request construction from
ai/scripts/resumeHarness.mjs into a shared .mjs helper selected through structural pre-flight at implementation time.
- Preserve the existing direct-spawn path for POSIX hosts and native Windows executables.
- Keep
.cmd / .bat dispatch scoped to cmd.exe /d /s /v:off /c with repo-owned quoting.
- Move or duplicate the existing adversarial unit coverage to the helper boundary.
- Migrate
resumeHarness as the first consumer.
- Optionally migrate one additional low-risk agent subprocess consumer if the helper API proves clean and the diff remains small.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
| Repo-owned Windows batch spawn helper |
ai/scripts/resumeHarness.mjs behavior introduced by PR #11769 |
Build spawn requests that execute .cmd / .bat through cmd.exe /d /s /v:off /c with escaped payload data |
POSIX and native executables keep direct spawn(cmd, args) behavior |
JSDoc @summary on exported helper functions |
Unit coverage with adversarial metacharacter and newline payloads |
resumeHarness subprocess dispatch |
#11767 / PR #11769 |
Consume the shared helper without changing harness behavior |
Existing #11769 logic remains the behavior baseline |
Existing resumeHarness JSDoc references updated if needed |
Existing resumeHarness.spec.mjs assertions still pass |
| Future subprocess callers |
Codebase sweep listed above |
Provide a small local primitive so future migrations do not add cross-spawn or ad hoc shell quoting |
Callers can remain unchanged until separately migrated |
Ticket/PR notes identify candidates without forcing broad churn |
Follow-up PR shows at least one migrated consumer or a clear non-migration rationale |
Acceptance Criteria
Out of Scope
- Broad conversion of all
shell: true build-script call sites.
- Rewriting build orchestration or webpack command topology.
- Changing PR #11769 behavior or widening its scope.
- Solving unrelated Windows shell compatibility issues without a concrete caller and test.
- Adding a third-party subprocess abstraction dependency.
Avoided Traps
- Do not treat
cross-spawn as the standard answer here. The operator rejected the dependency path for #11769 because this behavior is small enough to own locally.
- Do not turn this into a sweeping build-system cleanup. The value is a reusable primitive plus one proven consumer, not a giant shell migration.
- Do not rely on negated close-keyword phrasing in PR bodies when referencing related tickets; GitHub can still parse close targets incorrectly.
Related
Origin Session ID: 2741c4bd-92b2-428b-92d3-ab718d9a7c41
Retrieval Hint: Windows batch spawn helper cross-spawn cmd.exe quoting resumeHarness PR #11769
Retrieval Hint: quoteWindowsBatchArgument buildWindowsBatchCommandLine createSpawnRequest
Context
PR #11769 repaired #11767 / #10684 by removing the direct
cross-spawndependency and owning the Windows.cmddispatch path insideai/scripts/resumeHarness.mjs. The operator explicitly called out that this should not grow #11769: the active PR should remain the Antigravity dependency-removal fix, while reusable helper work belongs in a separate ticket.Pre-creation duplicate sweep:
Windows batch spawn helper cross-spawn cmd.exe quoting reusable subprocess helper ticketfound related historical Windows/subprocess issues (#7795, #10795), but no equivalent ticket for a reusable batch-spawn helper.resources/content/issuesandresources/content/discussionsforcross-spawn,cmd.exe,spawn helper,windows batch,batch spawn, and.cmdfound related mentions but no equivalent ticket.The Problem
The repo-owned Windows batch quoting logic now exists in one script because #11769 needed a contained fix. That is correct for the PR scope, but it leaves follow-up risk:
ai/scripts/resumeHarness.mjsownsisWindowsBatchCommand(),quoteWindowsBatchArgument(),buildWindowsBatchCommandLine(), andcreateSpawnRequest()locally..cmdfixes could reintroduce ad hoc quoting,shell: true, or another direct dependency if there is no reusable local primitive.The Architectural Reality
Current evidence from the code sweep:
ai/scripts/resumeHarness.mjsnow contains the repo-owned helper functions used by #11769.test/playwright/unit/ai/scripts/resumeHarness.spec.mjscontains adversarial coverage for the current helper behavior.buildScripts/build/all.mjsselectsnpm.cmdon Windows and usesspawnSync(..., {shell: true})across several build steps.buildScripts/webpack/buildThreads.mjsusesspawnSync(..., {shell: true})for webpack command dispatch.buildScripts/webpack/development/webpack.config.appworker.mjsandbuildScripts/webpack/production/webpack.config.appworker.mjspass a composedcopyFolder.mjs -s ... -t ...string through a shell path.ai/scripts/heartbeatLock.mjs,ai/scripts/bridge-daemon.mjs,ai/daemons/SwarmHeartbeatService.mjs, andai/services/neural-link/ConnectionService.mjshave generic subprocess call sites that may need consistent Windows batch-wrapper behavior later.ai/daemons/services/PrimaryRepoSyncService.mjsalready has explicitnpm.cmdhandling through injectedexecFileSyncFntest seams.This is not a request to rewrite every subprocess caller in one PR. The immediate substrate is the helper primitive and its first consumer migration.
The Fix
Create a small repo-owned Windows batch spawn helper and migrate the current
resumeHarnessimplementation to consume it.Expected shape:
ai/scripts/resumeHarness.mjsinto a shared.mjshelper selected through structural pre-flight at implementation time..cmd/.batdispatch scoped tocmd.exe /d /s /v:off /cwith repo-owned quoting.resumeHarnessas the first consumer.Contract Ledger Matrix
ai/scripts/resumeHarness.mjsbehavior introduced by PR #11769.cmd/.batthroughcmd.exe /d /s /v:off /cwith escaped payload dataspawn(cmd, args)behavior@summaryon exported helper functionsresumeHarnesssubprocess dispatchresumeHarnessJSDoc references updated if neededresumeHarness.spec.mjsassertions still passcross-spawnor ad hoc shell quotingAcceptance Criteria
@summaryand clear exported API.resumeHarnessimports and uses the shared helper instead of owning the helper functions locally..cmddispatch throughcmd.exe /d /s /v:off /cand adversarial argument escaping.cross-spawndependency is added.Out of Scope
shell: truebuild-script call sites.Avoided Traps
cross-spawnas the standard answer here. The operator rejected the dependency path for #11769 because this behavior is small enough to own locally.Related
Origin Session ID: 2741c4bd-92b2-428b-92d3-ab718d9a7c41
Retrieval Hint:
Windows batch spawn helper cross-spawn cmd.exe quoting resumeHarness PR #11769Retrieval Hint:quoteWindowsBatchArgument buildWindowsBatchCommandLine createSpawnRequest