From 31b0bfaac13004ddc5f868a1550166b93db31a25 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 17 May 2026 09:23:13 +0200 Subject: [PATCH] feat(diagnostic): ARIA-Live (read-only Terminal-Mirror) + Not-Aus statt SSH-Tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SSH-Tab raus — funktionierte eh nicht zuverlaessig und war konzeptionell falsch. Stattdessen Live-Mirror der Claude-Code-Session: - proxy-patches/routes.js: assistant + user Events parsed → POSTed Tool- Inputs (truncated 2 KB) + Tool-Results (truncated 4 KB) + Assistant-Text an aria-bridge:8090/internal/agent-stream. start/end Marker pro Session. Subprocess-Tracking (_activeSubprocesses Map) + interner Side-Channel auf Port 3457 mit POST /cancel-all fuer Hard-Kill. - bridge: neuer /internal/agent-stream Endpoint pusht 1:1 als RVS agent_stream. cancel_request Handler nimmt optional 'hard'-Flag — triggert dann zusaetzlich _cancel_proxy_subprocesses() das den Proxy- Side-Channel ruft. - rvs: agent_stream whitelisted. - diagnostic: SSH-Tab → 'ARIA Live'. Monospace-Stream, farbcodiert (text=hell, tool_use=cyan, tool_result=gruen/rot, thinking=gelb-italic), Auto-Scroll, max 2000 Zeilen Backlog. Roter ⛔ Not-Aus-Button mit Confirm → aria_panic_stop action → diagnostic-server broadcastet cancel_request mit hard:true. Co-Authored-By: Claude Opus 4.7 (1M context) --- bridge/aria_bridge.py | 46 +++++++- diagnostic/index.html | 233 ++++++++++++++++++++++++---------------- diagnostic/server.js | 17 +++ proxy-patches/routes.js | 171 ++++++++++++++++++++++++++--- rvs/server.js | 1 + 5 files changed, 360 insertions(+), 108 deletions(-) diff --git a/bridge/aria_bridge.py b/bridge/aria_bridge.py index e08833b..68b4edd 100644 --- a/bridge/aria_bridge.py +++ b/bridge/aria_bridge.py @@ -1677,8 +1677,14 @@ class ARIABridge: return if msg_type == "cancel_request": - logger.info("[rvs] Cancel-Request von App — rufe Diagnostic /api/cancel auf") - await self._cancel_via_diagnostic() + hard = bool(payload.get("hard")) + if hard: + logger.warning("[rvs] NOT-AUS — hard cancel: Diagnostic /api/cancel + Proxy /cancel-all") + await self._cancel_via_diagnostic() + await self._cancel_proxy_subprocesses() + else: + logger.info("[rvs] Cancel-Request von App — rufe Diagnostic /api/cancel auf") + await self._cancel_via_diagnostic() await self._emit_activity("idle", "") return @@ -2709,6 +2715,24 @@ class ARIABridge: status = await asyncio.get_event_loop().run_in_executor(None, _do_request) logger.info("[cancel] Diagnostic /api/cancel: %s", status) + async def _cancel_proxy_subprocesses(self) -> None: + """Not-Aus: ruft den proxy-internen /cancel-all Side-Channel auf + (siehe proxy-patches/routes.js). Killt alle aktiven Claude-Code- + Subprocesses sofort. Bridge ist auf aria-net, Proxy auch — also + per Container-Name + Side-Channel-Port (Default 3457) erreichbar.""" + url = os.environ.get("PROXY_INTERNAL_URL", "http://aria-proxy:3457") + "/cancel-all" + + def _do_request(): + try: + req = urllib.request.Request(url, method="POST", data=b"") + with urllib.request.urlopen(req, timeout=3) as resp: + return resp.status, resp.read().decode("utf-8", "ignore")[:200] + except Exception as e: + return f"error: {e}", "" + + status, body = await asyncio.get_event_loop().run_in_executor(None, _do_request) + logger.warning("[NOT-AUS] proxy /cancel-all: %s %s", status, body) + async def _emit_activity(self, activity: str, tool: str = "", force: bool = False) -> None: """Sendet agent_activity an die App — nur wenn sich der State geaendert hat. @@ -2890,6 +2914,24 @@ class ARIABridge: # selbst wenn derselbe Name zweimal in Folge kommt. asyncio.create_task(self._emit_activity("tool", tool, force=True)) await _send_response(writer, 200, {"ok": True}) + elif method == "POST" and path == "/internal/agent-stream": + # Vom Proxy gefeuert: voller Live-Stream der Claude-Code- + # Session (assistant_text, tool_use mit Input, tool_result + # mit truncated Output, start/end Markers). Wir leiten 1:1 + # als RVS agent_stream an Diagnostic (ARIA-Live-View) und + # App weiter — read-only Mirror der gerade laufenden + # ARIA-Aktivitaet. + try: + data = json.loads(body.decode("utf-8", "ignore")) + except Exception as exc: + await _send_response(writer, 400, {"error": f"bad json: {exc}"}) + return + asyncio.create_task(self._send_to_rvs({ + "type": "agent_stream", + "payload": data, + "timestamp": int(time.time() * 1000), + })) + await _send_response(writer, 200, {"ok": True}) elif method == "POST" and path == "/internal/flux-generate": # Vom Brain (flux_generate-Tool) gefeuert. Wir routen den # Render-Request via RVS an die flux-bridge (Gamebox), diff --git a/diagnostic/index.html b/diagnostic/index.html index 29580c5..201558d 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -395,18 +395,29 @@
- +
- -
-
- - Nicht verbunden + +
+
+ Idle — warte auf ARIA-Aktivitaet + + + +
+
+
Sobald ARIA denkt oder ein Tool nutzt, taucht es hier in Echtzeit auf.
-