This is an automated email from the ASF dual-hosted git repository.

akm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new 1c71cc0  Updating monitoring
1c71cc0 is described below

commit 1c71cc05a24e2f5e27f0dcad1e53a1500dbed91c
Author: Andrew Musselman <[email protected]>
AuthorDate: Thu Apr 2 15:04:11 2026 -0700

    Updating monitoring
---
 repos/apache/github-workflows/monitor-agent.sh | 122 +++++++++++++++++++------
 1 file changed, 96 insertions(+), 26 deletions(-)

diff --git a/repos/apache/github-workflows/monitor-agent.sh 
b/repos/apache/github-workflows/monitor-agent.sh
index bbca666..4f08305 100755
--- a/repos/apache/github-workflows/monitor-agent.sh
+++ b/repos/apache/github-workflows/monitor-agent.sh
@@ -1,39 +1,53 @@
 #!/bin/bash
-# monitor-agent.sh — tmux dashboard for CI analyzer agent progress
+# monitor-agent.sh — tmux dashboard for CI analyzer agents
+# Monitors: Publishing Analyzer, Security Scanner, Report Combiner
 # Usage: chmod +x monitor-agent.sh && ./monitor-agent.sh
 
 COUCH_URL="http://user:password@localhost:5984";
 DB="agent_data_store"
 SESSION="ci-monitor"
+OWNER="apache"
 
 # Kill existing session if any
 tmux kill-session -t "$SESSION" 2>/dev/null
 
-tmux new-session -d -s "$SESSION" -x 220 -y 50
+tmux new-session -d -s "$SESSION" -x 220 -y 60
 
-# ── Pane 0 (top-left): Namespace doc counts ──
-tmux send-keys "watch -n 5 'echo \"=== Doc Counts ===\"; echo; \
+# ── Pane 0 (top-left): All namespace doc counts grouped by agent ──
+tmux send-keys "watch -n 5 'echo \"=== Doc Counts (all agents) ===\"; echo; \
 curl -s \"${COUCH_URL}/${DB}/_find\" \
   -H \"Content-Type: application/json\" \
-  -d 
\"{\\\"selector\\\":{\\\"namespace\\\":{\\\"\\\$in\\\":[\\\"ci-classification:apache\\\",\\\"ci-workflows:apache\\\",\\\"ci-report:apache\\\"]}},\\\"fields\\\":[\\\"namespace\\\"],\\\"limit\\\":9999}\"
 \
+  -d 
\"{\\\"selector\\\":{\\\"namespace\\\":{\\\"\\\$in\\\":[\\\"ci-classification:${OWNER}\\\",\\\"ci-workflows:${OWNER}\\\",\\\"ci-report:${OWNER}\\\",\\\"ci-security:${OWNER}\\\",\\\"ci-combined:${OWNER}\\\"]}},\\\"fields\\\":[\\\"namespace\\\"],\\\"limit\\\":9999}\"
 \
 | python3 -c \"
 import sys, json
 from collections import Counter
 docs = json.load(sys.stdin)[\\\"docs\\\"]
 counts = Counter(d[\\\"namespace\\\"] for d in docs)
 print(f\\\"Total: {len(docs)} docs\\\")
-for ns, count in sorted(counts.items()):
-    print(f\\\"  {count}\\t{ns}\\\")
+print()
+groups = {
+    \\\"Agent 1 (Publishing)\\\": [\\\"ci-classification:${OWNER}\\\", 
\\\"ci-workflows:${OWNER}\\\", \\\"ci-report:${OWNER}\\\"],
+    \\\"Agent 2 (Security)\\\": [\\\"ci-security:${OWNER}\\\"],
+    \\\"Agent 3 (Combined)\\\": [\\\"ci-combined:${OWNER}\\\"],
+}
+for label, namespaces in groups.items():
+    group_total = sum(counts.get(ns, 0) for ns in namespaces)
+    print(f\\\"{label}: {group_total} docs\\\")
+    for ns in namespaces:
+        c = counts.get(ns, 0)
+        short = ns.split(\\\":\\\")[0]
+        print(f\\\"  {c}\\t{short}\\\")
+    print()
 if not docs:
-    print(\\\"  (empty)\\\")
+    print(\\\"  (all empty)\\\")
 \"'" C-m
 
-# ── Pane 1 (top-right): Completed repos + in-progress ──
+# ── Pane 1 (top-right): Completed repos + classification status ──
 tmux split-window -h
-tmux send-keys "watch -n 10 'echo \"=== Repo Status ===\"; echo; \
+tmux send-keys "watch -n 10 'echo \"=== Agent 1: Repo Status ===\"; echo; \
 curl -s \"${COUCH_URL}/${DB}/_find\" \
   -H \"Content-Type: application/json\" \
-  -d 
\"{\\\"selector\\\":{\\\"namespace\\\":\\\"ci-classification:apache\\\",\\\"key\\\":{\\\"\\\$regex\\\":\\\"^__meta__:\\\"}},\\\"fields\\\":[\\\"key\\\",\\\"value\\\"],\\\"limit\\\":9999}\"
 \
+  -d 
\"{\\\"selector\\\":{\\\"namespace\\\":\\\"ci-classification:${OWNER}\\\",\\\"key\\\":{\\\"\\\$regex\\\":\\\"^__meta__:\\\"}},\\\"fields\\\":[\\\"key\\\",\\\"value\\\"],\\\"limit\\\":9999}\"
 \
 | python3 -c \"
 import sys, json
 docs = json.load(sys.stdin)[\\\"docs\\\"]
@@ -48,45 +62,40 @@ for d in sorted(with_wf, key=lambda x: x[\\\"key\\\"]):
     print(f\\\"  ✓ {repo}: {len(wfs)} workflows\\\")
 \"'" C-m
 
-# ── Pane 2 (bottom): In-progress repo + latest classified files ──
+# ── Pane 2 (middle-left): In-progress classification ──
 tmux select-pane -t 0
 tmux split-window -v
-tmux send-keys "watch -n 5 'echo \"=== In-Progress Workflows ===\"; echo; \
+tmux send-keys "watch -n 5 'echo \"=== Agent 1: In-Progress ===\"; echo; \
 curl -s \"${COUCH_URL}/${DB}/_find\" \
   -H \"Content-Type: application/json\" \
-  -d 
\"{\\\"selector\\\":{\\\"namespace\\\":\\\"ci-classification:apache\\\",\\\"key\\\":{\\\"\\\$not\\\":{\\\"\\\$regex\\\":\\\"^__meta__:\\\"}}},\\\"fields\\\":[\\\"key\\\",\\\"updatedAt\\\"],\\\"limit\\\":9999}\"
 \
+  -d 
\"{\\\"selector\\\":{\\\"namespace\\\":\\\"ci-classification:${OWNER}\\\",\\\"key\\\":{\\\"\\\$not\\\":{\\\"\\\$regex\\\":\\\"^__meta__:\\\"}}},\\\"fields\\\":[\\\"key\\\"],\\\"limit\\\":9999}\"
 \
 | python3 -c \"
-import sys, json
+import sys, json, subprocess
 docs = json.load(sys.stdin)[\\\"docs\\\"]
 
-# Get completed repos
-import subprocess
 meta_raw = subprocess.run(
     [\\\"curl\\\", \\\"-s\\\", \\\"${COUCH_URL}/${DB}/_find\\\",
      \\\"-H\\\", \\\"Content-Type: application/json\\\",
-     \\\"-d\\\", json.dumps({\\\"selector\\\": {\\\"namespace\\\": 
\\\"ci-classification:apache\\\", \\\"key\\\": {\\\"\\\$regex\\\": 
\\\"^__meta__:\\\"}}, \\\"fields\\\": [\\\"key\\\", \\\"value\\\"], 
\\\"limit\\\": 9999})],
+     \\\"-d\\\", json.dumps({\\\"selector\\\": {\\\"namespace\\\": 
\\\"ci-classification:${OWNER}\\\", \\\"key\\\": {\\\"\\\$regex\\\": 
\\\"^__meta__:\\\"}}, \\\"fields\\\": [\\\"key\\\", \\\"value\\\"], 
\\\"limit\\\": 9999})],
     capture_output=True, text=True
 ).stdout
 meta_docs = json.loads(meta_raw)[\\\"docs\\\"]
 complete_repos = {d[\\\"key\\\"].replace(\\\"__meta__:\\\", \\\"\\\") for d in 
meta_docs if d.get(\\\"value\\\", {}).get(\\\"complete\\\")}
 
-# Group classification docs by repo
 by_repo = {}
 for d in docs:
     key = d[\\\"key\\\"]
     repo = key.split(\\\":\\\")[0] if \\\":\\\" in key else \\\"unknown\\\"
     by_repo.setdefault(repo, []).append(key)
 
-# Find in-progress repos (have classification docs but no __meta__ complete)
 in_progress = {r: files for r, files in by_repo.items() if r not in 
complete_repos}
 
 if not in_progress:
-    print(\\\"No repos currently being processed.\\\")
+    print(\\\"No repos currently being classified.\\\")
     print(f\\\"\\\\nTotal classified: {len(docs)} workflows across 
{len(by_repo)} repos\\\")
 else:
     for repo, files in sorted(in_progress.items()):
         print(f\\\"⏳ {repo}: {len(files)} classified so far\\\")
-        # Show last 15 files
         recent = sorted(files)[-15:]
         for f in recent:
             wf_name = f.split(\\\":\\\", 1)[1] if \\\":\\\" in f else f
@@ -96,11 +105,72 @@ else:
     print(f\\\"\\\\nTotal classified: {len(docs)} workflows\\\")
 \"'" C-m
 
-# ── Pane 3 (bottom-right): Docker logs tail ──
-tmux select-pane -t 3
+# ── Pane 3 (middle-right): Agent 2 security findings summary ──
+tmux select-pane -t 1
+tmux split-window -v
+tmux send-keys "watch -n 5 'echo \"=== Agent 2: Security Findings ===\"; echo; 
\
+curl -s \"${COUCH_URL}/${DB}/_find\" \
+  -H \"Content-Type: application/json\" \
+  -d 
\"{\\\"selector\\\":{\\\"namespace\\\":\\\"ci-security:${OWNER}\\\"},\\\"fields\\\":[\\\"key\\\",\\\"value\\\"],\\\"limit\\\":9999}\"
 \
+| python3 -c \"
+import sys, json
+docs = json.load(sys.stdin)[\\\"docs\\\"]
+
+if not docs:
+    print(\\\"No security data yet.\\\")
+    print(\\\"Run Agent 2 after Agent 1 completes.\\\")
+else:
+    finding_docs = [d for d in docs if 
d[\\\"key\\\"].startswith(\\\"findings:\\\")]
+    meta_docs = [d for d in docs if d[\\\"key\\\"].startswith(\\\"latest_\\\")]
+    
+    repos_with_findings = 0
+    repos_clean = 0
+    total_findings = 0
+    severity_counts = {}
+    check_counts = {}
+    
+    for d in finding_docs:
+        findings = d.get(\\\"value\\\", [])
+        if isinstance(findings, list):
+            if findings:
+                repos_with_findings += 1
+                total_findings += len(findings)
+            else:
+                repos_clean += 1
+            for f in findings:
+                if isinstance(f, dict):
+                    sev = f.get(\\\"severity\\\", \\\"?\\\")
+                    severity_counts[sev] = severity_counts.get(sev, 0) + 1
+                    chk = f.get(\\\"check\\\", \\\"?\\\")
+                    check_counts[chk] = check_counts.get(chk, 0) + 1
+    
+    print(f\\\"Repos processed: {len(finding_docs)} ({repos_with_findings} 
with findings, {repos_clean} clean)\\\")
+    print(f\\\"Total findings: {total_findings}\\\")
+    print()
+    
+    if severity_counts:
+        print(\\\"By severity:\\\")
+        for sev in [\\\"CRITICAL\\\", \\\"HIGH\\\", \\\"MEDIUM\\\", 
\\\"LOW\\\", \\\"INFO\\\"]:
+            c = severity_counts.get(sev, 0)
+            if c > 0:
+                print(f\\\"  {sev}: {c}\\\")
+        print()
+    
+    if check_counts:
+        print(\\\"By check:\\\")
+        for chk, c in sorted(check_counts.items(), key=lambda x: -x[1])[:10]:
+            print(f\\\"  {c}\\t{chk}\\\")
+    
+    if meta_docs:
+        print()
+        print(\\\"Reports: \\\", \\\", \\\".join(d[\\\"key\\\"] for d in 
meta_docs))
+\"'" C-m
+
+# ── Pane 4 (bottom): Docker logs tail ──
+tmux select-pane -t 2
 tmux split-window -v
-tmux send-keys "docker compose logs -f api 2>&1 | grep -E 
'(Scanning|Progress|Rate limit|WARNING|ERROR|Scan 
complete|classified|cached|Preflight|DEBUG|call_llm)'" C-m
+tmux send-keys "docker compose logs -f --tail=100 api 2>&1 | grep 
--line-buffered -E '(Scanning|Progress|Rate limit|WARNING|ERROR|Scan 
complete|classified|cached|Preflight|Security 
scan|findings|composite|call_llm)'" C-m
 
 # Layout and attach
 tmux select-layout -t "$SESSION" tiled
-tmux attach -t "$SESSION"
+tmux attach -t "$SESSION"
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to