@@ -408,16 +408,47 @@ def sanitize_verification_commands( |
| 408 | 408 | normalized = str(command or "").strip() |
| 409 | 409 | if not normalized: |
| 410 | 410 | continue |
| 411 | | - detected_paths = _extract_verification_command_paths(normalized) |
| 412 | | - if detected_paths and any( |
| 413 | | - not _path_is_within_allowed_verification_roots(path, allowed_roots) |
| 414 | | - for path in detected_paths |
| 415 | | - ): |
| 416 | | - continue |
| 417 | | - _append_unique(sanitized, normalized) |
| 411 | + for candidate in _split_concatenated_verification_command(normalized): |
| 412 | + candidate = _normalize_directory_test_command(candidate) |
| 413 | + detected_paths = _extract_verification_command_paths(candidate) |
| 414 | + if detected_paths and any( |
| 415 | + not _path_is_within_allowed_verification_roots(path, allowed_roots) |
| 416 | + for path in detected_paths |
| 417 | + ): |
| 418 | + continue |
| 419 | + _append_unique(sanitized, candidate) |
| 418 | 420 | return sanitized |
| 419 | 421 | |
| 420 | 422 | |
| 423 | +def _split_concatenated_verification_command(command: str) -> list[str]: |
| 424 | + """Split common accidental command concatenations from model-authored plans.""" |
| 425 | + |
| 426 | + if not command.strip(): |
| 427 | + return [] |
| 428 | + if len(re.findall(r"(?<!\S)(?:ls|test)\s+", command)) < 2: |
| 429 | + return [command] |
| 430 | + pieces = [ |
| 431 | + piece.strip() |
| 432 | + for piece in re.split(r"\s+(?=(?:ls|test)\s+)", command) |
| 433 | + if piece.strip() |
| 434 | + ] |
| 435 | + return pieces or [command] |
| 436 | + |
| 437 | + |
| 438 | +def _normalize_directory_test_command(command: str) -> str: |
| 439 | + try: |
| 440 | + tokens = shlex.split(command) |
| 441 | + except ValueError: |
| 442 | + return command |
| 443 | + if len(tokens) != 3 or tokens[0] != "test" or tokens[1] != "-f": |
| 444 | + return command |
| 445 | + target = tokens[2] |
| 446 | + target_path = Path(target).expanduser() |
| 447 | + if target.endswith("/") or target_path.is_dir(): |
| 448 | + return f"test -d {shlex.quote(target)}" |
| 449 | + return command |
| 450 | + |
| 451 | + |
| 421 | 452 | def build_verification_summary(evidence: list[VerificationEvidence]) -> str: |
| 422 | 453 | """Create a short evidence summary for the final user response.""" |
| 423 | 454 | |