Private
Public Access
0
0

docs(tools): fix run_powershell signature (add patch_callback + correct Popen kwargs + qa_callback also fires on stderr-only)

This commit is contained in:
2026-06-10 23:45:02 -04:00
parent 03056a4f4c
commit aa4ec2ed08
+11 -8
View File
@@ -495,12 +495,15 @@ EXPANDED = "${HOME}/subdir"
`_build_subprocess_env()` copies `os.environ`, prepends `[path].prepend` entries to `PATH`, and sets `[env]` key-value pairs with `${VAR}` expansion.
### `run_powershell(script, base_dir, qa_callback=None) -> str`
### `run_powershell(script, base_dir, qa_callback=None, patch_callback=None) -> str`
1. Prepends `Set-Location -LiteralPath '<base_dir>'` (with escaped single quotes).
2. Locates PowerShell: tries `powershell.exe`, `pwsh.exe`, `powershell`, `pwsh` in order.
3. Runs via `subprocess.Popen([exe, "-NoProfile", "-NonInteractive", "-Command", full_script])`.
4. `process.communicate(timeout=60)` — 60-second hard timeout.
5. On `TimeoutExpired`: kills process tree via `taskkill /F /T /PID`, returns `"ERROR: timed out after 60s"`.
6. Returns combined output: `STDOUT:\n<out>\nSTDERR:\n<err>\nEXIT CODE: <code>`.
7. If `qa_callback` provided and command failed: appends `QA ANALYSIS:\n<qa_callback(stderr)>` — integrates Tier 4 QA error analysis directly.
Actual signature (from `src/shell_runner.py:56`): `def run_powershell(script: str, base_dir: str, qa_callback: Optional[Callable[[str], str]] = None, patch_callback: Optional[Callable[[str, str], Optional[str]]] = None) -> str:`
1. Prepends `Set-Location -LiteralPath '<base_dir>'` (with escaped single quotes via `replace("'", "''")`).
2. Locates PowerShell: tries `powershell.exe`, `pwsh.exe`, `powershell`, `pwsh` in order, via `shutil.which()`.
3. Runs via `subprocess.Popen([exe, "-NoProfile", "-NonInteractive", "-Command", full_script], stdin=DEVNULL, stdout=PIPE, stderr=PIPE, text=True, cwd=base_dir, env=_build_subprocess_env())`.
4. `process.communicate(timeout=60)` — 60-second hard timeout (the constant is `TIMEOUT_SECONDS = 60` at `src/shell_runner.py:21`).
5. On `TimeoutExpired` (or `KeyboardInterrupt`, or any other exception): kills process tree via `subprocess.run(["taskkill", "/F", "/T", "/PID", str(process.pid)], capture_output=True)` and returns the error string. `KeyboardInterrupt` re-raises.
6. Returns combined output as a single string: `STDOUT:\n<out>\nSTDERR:\n<err>\nEXIT CODE: <code>`. Empty `stdout`/`stderr` segments are omitted.
7. If `qa_callback` is provided AND the command failed (returncode != 0) OR produced non-empty stderr: appends `QA ANALYSIS:\n<qa_callback(stderr.strip())>` — integrates Tier 4 QA error analysis (see [guide_mma.md](guide_mma.md) "Tier 4: QA Error Analysis"). Note: the `qa_callback` fires on stderr-only too, not just on non-zero exit code.
8. If `patch_callback` is provided AND the same condition holds: appends `AUTO_PATCH:\n<patch_callback(stderr.strip(), base_dir)>` — the Tier 4 patch generation flow uses this to inject auto-generated fix text into the worker's context without requiring a separate AI round-trip.