解析 Claude Code MCTS log 文件,提取节点树结构 Returns: nodes: {node_id: NodeInfo} root_id: 根节点ID
(log_file: str)
| 32 | |
| 33 | |
| 34 | def parse_log_claude(log_file: str) -> Tuple[Dict[str, NodeInfo], str]: |
| 35 | """ |
| 36 | 解析 Claude Code MCTS log 文件,提取节点树结构 |
| 37 | |
| 38 | Returns: |
| 39 | nodes: {node_id: NodeInfo} |
| 40 | root_id: 根节点ID |
| 41 | """ |
| 42 | nodes: Dict[str, NodeInfo] = {} |
| 43 | root_id = None |
| 44 | |
| 45 | print(f"Parsing Claude Code MCTS log: {log_file}...") |
| 46 | |
| 47 | with open(log_file, 'r', encoding='utf-8') as f: |
| 48 | for line in f: |
| 49 | # 提取根节点 |
| 50 | # [step] Starting from root |
| 51 | # [select] Starting from node XXX, stage=root, is_terminal=False |
| 52 | if '[select] Starting from node' in line and 'stage=root' in line: |
| 53 | match = re.search(r'from node (\w+).*stage=root', line) |
| 54 | if match: |
| 55 | node_id = match.group(1) |
| 56 | if node_id not in nodes: |
| 57 | nodes[node_id] = NodeInfo(node_id, "root") |
| 58 | root_id = node_id |
| 59 | |
| 60 | # 提取 draft 节点创建 |
| 61 | # [draft] node=XXX generating initial code |
| 62 | if '[draft] node=' in line and 'generating initial code' in line: |
| 63 | match = re.search(r'node=(\w+)', line) |
| 64 | if match: |
| 65 | node_id = match.group(1) |
| 66 | if node_id not in nodes: |
| 67 | nodes[node_id] = NodeInfo(node_id, "draft", root_id) |
| 68 | if root_id and root_id in nodes: |
| 69 | # 添加为 root 的子节点(如果还不在子节点列表中) |
| 70 | if node_id not in nodes[root_id].children_ids: |
| 71 | nodes[root_id].children_ids.append(node_id) |
| 72 | |
| 73 | # 提取 improve 节点创建 |
| 74 | # [improve] parent=XXX node=YYY improving code |
| 75 | if '[improve] parent=' in line and 'improving code' in line: |
| 76 | match = re.search(r'parent=(\w+).*node=(\w+)', line) |
| 77 | if match: |
| 78 | parent_id = match.group(1) |
| 79 | node_id = match.group(2) |
| 80 | if node_id not in nodes: |
| 81 | nodes[node_id] = NodeInfo(node_id, "improve", parent_id) |
| 82 | if parent_id in nodes: |
| 83 | # 添加为父节点的子节点(如果还不在子节点列表中) |
| 84 | if node_id not in nodes[parent_id].children_ids: |
| 85 | nodes[parent_id].children_ids.append(node_id) |
| 86 | |
| 87 | # 提取运行状态 |
| 88 | # [draft] node=XXX run SUCCESS |
| 89 | # [draft] node=XXX run FAILED, attempting to fix |
| 90 | if 'node=' in line and ('run SUCCESS' in line or 'run FAILED' in line): |
| 91 | match = re.search(r'node=(\w+).*run (SUCCESS|FAILED)', line) |
no test coverage detected