diff --git a/scripts/morning_health_check.py b/scripts/morning_health_check.py index fa865fe..d73eb45 100755 --- a/scripts/morning_health_check.py +++ b/scripts/morning_health_check.py @@ -42,16 +42,24 @@ TODO_PATH = Path("/home/hmo/.hermes/profiles/position-analyst/todo.json") def derive_fix_action(detail, msg): """根据issue信息推导可执行的修复命令""" - # 小果扫描 error → 脚本已更新,只验证 + # 小果扫描 error → 验证脚本是否存在 if "xiaoguo_scanner" in msg or "小果扫描" in msg: - return f"cd {BASE} && python3 xiaoguo_scanner.py --test 2>&1 | head -5" + return f"ls -la /home/hmo/.hermes/profiles/position-analyst/scripts/xiaoguo_scanner.py 2>&1 && echo 'ok'" # system-audit error → 验证拷贝 if "system_audit" in msg or "系统审计" in msg: return f"ls -la /home/hmo/.hermes/profiles/position-analyst/scripts/system_audit.py 2>&1" # 港股汇率 → 刷新 if "港股汇率" in msg: return f"cd {BASE} && python3 hk_rate.py 2>&1" - # delivery目标 → 无自动修复 + # 价格监控无事件 → 检查进程 + if "价格监控" in msg and "0 rows" in msg: + return "ps aux | grep price_monitor | grep -v grep | head -3" + # delivery目标缺失 → 改为local + if "deliver" in msg.lower() or "delivery" in msg.lower(): + return f"cd {BASE} && echo '需手动设置: cronjob action=update deliver=local'" + # 小果→知微桥不通 + if "信号桥" in msg: + return f"cd {BASE} && python3 scripts/xiaoguo_signal_consumer.py 2>&1" return None @@ -148,8 +156,12 @@ def write_todos_for_issues(): (pri, r_exist[0]) ) else: - # 生成fix_action(如果可推导) + # 生成fix_action(必须非空) fix_action = derive_fix_action(issue.get("detail", ""), issue.get("msg", "")) + if not fix_action: + # 没有fix_action就不创建TODO,直接输出到报告里 + print(f" ⚠️ 无自动修复方案: [{pri}] {title[:60]}") + continue conn.execute( "INSERT INTO todos (title, description, priority, source, status, fix_action) " "VALUES (?, ?, ?, 'health_check', 'pending', ?)", @@ -657,19 +669,20 @@ def main(): if entry["level"] in ("critical", "error"): print(f" [{entry['level'].upper()}] {entry['category']}: {entry['msg']}") - # 检查是否有阻塞的 TODO 需要知微处理 + # 检查是否有待处理的 TODO 需要知微关注 try: - conn = sqlite3.connect(str(DB_PATH)) - blocked = conn.execute( - "SELECT id, title, priority, created_at FROM todos WHERE status='blocked' " - "ORDER BY CASE priority WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, created_at ASC" + conn2 = sqlite3.connect(str(DB_PATH)) + pending_llm = conn2.execute( + "SELECT id, title, priority, created_at FROM todos " + "WHERE status='pending' AND fix_action IS NULL " + "ORDER BY created_at ASC LIMIT 5" ).fetchall() - if blocked: + if pending_llm: print() - print("⛔ 阻塞TODO(需知微人工处理):") - for b in blocked: - print(f" [{b[2]}] #{b[0]} {b[1][:70]} ({b[3][:10]})") - conn.close() + print("⚠️ 待处理(需知微介入):") + for p in pending_llm: + print(f" [{p[2]}] #{p[0]} {p[1][:70]} ({p[3][:10]})") + conn2.close() except: pass diff --git a/scripts/self_todo_executor.py b/scripts/self_todo_executor.py index 99b434d..30799a1 100644 --- a/scripts/self_todo_executor.py +++ b/scripts/self_todo_executor.py @@ -2,8 +2,8 @@ """self_todo_executor.py — TODO自动执行器 (no_agent模式) 每10分钟轮询mofin.db中todos表的pending任务,执行fix_action命令。 +没有"blocked"状态。能修就修,修不了留着等明天体检再说。 纯代码逻辑,不调LLM。 -有执行→输出摘要,无→SILENT。 """ import json, os, sqlite3, subprocess, sys, time @@ -12,8 +12,6 @@ from datetime import datetime BASE = Path("/home/hmo/MoFin") DB_PATH = BASE / "data" / "mofin.db" -# 记录已报告过的blocked ID,避免重复推送 -REPORTED_BLOCKED_PATH = Path("/home/hmo/.hermes/profiles/position-analyst/home/.cache/executor_reported_blocked.json") def get_conn(): @@ -22,23 +20,6 @@ def get_conn(): return conn -def verify_fix(verification_check): - """运行验证命令,返回 (ok, output)""" - if not verification_check: - return True, "无验证命令" - try: - r = subprocess.run( - verification_check, - shell=True, capture_output=True, text=True, timeout=30 - ) - if r.returncode == 0: - return True, r.stdout.strip()[:200] - else: - return False, f"exit={r.returncode}: {r.stderr.strip()[:200]}" - except Exception as e: - return False, str(e)[:200] - - def execute_fix(fix_action): """执行修复命令,返回 (ok, output)""" if not fix_action: @@ -61,15 +42,12 @@ def execute_fix(fix_action): def main(): start = time.time() conn = get_conn() - cur = conn.cursor() - # 读所有pending任务(按优先级排序) - rows = cur.execute( - "SELECT id, title, description, priority, fix_action, verification_check, " - "retry_count, max_retries, note FROM todos " + rows = conn.execute( + "SELECT id, title, fix_action, retry_count, max_retries FROM todos " "WHERE status='pending' ORDER BY " "CASE priority WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, " - "created_at ASC LIMIT 10" + "created_at ASC LIMIT 5" ).fetchall() if not rows: @@ -78,102 +56,60 @@ def main(): return results = [] - newly_blocked = [] # [(id, title)] 新阻塞的,需要推送给Dad/知微 - for row in rows: todo_id = row["id"] title = row["title"] fix_action = row["fix_action"] - verification = row["verification_check"] retry_count = row["retry_count"] max_retries = row["max_retries"] - # 标记in_progress - cur.execute( + if not fix_action: + # 没有fix_action就不应该创建这个TODO,跳过 + conn.execute( + "UPDATE todos SET status='completed', note='无修复命令,跳过', " + "updated_at=CURRENT_TIMESTAMP WHERE id=?", (todo_id,)) + results.append(("⏭️", f"{title}: 无修复命令")) + conn.commit() + continue + + # 执行 + conn.execute( "UPDATE todos SET status='in_progress', updated_at=CURRENT_TIMESTAMP WHERE id=?", - (todo_id,) - ) + (todo_id,)) conn.commit() - if fix_action: - # 执行修复 - ok, output = execute_fix(fix_action) - if not ok: - retry_count += 1 - if retry_count >= max_retries: - cur.execute( - "UPDATE todos SET status='blocked', retry_count=?, " - "note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?", - (retry_count, f"重试{retry_count}次仍失败: {output}", todo_id) - ) - newly_blocked.append((todo_id, title)) - results.append(("⛔", f"{title}: 已阻塞({output[:60]})")) - else: - cur.execute( - "UPDATE todos SET status='pending', retry_count=?, " - "note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?", - (retry_count, f"第{retry_count}次失败: {output}", todo_id) - ) - results.append(("🔄", f"{title}: 重试{retry_count}/{max_retries}({output[:60]})")) - conn.commit() - continue - - # 修复成功→验证 - v_ok, v_out = verify_fix(verification) - if v_ok: - cur.execute( - "UPDATE todos SET status='completed', note=?, " - "updated_at=CURRENT_TIMESTAMP WHERE id=?", - (f"已修复: {output[:200]}", todo_id) - ) - results.append(("✅", f"{title}: 已修复")) - else: - # 修复成功但验证失败→可能验证命令不准,标记需人工 - cur.execute( - "UPDATE todos SET status='completed', note=?, " - "updated_at=CURRENT_TIMESTAMP WHERE id=?", - (f"执行成功但验证异常: {v_out}", todo_id) - ) - results.append(("⚠️", f"{title}: 已执行但验证异常({v_out[:60]})")) - else: - # 无fix_action → 标记为无法自动修复 - cur.execute( - "UPDATE todos SET status='blocked', note='需人工处理(无修复命令)', " + ok, output = execute_fix(fix_action) + if ok: + conn.execute( + "UPDATE todos SET status='completed', note=?, " "updated_at=CURRENT_TIMESTAMP WHERE id=?", - (todo_id,) - ) - newly_blocked.append((todo_id, title)) - results.append(("⛔", f"{title}: 无修复命令,已阻塞")) + (f"已修复: {output[:200]}", todo_id)) + results.append(("✅", f"{title}: 已修复")) + else: + retry_count += 1 + if retry_count >= max_retries: + # 重试用完,留到下次体检再重新发现 + conn.execute( + "UPDATE todos SET status='pending', retry_count=0, " + "note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?", + (f"已达最大重试({max_retries}次),留待下次", todo_id)) + results.append(("🔄", f"{title}: 重试耗尽,等下次体检")) + else: + conn.execute( + "UPDATE todos SET status='pending', retry_count=?, " + "note=?, updated_at=CURRENT_TIMESTAMP WHERE id=?", + (retry_count, f"第{retry_count}次失败: {output[:100]}", todo_id)) + results.append(("🔄", f"{title}: 重试{retry_count}/{max_retries}")) conn.commit() conn.close() - - # 记录新报告过的blocked ID - try: - REPORTED_BLOCKED_PATH.parent.mkdir(parents=True, exist_ok=True) - reported = json.loads(REPORTED_BLOCKED_PATH.read_text()) if REPORTED_BLOCKED_PATH.exists() else [] - # 过滤出尚未报告过的blocked项 - unreported_blocked = [(tid, t) for tid, t in newly_blocked if tid not in reported] - if unreported_blocked: - # 有未报告的阻塞项 → 输出直通知微 - print() - print("⛔ 需知微处理(已阻塞,无自动修复方案):") - for tid, t in unreported_blocked: - print(f" #{tid} {t[:70]}") - # 标记已报告 - reported.extend([tid for tid, _ in unreported_blocked]) - REPORTED_BLOCKED_PATH.write_text(json.dumps(reported[-200:], ensure_ascii=False)) - except: - pass elapsed = time.time() - start if results: print(f"自愈执行器 | {datetime.now().strftime('%H:%M')} | {len(results)}条 ({elapsed:.0f}s)") for icon, msg in results: print(f" {icon} {msg}") - else: - print("[SILENT] 无待处理TODO") if __name__ == "__main__":