"""Pre-flight check for work-order consistency and system health.""" import json import os import re import sys from pathlib import Path import click @click.command(name="preflight") def preflight_cmd(): """Run pre-flight checks before executing work orders.""" issues = [] warnings = [] click.secho("Running pre-flight checks...", fg="cyan") click.echo("") # === Check 1: work-order.md vs checkpoint JSON consistency === work_order = Path.home() / "workspace/assistant/work-order.md" if work_order.exists(): content = work_order.read_text() # Find progress numbers like "进度: X/Y 步骤" progress_match = re.search(r"进度[::]\s*(\d+)/(\d+)\s*步骤", content) if progress_match: wo_current = int(progress_match.group(1)) wo_total = int(progress_match.group(2)) # Find checkpoint files referenced in work-order cp_match = re.search(r"进度档[::]\s*(\S+)", content) if cp_match: cp_path = Path.home() / "workspace" / cp_match.group(1) if cp_path.exists(): try: cp = json.loads(cp_path.read_text()) cp_current = cp.get("currentStep", 0) cp_total = cp.get("totalSteps", 0) cp_completed = len(cp.get("completedSteps", [])) if wo_current != cp_current or wo_total != cp_total: issues.append( f"进度不一致: 工作单 {wo_current}/{wo_total} vs 进度档 {cp_current}/{cp_total}" ) elif cp_current != cp_completed + 1 and cp_current <= cp_total: # currentStep should be next step to do (completed + 1) # unless all completed pass except json.JSONDecodeError: warnings.append(f"进度档 JSON 损坏: {cp_path}") # Check for duplicate step numbers in step list step_lines = re.findall(r"-\s*\[[x ]\]\s*\d+\.", content) step_nums = [] for line in step_lines: m = re.search(r"(\d+)\.", line) if m: step_nums.append(int(m.group(1))) seen = set() for num in step_nums: if num in seen: issues.append(f"步骤 {num} 在清单中重复出现") seen.add(num) # Check for gaps in step numbering if step_nums: expected = list(range(1, max(step_nums) + 1)) missing = [n for n in expected if n not in seen] if missing: warnings.append(f"步骤编号缺失: {missing}") else: warnings.append("工作单文件不存在") # === Check 2: .zshrc PATH references === zshrc = Path.home() / ".zshrc" if zshrc.exists(): zshrc_content = zshrc.read_text() # Find paths in PATH exports (lines starting with export PATH=) for line in zshrc_content.splitlines(): if not line.strip().startswith("export PATH="): continue refs = re.findall(r"/Users/\S+", line) for ref in refs: full_path = Path(ref).expanduser() if not full_path.exists(): issues.append(f".zshrc PATH 引用失效: {ref}") else: warnings.append(".zshrc 不存在") # === Check 3: Workspace symlink health === workspace = Path.home() / "workspace" if workspace.exists(): for item in workspace.iterdir(): if item.is_symlink(): if not item.exists(): issues.append(f"符号链接失效: {item.name} -> {os.readlink(item)}") # === Report === click.echo("-" * 50) if issues: click.secho(f"发现 {len(issues)} 个问题:", fg="red") for issue in issues: click.secho(f" [x] {issue}", fg="red") else: click.secho("未发现严重问题", fg="green") if warnings: click.secho(f"\n{len(warnings)} 个警告:", fg="yellow") for w in warnings: click.secho(f" [!] {w}", fg="yellow") click.echo("-" * 50) if issues: sys.exit(1)