From aa4ec2ed0884174d55aa33b996867ee473caef30 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 10 Jun 2026 23:45:02 -0400 Subject: [PATCH] docs(tools): fix run_powershell signature (add patch_callback + correct Popen kwargs + qa_callback also fires on stderr-only) --- docs/guide_tools.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/guide_tools.md b/docs/guide_tools.md index e27c9e7b..c531484a 100644 --- a/docs/guide_tools.md +++ b/docs/guide_tools.md @@ -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 ''` (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\nSTDERR:\n\nEXIT CODE: `. -7. If `qa_callback` provided and command failed: appends `QA ANALYSIS:\n` — 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 ''` (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\nSTDERR:\n\nEXIT 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` — 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` — 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.