#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Reconstruct admin.html from JSONL conversation transcript. Only applies operations that succeeded (matched tool_result with no error). """ import json import sys JSONL_PATH = r'C:/Users/Administrator/.claude/projects/h--lab-safety-monitor-exam-main-2026/369b78fb-8697-4ea6-b83e-eeb87cee0bba.jsonl' OUTPUT_PATH = r'H:/lab-safety-monitor/exam_main_2026/admin.html' # --- Pass 1: collect tool_use items for admin.html, keyed by tool_use_id --- tool_uses = {} # tool_use_id -> {'ts', 'name', 'input', 'order'} order = 0 tool_results = {} # tool_use_id -> {'ts', 'is_error', 'content'} with open(JSONL_PATH, 'r', encoding='utf-8') as f: for raw_line in f: raw_line = raw_line.strip() if not raw_line: continue try: obj = json.loads(raw_line) except Exception: continue ts = obj.get('timestamp', '') msg = obj.get('message', {}) if not isinstance(msg, dict): continue content = msg.get('content', []) if not isinstance(content, list): continue for item in content: if not isinstance(item, dict): continue if item.get('type') == 'tool_use': name = item.get('name', '') inp = item.get('input', {}) fp = inp.get('file_path', '') if 'admin.html' in fp and name in ('Write', 'Edit'): tid = item.get('id', '') tool_uses[tid] = { 'ts': ts, 'name': name, 'input': inp, 'order': order, } order += 1 elif item.get('type') == 'tool_result': tid = item.get('tool_use_id', '') is_error = item.get('is_error', False) tc = item.get('content', '') # Also check for error strings in content if isinstance(tc, list): tc_text = ' '.join(x.get('text', '') if isinstance(x, dict) else str(x) for x in tc) else: tc_text = str(tc) if '' in tc_text: is_error = True tool_results[tid] = {'ts': ts, 'is_error': is_error, 'content': tc_text} # Sort operations by original order ops = sorted(tool_uses.values(), key=lambda x: x['order']) print(f"Total admin.html operations: {len(ops)}") # Find the initial Write write_ops = [op for op in ops if op['name'] == 'Write'] edit_ops = [op for op in ops if op['name'] == 'Edit'] if not write_ops: print("ERROR: No Write operation found!") sys.exit(1) # Get the write that actually succeeded # Find tool_use_id for the write write_tid = None for tid, v in tool_uses.items(): if v['name'] == 'Write' and 'admin.html' in v['input'].get('file_path', ''): r = tool_results.get(tid, {}) if not r.get('is_error', True): write_tid = tid break if write_tid is None: print("WARNING: Write had no matching result, using it anyway") write_tid = [tid for tid, v in tool_uses.items() if v['name'] == 'Write'][0] file_content = tool_uses[write_tid]['input'].get('content', '') print(f"Initial Write content length: {len(file_content)}") # Apply edits in order, skipping failed ones skipped = 0 applied = 0 for tid, v in sorted([(tid, v) for tid, v in tool_uses.items() if v['name'] == 'Edit'], key=lambda x: x[1]['order']): result = tool_results.get(tid, {}) if result.get('is_error', False): print(f" SKIP (original error): {v['ts']}") skipped += 1 continue inp = v['input'] old = inp.get('old_string', '') new = inp.get('new_string', '') replace_all = inp.get('replace_all', False) if replace_all: count = file_content.count(old) file_content = file_content.replace(old, new) print(f" replace_all {v['ts']}: {count} replacements, len={len(file_content)}") applied += 1 else: count = file_content.count(old) if count == 0: print(f" WARNING not found: {v['ts']} old={repr(old[:80])}") # Still count as applied since original session said success elif count == 1: file_content = file_content.replace(old, new, 1) print(f" OK {v['ts']}: len={len(file_content)}") applied += 1 else: # Multiple matches - replace first file_content = file_content.replace(old, new, 1) print(f" MULTI({count}) {v['ts']}: replaced first, len={len(file_content)}") applied += 1 print(f"\nApplied: {applied}, Skipped: {skipped}") print(f"Final content length: {len(file_content)}") print(f"Final line count: {file_content.count(chr(10)) + 1}") with open(OUTPUT_PATH, 'w', encoding='utf-8') as f: f.write(file_content) print(f"\nWritten to: {OUTPUT_PATH}")