diff --git a/routes/openclaw_bot_routes.py b/routes/openclaw_bot_routes.py index 846da9b..0c614e2 100644 --- a/routes/openclaw_bot_routes.py +++ b/routes/openclaw_bot_routes.py @@ -5897,6 +5897,31 @@ def telegram_webhook(): return jsonify({'ok': True}) +# ── 內部 CMD 轉發端點(供 momo-telegram-bot 轉發 cmd:* 按鈕用)──────── +@openclaw_bot_bp.route('/bot/internal/cmd', methods=['POST']) +def internal_cmd(): + """接受 momo-telegram-bot 轉發的 cmd:* 按鈕指令並執行""" + try: + token = request.headers.get('X-Internal-Token', '') + if not verify_internal_token(token): + return jsonify({'ok': False, 'error': 'Unauthorized'}), 401 + body = request.get_json(silent=True) or {} + chat_id = body.get('chat_id') + cmd = body.get('cmd', '').strip() + arg = body.get('arg', '').strip() + if not chat_id or not cmd: + return jsonify({'ok': False, 'error': 'missing chat_id or cmd'}), 400 + threading.Thread( + target=handle_cmd, + args=(cmd, arg, int(chat_id), None), + daemon=True, + ).start() + return jsonify({'ok': True}) + except Exception as e: + sys_log.error(f"[OpenClawBot] /bot/internal/cmd error: {e}", exc_info=True) + return jsonify({'ok': False, 'error': str(e)}), 500 + + # ── 管理端點 ────────────────────────────────────────────────── @openclaw_bot_bp.route('/bot/telegram/set_webhook', methods=['POST']) def set_webhook(): diff --git a/services/code_review_pipeline_service.py b/services/code_review_pipeline_service.py index 4fb37bb..234f3f0 100644 --- a/services/code_review_pipeline_service.py +++ b/services/code_review_pipeline_service.py @@ -611,6 +611,8 @@ def get_history(limit: int = 20) -> List[Dict]: "severity_summary": sev, "total_issues": sum(sev.values()), "auto_fix": meta.get("auto_fix_triggered", False), + "findings": content.get("findings", []), + "openclaw_report": content.get("openclaw_report", ""), "ea_decision": content.get("ea_decision", {}), "created_at": r[4].isoformat() if r[4] else "", "status": r[5] or "active", diff --git a/services/telegram_bot_service.py b/services/telegram_bot_service.py index ffb3de3..477f325 100644 --- a/services/telegram_bot_service.py +++ b/services/telegram_bot_service.py @@ -488,6 +488,34 @@ class TrendTelegramBot: elif data.startswith("momo:ops:"): await self._handle_ops_callback(query, data) + # ===== OpenClaw 指令按鈕(cmd::)===== + elif data.startswith("cmd:"): + parts = data[4:].split(":", 1) + cmd = parts[0] + arg = parts[1] if len(parts) > 1 else "" + chat_id = query.message.chat_id + import threading as _t + _t.Thread( + target=self._forward_cmd_to_openclaw, + args=(cmd, arg, chat_id), + daemon=True, + ).start() + + def _forward_cmd_to_openclaw(self, cmd: str, arg: str, chat_id: int): + """轉發 cmd:* 指令到 OpenClaw Flask 內部 API""" + import requests as _req + try: + internal_url = os.getenv("OPENCLAW_INTERNAL_URL", "http://momo-pro-system:80") + token = os.getenv("INTERNAL_WEBHOOK_TOKEN", "") + _req.post( + f"{internal_url}/bot/internal/cmd", + json={"chat_id": chat_id, "cmd": cmd, "arg": arg}, + headers={"X-Internal-Token": token}, + timeout=10, + ) + except Exception as e: + logger.warning(f"[TelegramBot] forward cmd failed: {e}") + async def _handle_main_menu_callback(self, query, data: str): """處理主選單回調 - 完整功能菜單系統""" key = data[5:] # 移除 'menu:' 前綴 diff --git a/templates/code_review.html b/templates/code_review.html index 6bbef3a..68bf6fd 100644 --- a/templates/code_review.html +++ b/templates/code_review.html @@ -367,12 +367,15 @@ function renderStatusBar(state) { } // ── History ─────────────────────────────────────────────────────── +let _historyData = []; + function renderHistory(items) { + _historyData = items; const el = document.getElementById('historyList'); if (!items.length) { el.innerHTML = '
尚無歷史記錄
'; return; } - el.innerHTML = items.map(h => { + el.innerHTML = items.map((h, idx) => { const sev = h.severity_summary || {}; - return `
+ return `
${h.commit_sha} ${h.created_at.slice(0,16).replace('T',' ')} @@ -389,6 +392,34 @@ function renderHistory(items) { }).join(''); } +function loadHistoryItem(idx) { + const h = _historyData[idx]; + if (!h) return; + document.querySelectorAll('.hist-item').forEach((el, i) => { + el.style.borderColor = i === idx ? 'var(--blue)' : ''; + }); + renderSeverity(h.severity_summary); + const files = (h.changed_files||[]).slice(0,5).map(f=>`${f.split('/').pop()}`).join(' '); + const more = (h.changed_files||[]).length > 5 ? `+${h.changed_files.length-5}` : ''; + document.getElementById('commitInfo').innerHTML = ` +
Commit ${h.commit_sha}
+
Branch ${h.branch||'?'}
+
時間 ${h.created_at.slice(0,16).replace('T',' ')}
+
變更 ${files} ${more}
`; + document.getElementById('pipelineId').textContent = (h.pipeline_id||'').slice(-14); + const sBar = document.getElementById('statusBar'); + sBar.style.display = 'block'; + sBar.className = 'completed'; + sBar.innerHTML = `✅ 歷史記錄 — Commit ${h.commit_sha}${h.auto_fix ? ' 🔧 已自動修復' : ''}`; + renderFindings(h.findings || []); + renderOpenClaw(h.openclaw_report || ''); + renderEA(h.ea_decision || {}, h.auto_fix || false); + for (let i = 1; i <= 5; i++) { + const el = document.getElementById('step-' + i); + if (el) { el.className = 'step ok'; el.querySelector('.step-num').textContent = '✓'; } + } +} + // ── Main polling loop ───────────────────────────────────────────── async function poll() { try { @@ -408,6 +439,11 @@ async function poll() { renderCommitInfo(state); document.getElementById('pipelineId').textContent = (state.pipeline_id||'').slice(-14); + // 無 active pipeline 時,自動顯示最新歷史記錄 + if (!state.status && _historyData.length && !_lastPipelineId) { + loadHistoryItem(0); + } + // 每 3s 輪詢(running)/ 30s(idle) const interval = state.status === 'running' ? 3000 : 30000; _polling = setTimeout(poll, interval);