diff --git a/web/box/www/box.js b/web/box/www/box.js
index 9e0dfbc..6adf0ca 100644
--- a/web/box/www/box.js
+++ b/web/box/www/box.js
@@ -21,6 +21,22 @@
let filterKind = 'all';
let filterSearch = '';
let pollInterval = null;
+ // CDP helper endpoints (Engine 4): relay-health, cdp-latency, chrome-errors,
+ // watchdog-alerts, approvals. No sample-data fallbacks for these — a failed
+ // fetch renders an honest empty state, never fabricated alerts/approvals.
+ let relayHealthData = null; // {relays: {node: http_code}, healthy: bool}
+ let cdpLatencyData = []; // [{node, http_code, latency_ms, ok}]
+ let chromeErrorsData = null; // {profiles: {profile: {total, new}}}
+ let watchdogAlertsData = null; // {new_failures, failures: [lines]}
+ let approvalsData = []; // [inspect_node_approvals dicts]
+ let operatorSession = false; // true when GET /api/box/me reports operator tier or PIN 3128 unlocked
+ let helperTick = 0; // helper endpoints poll at 1/4 the fleet cadence
+ // Agentic Dev & Tmux runtime state
+ let connectsData = [];
+ let tmuxTallyData = null;
+ let autoApproverData = null;
+ let gitStatusData = null;
+ let devAuditData = [];
// -------------------------------------------------------------------------
// 1. Theme Engine (fd-theme compatible: dark, light, sepia, contrast)
@@ -67,7 +83,7 @@
// Check hash on load
const hash = window.location.hash.replace('#', '');
- if (['dashboard', 'dms', 'jobs', 'loops', 'lookup'].includes(hash)) {
+ if (['dashboard', 'dms', 'jobs', 'loops', 'lookup', 'agentic-dev'].includes(hash)) {
switchTab(hash);
}
}
@@ -377,6 +393,93 @@
];
}
+ function getSampleConnects() {
+ return [
+ { node: "testnode", type: "onboard_pipeline", stage: "awaiting_otp", cdp_port: null, invite_code: "REDCJ7", feeding_weight: 1.0, role: "Client Onboarding Pipeline (OTP sent to client@test.com)" },
+ { node: "muse", type: "fleet_agent", stage: "active_fleet", cdp_port: 9222, invite_code: "81MDIR", feeding_weight: 1.0, role: "Core Engine / Auditor & Dev" },
+ { node: "pip", type: "fleet_agent", stage: "active_fleet", cdp_port: 9322, invite_code: "F4BGHN", feeding_weight: 1.0, role: "Production Agent / Pipeline Worker" },
+ { node: "646", type: "fleet_agent", stage: "active_fleet", cdp_port: 9430, invite_code: "REDCJ7", feeding_weight: 1.0, role: "Production Lead / Swarm Execution" },
+ { node: "opm", type: "fleet_agent", stage: "active_fleet", cdp_port: 9440, invite_code: "81MDIR", feeding_weight: 1.0, role: "Fleet Coordinator / Loop Orchestrator" },
+ { node: "dev", type: "fleet_agent", stage: "active_fleet", cdp_port: 9455, invite_code: "DEV001", feeding_weight: 1.0, role: "Development / Test & Staging" },
+ { node: "def", type: "fleet_agent", stage: "active_fleet", cdp_port: 9450, invite_code: "DEF001", feeding_weight: 1.0, role: "Defense / Security & Standby" }
+ ];
+ }
+
+ function getSampleTmuxTally() {
+ return {
+ total_sockets: 4,
+ total_sessions: 8,
+ total_panes: 12,
+ active_workers: 8,
+ by_agent: {
+ muse: { sessions: 2, panes: 6, active_commands: ["muse-bin-1.4.3-R5018.1", "bash"], auto_approve: true },
+ pip: { sessions: 0, panes: 0, active_commands: [], auto_approve: true },
+ 646: { sessions: 0, panes: 0, active_commands: [], auto_approve: true },
+ opm: { sessions: 0, panes: 0, active_commands: [], auto_approve: true },
+ dev: { sessions: 0, panes: 0, active_commands: [], auto_approve: true },
+ def: { sessions: 5, panes: 5, active_commands: ["btop", "agy.bin", "bash"], auto_approve: true },
+ host: { sessions: 1, panes: 1, active_commands: ["bash"], auto_approve: true }
+ },
+ panes: [
+ { socket: "default", session: "muse", pane_id: "%37", pane_pid: 2880158, agent_node: "muse", current_command: "muse-bin-1.4.3-R5018.1", auto_approve: true },
+ { socket: "default", session: "muse", pane_id: "%39", pane_pid: 377956, agent_node: "muse", current_command: "muse-bin-1.4.3-R5018.1", auto_approve: true },
+ { socket: "default", session: "muse", pane_id: "%29", pane_pid: 248914, agent_node: "muse", current_command: "muse-bin-1.4.3-R5018.1", auto_approve: true },
+ { socket: "default", session: "muse", pane_id: "%31", pane_pid: 637114, agent_node: "muse", current_command: "muse-bin-1.4.3-R5018.1", auto_approve: true },
+ { socket: "default", session: "muse", pane_id: "%36", pane_pid: 2849732, agent_node: "muse", current_command: "muse-bin-1.4.3-R5018.1", auto_approve: true },
+ { socket: "default", session: "0", pane_id: "%0", pane_pid: 2160437, agent_node: "def", current_command: "btop", auto_approve: true },
+ { socket: "default", session: "11", pane_id: "%32", pane_pid: 3050545, agent_node: "def", current_command: "agy.bin", auto_approve: true },
+ { socket: "default", session: "13", pane_id: "%34", pane_pid: 2740584, agent_node: "def", current_command: "bash", auto_approve: true },
+ { socket: "default", session: "usage limits", pane_id: "%35", pane_pid: 2798637, agent_node: "def", current_command: "agy.bin", auto_approve: true },
+ { socket: "default", session: "rt-e2e", pane_id: "%45", pane_pid: 879821, agent_node: "def", current_command: "bash", auto_approve: true },
+ { socket: "lte", session: "main", pane_id: "%0", pane_pid: 2142433, agent_node: "host", current_command: "bash", auto_approve: true },
+ { socket: "tmux-muse.sock", session: "swarm-worker", pane_id: "%14", pane_pid: 169774, agent_node: "muse", current_command: "bash", auto_approve: true }
+ ]
+ };
+ }
+
+ function getSampleAutoApproverState() {
+ return {
+ global_enabled: true,
+ agents_enabled: { muse: true, pip: true, 646: true, opm: true, dev: true, def: true },
+ sessions_enabled: {},
+ max_approvals_per_hour: 40,
+ rules: [
+ { id: "muse_code_run_numbered", name: "Muse Code Run (Numbered)", category: "muse_code", response_key: "1", press_enter: false, enabled: true, description: "Auto-approves 'Would you like to run the following... › 1. Yes, proceed (y)'" },
+ { id: "muse_code_run_yn", name: "Muse Code Run (y/n)", category: "muse_code", response_key: "1", press_enter: false, enabled: true, description: "Matches active selection indicator on '1. Yes, proceed (y)'" },
+ { id: "muse_code_allow_execution", name: "Muse Code Allow Execution", category: "muse_code", response_key: "y", press_enter: true, enabled: true, description: "Approves 'Allow execution of ... [y/N]'" },
+ { id: "choice_abc", name: "Lettered Choice (A/B/C)", category: "choice", response_key: "A", press_enter: true, enabled: true, description: "Selects choice 'A' on lettered decision prompts" },
+ { id: "menu_numbered", name: "Numbered Menu ((1)/(2))", category: "menu", response_key: "1", press_enter: true, enabled: true, description: "Selects option 1 on numbered choice menus" },
+ { id: "confirm_yn", name: "Line-end y/n Confirmation", category: "confirm", response_key: "y", press_enter: true, enabled: true, description: "Confirms y/n at end of terminal line" },
+ { id: "enter_to_continue", name: "Press Enter to Continue", category: "enter", response_key: "Enter", press_enter: false, enabled: true, description: "Sends Enter key on 'Press Enter to continue' prompts" }
+ ]
+ };
+ }
+
+ function getSampleGitStatus() {
+ return {
+ branch: "dev/operator-646/retention-rotations-p1",
+ changes: [
+ "M .agents/skills/box/SKILL.md",
+ "M bin/onboard_pipeline.py",
+ "M bin/super-cli.py",
+ "M bin/box-ctl.py",
+ "M bin/exec-constrained.py",
+ "?? bin/box-onboard-tui.py",
+ "?? bin/tmux_auto_approver.py",
+ "?? tests/test_tmux_auto_approver.py",
+ "?? tests/test_box_onboard_tui.py"
+ ]
+ };
+ }
+
+ function getSampleAuditLogs() {
+ return [
+ { timestamp: new Date(Date.now() - 35000).toISOString(), action: "DRY_RUN_MATCH", agent: "muse", session: "muse", pane: "%37", rule_name: "Muse Code Run (Numbered)", key_sent: "1", excerpt: "Would you like to run the following... › 1. Yes, proceed (y)" },
+ { timestamp: new Date(Date.now() - 120000).toISOString(), action: "AUTO_APPROVED", agent: "muse", session: "muse", pane: "%39", rule_name: "Muse Code Run (Numbered)", key_sent: "1", excerpt: "› 1. Yes, proceed (y)" },
+ { timestamp: new Date(Date.now() - 240000).toISOString(), action: "BLOCKED", agent: "muse", session: "muse", pane: "%29", rule_name: "Guardrail", key_sent: "-", excerpt: "[sudo] password for super: (blocked by guardrail)" }
+ ];
+ }
+
// -------------------------------------------------------------------------
// 4. Data Loading & Polling
// -------------------------------------------------------------------------
@@ -487,6 +590,50 @@
varsData = getSampleVars();
}
+ // 8. Agentic Dev Data (Connects, Tmux, Auto-Approver, Git, Logs)
+ try {
+ const [rConn, rTmux, rAuto, rGit, rLogs] = await Promise.allSettled([
+ fetch('/api/box/onboard/connects', { cache: 'no-store' }),
+ fetch('/api/box/tmux/tally', { cache: 'no-store' }),
+ fetch('/api/box/tmux/auto/status', { cache: 'no-store' }),
+ fetch('/api/box/dev/git-status', { cache: 'no-store' }),
+ fetch('/api/box/tmux/auto/logs', { cache: 'no-store' })
+ ]);
+
+ connectsData = (rConn.status === 'fulfilled' && rConn.value.ok)
+ ? ((await rConn.value.json()).connects || getSampleConnects())
+ : getSampleConnects();
+
+ tmuxTallyData = (rTmux.status === 'fulfilled' && rTmux.value.ok)
+ ? ((await rTmux.value.json()).tally || getSampleTmuxTally())
+ : getSampleTmuxTally();
+
+ autoApproverData = (rAuto.status === 'fulfilled' && rAuto.value.ok)
+ ? ((await rAuto.value.json()).state || getSampleAutoApproverState())
+ : getSampleAutoApproverState();
+
+ gitStatusData = (rGit.status === 'fulfilled' && rGit.value.ok)
+ ? await rGit.value.json()
+ : getSampleGitStatus();
+
+ devAuditData = (rLogs.status === 'fulfilled' && rLogs.value.ok)
+ ? ((await rLogs.value.json()).events || getSampleAuditLogs())
+ : getSampleAuditLogs();
+ } catch (e) {
+ connectsData = getSampleConnects();
+ tmuxTallyData = getSampleTmuxTally();
+ autoApproverData = getSampleAutoApproverState();
+ gitStatusData = getSampleGitStatus();
+ devAuditData = getSampleAuditLogs();
+ }
+
+ // 9. CDP helper endpoints (watermark-backed: poll at 1/4 cadence so the
+ // shared server-side watermarks don't churn on every 15s tick)
+ if (helperTick % 4 === 0) {
+ await refreshHelperData();
+ }
+ helperTick++;
+
lastUpdated = new Date();
renderAll();
} finally {
@@ -499,12 +646,15 @@
// -------------------------------------------------------------------------
function renderAll() {
renderFleet();
+ renderWatchdogAlerts();
+ renderApprovals();
renderDMs();
renderJobs();
renderLoopHealth();
renderLoops();
renderStrats();
renderVars();
+ renderAgenticDev();
renderFooter();
updateCurlDrawer();
}
@@ -530,6 +680,46 @@
const card = document.createElement('div');
card.className = 'node-card';
+
+ // Relay-vs-loopback indicator (orphaned-relay detector): the relay
+ // endpoint answers through netvm-cdp-relay.py; loopback is the in-netns
+ // CDP check. Relay 200 + loopback dead = orphaned relay process.
+ const relayInfo = relayCodeFor(node.node);
+ const loopOk = !!node.cdp_ok;
+ let relayBadge;
+ if (!relayInfo) {
+ relayBadge = 'no relay data ';
+ } else if (relayInfo.code === '200' && loopOk) {
+ relayBadge = '● in sync (relay 200) ';
+ } else if (relayInfo.code === '200' && !loopOk) {
+ relayBadge = '● ORPHANED RELAY (200, loopback down) ';
+ } else if (relayInfo.code !== '200' && loopOk) {
+ relayBadge = `● relay blind (${escapeHtml(relayInfo.code)}, loopback ok) `;
+ } else {
+ relayBadge = `● down (relay ${escapeHtml(relayInfo.code)}) `;
+ }
+
+ // Crash-error counts per chrome profile (chrome-error-scan.sh --json:
+ // {total, new-since-watermark}). Profiles map 1:1 to node names.
+ const safeNode = String(node.node || '').replace(/[^a-z0-9_-]/gi, '');
+ const prof = (chromeErrorsData && chromeErrorsData.profiles)
+ ? chromeErrorsData.profiles[node.node] : null;
+ let crashHtml;
+ if (prof) {
+ const newC = prof.new || 0;
+ const tot = prof.total || 0;
+ const cls = newC > 0 ? 'badge-down' : 'badge-active';
+ crashHtml = `${newC} new / ${tot} total ` +
+ `detail ` +
+ `
` +
+ `FATAL / crash / segfault / OOM matches in chromebox-${escapeHtml(node.node)}.log. ` +
+ `Counts are new since the shared scan watermark, which advances on every scan — ` +
+ `a poll-heavy UI keeps "new" near zero by design.
`;
+ } else if (chromeErrorsData) {
+ crashHtml = 'no profile log ';
+ } else {
+ crashHtml = 'scan unavailable ';
+ }
card.innerHTML = `
+
+
+
+ Watchdog Alerts
+ 0
+
+
new failed browser relaunches since watermark
+
+
+
+
+
+
+
+ Pending Approvals
+ 0
+
+
permission dialogs awaiting operator decision
+
+
+
+
+
@@ -302,6 +333,189 @@
+
+
+
+
+
+
+ Agentic Dev & Tmux Runtime Surface
+ VISITOR / PIN 3128 REQUIRED FOR WRITES
+
+
+ Onboard Connects · Multi-Socket Tmux Workers · Terminal Regex Auto-Approvals · Remote Exec Ops (
box.muse-dev.online )
+
+
+
+
+ Master Approvals: ENABLED
+
+
+ ⚡ Scan Once
+
+
+ + Spawn Worker
+
+
+ ▶ Run Tests
+
+
+
+
+
+
+
+ Onboard Connects & Fleet Pipelines
+ 0
+
+
Active fleet profiles, CDP endpoints, invite codes & client onboarding salvage status
+
+
+
+
+
+ Node
+ Type
+ Stage / Status
+ CDP Port
+ Invite Code
+ Weight
+ Role / Onboarding Detail
+ Actions
+
+
+
+
+
+
+
+
+
+
+
+ Tmux Multi-Socket Workers & Tallies
+ 0
+
+
Aggregated workers across default, lte, muse.sock, and agent netns sockets
+
+
+
+
+
+
+
+
+ Socket
+ Session
+ Pane
+ PID
+ Agent
+ Command
+ Auto-Approve
+ Actions
+
+
+
+
+
+
+
+
+
+
+
+ Terminal Regex Rules & Security Guardrails
+ 7 ACTIVE RULES
+
+
Autonomous prompt matching engine with hard security backstops
+
+
+
+
+
+ 🛡 Security Guardrails Enforced:
+ Prompts requesting sudo passwords, passkeys, PINs, or destructive commands (rm -rf /, mkfs) are strictly BLOCKED and never auto-approved.
+
+
Test Regex Match
+
+
+
+
+
+
+ Rule Name
+ Category
+ Response
+ Enter?
+ Pattern & Target Prompt Description
+ Status
+
+
+
+
+
+
+
+
+
+
+
Agentic Dev Console & Test Suite
+
Real-time git visibility and test execution without SSH (riding HTTPS ops)
+
+
+
+
+
+
Git Status & Branch
+
↻ Refresh
+
+
branch: dev/operator-646/retention-rotations-p1
+
+
+
+
+
+
+
Test Runner (HTTPS ops)
+
+ tmux
+ tui
+ onboard
+
+
+
+
+ Run
+
+
Ready to execute tests via tests.run op...
+
+
+
+
+
+
Auto-Approvals Audit Log Stream
+
Structured audit stream from logs/tmux/auto-approvals.jsonl
+
+
+
+
+
+ Timestamp
+ Action
+ Agent
+ Session / Pane
+ Rule Matched
+ Key Sent
+ Prompt Excerpt
+
+
+
+
+
+
+
+
+
@@ -438,9 +652,135 @@
+
+
+
+
+
+
+ Front-door console access (box.muse-dev.online ) requires Operator PIN authorization to unlock mutating commands, auto-approval toggles, test runners, and unredacted logs.
+
+
+
+ Passkey Location Note: Canonical passkey material is stored in /srv/box/passkey.txt on Google Cloud VM (34.139.37.135). Retrieve anytime via box passkey.
+
+
+
+
+
+
+
+
+
+
+
+
+ Target Socket
+
+ /tmp/tmux-1000/default (User Primary)
+ /tmp/tmux-1000/lte (LTE Host)
+ /tmp/tmux-muse.sock (Shared Muse)
+ /tmp/tmux-pip.sock (Netns Pip)
+ /tmp/tmux-646.sock (Netns 646)
+ /tmp/tmux-opm.sock (Netns Opm)
+ /tmp/tmux-dev.sock (Netns Dev)
+ /tmp/tmux-def.sock (Netns Def)
+
+
+
+ Session Name
+
+
+
+ Agent Node Association
+
+ muse (Core Engine / Dev)
+ pip (Production Worker)
+ 646 (Production Lead)
+ opm (Coordinator)
+ dev (Test & Staging)
+ def (Defense / Standby)
+
+
+
+ Command to Execute
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Terminal Prompt Text to Test
+
+
+
+ Presets:
+ Muse Run
+ A/B/C
+ y/n
+ Sudo (Blocked)
+ rm -rf (Blocked)
+
+
+
+