""" Free-form command parser for the CI/CD Doctor environment. Converts raw command strings into structured ParsedCommand objects. """ import re from dataclasses import dataclass from typing import Optional @dataclass class ParsedCommand: type: str # "cat" | "echo_append" | "sed" | "pipeline_run" | "pipeline_logs" | "pipeline_status" | "diagnose" | "unknown" filename: Optional[str] = None content: Optional[str] = None # for echo >> pattern: Optional[str] = None # for sed: old value replacement: Optional[str] = None # for sed: new value stage: Optional[str] = None diagnosis: Optional[str] = None # for diagnose: agent's theory about the bug def parse_command(command: str) -> ParsedCommand: command = command.strip() for sep in ["&&", ";"]: if sep in command: command = command.split(sep)[0].strip() break m = re.match(r"cat\s+(.+)", command) if m: return ParsedCommand(type="cat", filename=m.group(1).strip()) m = re.match(r'echo\s+([\'"])(.*?)\1\s*>>\s*(\S+)', command, re.DOTALL) if m: return ParsedCommand( type="echo_append", content=m.group(2), filename=m.group(3), ) # Example supported: sed -i 's/old/new/g' file OR sed -i "s|old|new|" file m = re.match( r"sed\s+-i\s+([\'\"]?)s(.)(.+?)\2(.*?)\2([g]*)\1\s+(\S+)", command, ) if m: return ParsedCommand( type="sed", pattern=m.group(3), replacement=m.group(4), filename=m.group(6), ) if re.fullmatch(r"pipeline\s+run", command): return ParsedCommand(type="pipeline_run") m = re.match(r"pipeline\s+logs(?:\s+(\S+))?\s*$", command) if m: return ParsedCommand(type="pipeline_logs", stage=m.group(1)) if re.fullmatch(r"pipeline\s+status", command): return ParsedCommand(type="pipeline_status") m = re.match(r'diagnose\s+([\'"])(.*?)\1\s*$', command, re.DOTALL) if m: return ParsedCommand(type="diagnose", diagnosis=m.group(2)) return ParsedCommand(type="unknown")