Skip to content

[Bug]: Windows install cancellation can leave cargo running after Ctrl+C #237

@Drswith

Description

@Drswith

What went wrong?

qtx install vtcode on Windows can return control to PowerShell after Ctrl+C while the underlying cargo install vtcode process continues fetching crates and writing progress to the same console.

The provided terminal fragment shows PowerShell prompts appearing after repeated ^C, but Cargo progress keeps printing afterward:

PS C:\Users\drs> qtx install vtcode
Installing vtcode v0.105.7
    Updating crates.io index
       Fetch [===qtx install vtcode^C          ] 44 complete; 8 pending
PS C:\Users\drs> ^C
PS C:\Users\drs>        Fetch [========>                        ] 45 complete; 7 pending
...
PS C:\Users\drs>        Fetch [==============>                  ] 429 complete; 4 pending
Locking 738 packages to latest compatible versions
      Adding agent-client-protocol v0.10.4 (available: v0.11.1)

This makes the CLI appear impossible to exit cleanly and leaves the user with installer output interleaved with new shell prompts.

Reproduction steps

  1. On Windows PowerShell, run qtx install vtcode in an environment where VTCode is not already installed and Cargo is available.
  2. Wait until cargo install vtcode begins fetching from crates.io.
  3. Press Ctrl+C once or repeatedly.
  4. Observe whether PowerShell returns to PS ...> while Cargo fetch/build output continues printing.

Expected behavior

Ctrl+C should cancel the Quantex lifecycle operation and terminate the managed installer process tree. The terminal should not continue receiving Cargo progress after Quantex reports cancellation or returns to the shell.

If immediate termination is not possible on Windows, Quantex should make the cancellation state explicit, wait for a bounded cleanup window, and avoid releasing control/state in a way that lets installer output keep mutating the current console session unexpectedly.

Actual behavior

The parent qtx process appears to handle SIGINT and return to PowerShell, but the underlying Cargo operation keeps running and emitting inherited-stdio progress. Repeated ^C does not reliably stop the ongoing Cargo fetch/build output.

Diagnostics collected

User-provided terminal log is included above.

Relevant code paths observed in the repository:

  • src/package-manager/cargo.ts runs cargo install <package> through spawnWithQuantexStdio(...).
  • src/utils/child-process.ts uses inherited stdio for human output and registers cancellation as proc.kill?.('SIGTERM').
  • src/command-runtime.ts races command execution with a signal promise. On SIGINT, it calls cancelCliContextOperations() and resolves a CANCELLED result without waiting for the spawned installer process tree to fully exit.
  • On Windows, killing only the direct child with SIGTERM is not a reliable process-tree cancellation strategy for Cargo and its descendants, especially with inherited console handles.

Likely root cause: Quantex cancels the CLI runtime before it has reliably terminated and joined the installer process tree. The direct child kill is too narrow for Windows/Cargo, and the cancellation path returns control before installer output has stopped.

Suggested direction

  • Treat cancellation of managed installers as process-tree cancellation, not just direct child cancellation.
  • On Windows, use a termination strategy that reaches descendants, for example a job object, taskkill /T /F /PID <pid> fallback, or a shell/process-group approach with a bounded graceful-first cleanup.
  • After SIGINT or timeout, wait for the installer handle to exit or for a short cleanup deadline before returning the final cancelled result.
  • Ensure lifecycle locks/state are not released as successful or retry-safe while the external installer may still be running.
  • Add a focused regression test around cancellation semantics using a fake long-running installer process. Full Windows/Cargo validation can be manual or sandboxed if needed.

Linked artifacts

  • docs/runbooks/quantex-troubleshooting.md cancellation section says Quantex maps timeout and signal cancellation into stable lifecycle behavior and terminates managed child processes according to runtime policy.
  • This issue likely requires an OpenSpec change before implementation because the fix changes observable CLI lifecycle cancellation behavior.

Checklist

  • I checked the canonical troubleshooting runbook first.
  • I included enough detail for an agent to reproduce or continue debugging.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions