""" Round 12: Commander-monitored Android client testing Monitor phase transitions, detect failures, report to commander. Commander: Claude Code (you) monitors this output. """ import urllib.request import json import sys import time BASE = "http://127.0.0.1:8037/api/v1" TEAM_ID = "5b032316-9e31-4ecb-a2b1-b46c7beff2eb" def login(): req = urllib.request.Request( f"{BASE}/auth/login", data=b"username=admin&password=123456", headers={"Content-Type": "application/x-www-form-urlencoded"} ) return json.loads(urllib.request.urlopen(req).read())["access_token"] TOKEN = login() print(f"[CMD] Logged in. Token: {TOKEN[:30]}...") TASK = """## 任务: Android客户端全面质量审计 ### 目标 D:\\aaa\\aiagent\\android - Kotlin/Jetpack Compose Android 客户端 ### 要求 1. 每个Agent必须扫描真实源代码文件(.kt/.xml/.gradle.kts),不得基于设计文档分析 2. 对标ChatGPT Android和豆包(Doubao)进行UX体验对比 3. 所有发现必须标注具体文件路径和行号 4. 使用 list_files → project_scan → file_read → grep_search 标准流程 ### 各阶段产出 - 架构师: 技术栈分析、模块结构、数据流路径、已知架构风险 - 测试规划师: 15+测试场景、风险矩阵、用户画像 - 功能测试员: 12+真实bug(含文件路径+行号+修复代码) - UX审查员: vs ChatGPT/豆包的差距分析、优先级、修复建议 - 边界探索员: 30+边界场景(网络/并发/数据/输入/资源) - 性能评估员: 线程模型/内存/Compose/网络/数据库反模式 ### 成功标准 - 所有发现引用真实源文件路径和行号 - 跨阶段重复率<10% - 50%以上发现可独立验证 """ body = json.dumps({"project_description": TASK}).encode("utf-8") req = urllib.request.Request( f"{BASE}/teams/{TEAM_ID}/execute/stream", data=body, headers={ "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json" }, method="POST" ) print("[CMD] 任务已下达,等待虚拟团队执行...") print("[CMD] 监控中 — 发现问题会立即报告\n") phases_seen = set() errors = [] start_time = time.time() try: response = urllib.request.urlopen(req, timeout=900) # 15 min timeout buffer = "" while True: chunk = response.read(4096) if not chunk: break try: text = chunk.decode("utf-8") except: text = chunk.decode("gbk", errors="replace") buffer += text while "\n\n" in buffer: event_str, buffer = buffer.split("\n\n", 1) lines = event_str.strip().split("\n") for line in lines: if not line.startswith("data: "): continue try: data = json.loads(line[6:]) event_type = data.get("type", "?") if event_type == "plan_start": print(f"[{time.time()-start_time:.0f}s] PLAN_START | 团队: {data.get('team_name','?')} | 成员: {data.get('member_count','?')}") print(f"[{time.time()-start_time:.0f}s] 项目路径: {data.get('project_path','?')}") elif event_type == "phase_start": pid = f"{data.get('phase','?')}-{data.get('name','?')}" print(f"\n[{time.time()-start_time:.0f}s] PHASE_START | 阶段{data.get('phase','?')}: {data.get('name','?')} | 角色: {data.get('role','?')} | Agent: {data.get('agent','?')}") elif event_type == "phase_done": success = data.get("success", False) iters = data.get("iterations", "?") tool_calls = data.get("tool_calls", "?") output_len = len(data.get("output", "")) files = data.get("files", []) status_icon = "OK" if success else "FAIL" print(f"[{time.time()-start_time:.0f}s] PHASE_DONE {status_icon} | 阶段{data.get('phase','?')}: {data.get('name','?')}") print(f" success={success} iterations={iters} tool_calls={tool_calls} output={output_len}chars files={len(files)}") if not success: error_msg = data.get("error", "") print(f" ERROR: {error_msg[:300]}") errors.append({ "phase": data.get("name", "?"), "role": data.get("role", "?"), "error": error_msg }) if files: for f in files[:5]: print(f" file: {f}") elif event_type == "plan_done": plan = data.get("plan", {}) phases = plan.get("phases", []) success = data.get("success", False) print(f"\n[{time.time()-start_time:.0f}s] PLAN_DONE | success={success} | phases={len(phases)}") if not success: raw = data.get("raw_output", "")[:200] print(f" raw: {raw}") if phases: for p in phases: deps = p.get("depends_on", []) dep_str = f" depends_on={deps}" if deps else "" print(f" Phase{p.get('phase')}: {p.get('name','?')} [{p.get('role','?')}]{dep_str}") elif event_type == "plan_fallback": print(f"\n[{time.time()-start_time:.0f}s] PLAN_FALLBACK | {data.get('content','?')[:200]}") elif event_type == "qa_done": review = data.get("review", {}) print(f"\n[{time.time()-start_time:.0f}s] QA_DONE | pass={review.get('pass','?')} score={review.get('score','?')}") elif event_type == "final": print(f"\n[{'='*50}]") print(f"[{time.time()-start_time:.0f}s] FINAL | 执行完成!") print(f" 项目路径: {data.get('project_path','?')}") files = data.get("files", []) print(f" 产出文件: {len(files)} 个") for f in files[:15]: print(f" {f}") if len(files) > 15: print(f" ...还有 {len(files)-15} 个文件") deliv = data.get("deliverable", "")[:500] if deliv: print(f" 交付物摘要: {deliv}") elif event_type == "error": msg = data.get("content", "")[:400] print(f"\n[{time.time()-start_time:.0f}s] *** ERROR *** {msg}") errors.append({"phase": "global", "error": msg}) else: # brief for other events short = str(data.get("content", str(data)))[:80] print(f"[{time.time()-start_time:.0f}s] {event_type}: {short}") except json.JSONDecodeError: pass print(f"\n[CMD] 流结束 | 总耗时: {time.time()-start_time:.0f}s | 错误数: {len(errors)}") except Exception as e: print(f"\n[CMD] 连接异常: {e}") finally: if errors: print(f"\n[CMD] === 需要处理的错误 ({len(errors)}) ===") for i, err in enumerate(errors): print(f" [{i+1}] {err['phase']}({err.get('role','?')}): {err['error'][:200]}")