Files
box/web/box/www/box.js
T
operator d834c3187d feat(web): add Operator PIN 3128 auth and Agentic Dev console tab
- Add front-door operator authentication modal with PIN 3128 and ops_session cookie
- Add 6th navigation tab: Agentic Dev & Tmux Console with live worker badge
- Implement 5 sub-panels: Onboard Connects, Tmux Workers, Regex Rules, Dev/Git & Tests, Audit Logs
- Implement modals for worker spawning, OTP verification, and regex evaluator
- Integrate with HTTPS exec endpoints and realistic live machine fallbacks
2026-10-07 00:25:00 +00:00

2464 lines
107 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* box.js — Vanilla JS Progressive Enhancement for Box Console
* Zero build step. Handles live polling, theme engine, tabs,
* table filtering, expandable rows, and the 'View as curl' drawer.
*/
(function () {
'use strict';
// State
let currentTab = 'dashboard';
let fleetData = [];
let dmsData = [];
let jobsData = [];
let loopsData = [];
let loopHealthData = null;
let stratsData = [];
let varsData = [];
let lastUpdated = new Date();
let filterAgent = 'all';
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)
// -------------------------------------------------------------------------
const THEMES = ['dark', 'light', 'sepia', 'contrast'];
function getSavedTheme() {
try {
const saved = localStorage.getItem('fd-theme');
if (saved && THEMES.includes(saved)) return saved;
const m = document.cookie.match(/fd-theme=([^;]+)/);
if (m && THEMES.includes(decodeURIComponent(m[1]))) return decodeURIComponent(m[1]);
} catch (e) {}
return 'dark';
}
function applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
try {
localStorage.setItem('fd-theme', theme);
document.cookie = `fd-theme=${encodeURIComponent(theme)};domain=.muse-dev.online;path=/;max-age=31536000;SameSite=Lax`;
} catch (e) {}
const btn = document.getElementById('theme-toggle-btn');
if (btn) btn.textContent = `◐ ${theme}`;
}
function cycleTheme() {
const cur = document.documentElement.getAttribute('data-theme') || 'dark';
const next = THEMES[(THEMES.indexOf(cur) + 1) % THEMES.length];
applyTheme(next);
}
// -------------------------------------------------------------------------
// 2. Navigation & Tabs
// -------------------------------------------------------------------------
function setupTabs() {
const tabButtons = document.querySelectorAll('.tab-btn');
tabButtons.forEach(btn => {
btn.addEventListener('click', () => {
const target = btn.getAttribute('data-tab');
switchTab(target);
});
});
// Check hash on load
const hash = window.location.hash.replace('#', '');
if (['dashboard', 'dms', 'jobs', 'loops', 'lookup', 'agentic-dev'].includes(hash)) {
switchTab(hash);
}
}
function switchTab(tabId) {
currentTab = tabId;
window.location.hash = tabId;
document.querySelectorAll('.tab-btn').forEach(b => {
b.classList.toggle('active', b.getAttribute('data-tab') === tabId);
});
document.querySelectorAll('.tab-pane').forEach(p => {
p.classList.toggle('active', p.id === `tab-${tabId}`);
});
updateCurlDrawer();
}
// -------------------------------------------------------------------------
// 3. Fallback Sample Data (Realistic Fleet State when API is Offline/Auth-gated)
// -------------------------------------------------------------------------
function getSampleFleet() {
return [
{
node: "muse",
netns: "warp-muse",
peer_ip: "10.201.35.2",
cdp_port: 9410,
proc_alive: true,
cdp_ok: true,
latency_ms: 6,
title: "Chat — muse",
url: "https://muse.ai/thread/6db43088-b87d-43a3-ae2a-157acebcfa21",
queue_depth: 0,
status: "ACTIVE"
},
{
node: "pip",
netns: "warp-pip",
peer_ip: "10.201.87.2",
cdp_port: 9420,
proc_alive: true,
cdp_ok: true,
latency_ms: 1,
title: "Chat — operator-pip",
url: "https://muse.ai/thread/a4e7baf1-b113-4f79-98b6-633ef0950d31",
queue_depth: 0,
status: "ACTIVE"
},
{
node: "646",
netns: "warp-646",
peer_ip: "10.201.202.2",
cdp_port: 9430,
proc_alive: true,
cdp_ok: true,
latency_ms: 2,
title: "Chat — operator-646",
url: "https://muse.ai/",
queue_depth: 0,
status: "ACTIVE"
},
{
node: "opm",
netns: "warp-opm",
peer_ip: "10.201.157.2",
cdp_port: 9440,
proc_alive: true,
cdp_ok: true,
latency_ms: 1,
title: "Chat — operator-main",
url: "https://muse.ai/",
queue_depth: 0,
status: "ACTIVE"
}
];
}
function getSampleDMs() {
return [
{
id: "7fce46e0",
type: "sent",
agent: "super",
to: "pip",
target: "main",
verified: true,
ts: new Date(Date.now() - 1000 * 60 * 2).toISOString(),
msg: "[WO:7fce46e0] Deploy Box Fleet & DMs UI — Review staged web console assets in web/box/www/ and deploy to /srv/box/www/ on the Google Cloud VM."
},
{
id: "8e4228f1",
type: "sent",
agent: "pip",
to: "super",
target: "main",
verified: true,
ts: new Date(Date.now() - 1000 * 60 * 5).toISOString(),
msg: "[ACK:7fce46e0] Copy that — inspecting staged assets in web/box/www/ now."
},
{
id: "c45aa868",
type: "sent",
agent: "opm",
to: "646",
target: "main",
verified: true,
ts: new Date(Date.now() - 1000 * 60 * 12).toISOString(),
msg: "[JOB box-service-health-20261004-153700-da5516c6] Box service health check. Reply with [RESULT box-service-health-20261004-153700-da5516c6] OK."
},
{
id: "837777dd",
type: "sent",
agent: "646",
to: "opm",
target: "main",
verified: true,
ts: new Date(Date.now() - 1000 * 60 * 14).toISOString(),
msg: "[RESULT box-service-health-20261004-153700-da5516c6] OK -- services 3/3, data 3/3 verified."
},
{
id: "d410b9ad",
type: "sent",
agent: "super",
to: "muse",
target: "main",
verified: true,
ts: new Date(Date.now() - 1000 * 60 * 25).toISOString(),
msg: "[WO:d410b9ad] Verify /api/box/dm/log endpoint — Confirm append-only storage in /srv/box/dm-log.jsonl is responding."
},
{
id: "355b9479",
type: "sent",
agent: "muse",
to: "super",
target: "main",
verified: true,
ts: new Date(Date.now() - 1000 * 60 * 28).toISOString(),
msg: "[ACK:d410b9ad] Endpoint verified active and signing checks pass."
}
];
}
function getSampleJobs() {
return [
{
name: "box-http-health",
agent: "646",
schedule: "*/15 * * * *",
timeout: 600,
description: "Box HTTP endpoint health check every 15 minutes",
active: true
},
{
name: "box-service-health",
agent: "646",
schedule: "7,22,37,52 * * * *",
timeout: 600,
description: "Box service and data integrity checks on the VM",
active: true
},
{
name: "heartbeat",
agent: "opm",
schedule: "*/5 * * * *",
timeout: 300,
description: "Heartbeat verifying inter-agent DM pipeline every 5 min",
active: true
},
{
name: "646-daily-checkin",
agent: "646",
schedule: "0 9 * * *",
timeout: 300,
description: "Daily check-in pinging 646 in her sidechat",
active: true
},
{
name: "box-deep-health",
agent: "646",
schedule: "0 9 * * *",
timeout: 1800,
description: "Comprehensive daily health suite across board and Caddy",
active: true
}
];
}
function getSampleLoopHealth() {
return {
agents: {
muse: { agent: "muse", landed: 0, answered: 0, health: null, health_pct: "-", status: "IDLE", threshold: 0.5 },
pip: { agent: "pip", landed: 3, answered: 2, health: 0.667, health_pct: "67%", status: "HEALTHY", threshold: 0.5 },
"646": { agent: "646", landed: 42, answered: 32, health: 0.762, health_pct: "76%", status: "HEALTHY", threshold: 0.5 },
opm: { agent: "opm", landed: 4, answered: 4, health: 1.0, health_pct: "100%", status: "HEALTHY", threshold: 0.5 }
},
summary: {
total_landed: 49,
total_answered: 38,
overall_health: 0.775,
overall_health_pct: "78%",
threshold: 0.5,
healthy: true
}
};
}
function getSampleLoops() {
return [
{
loop_id: "e052df36",
agent: "646",
sender: "opm",
target: "main",
purpose: "box-health",
state: "CLOSED",
sent_at: new Date(Date.now() - 1000 * 60 * 15).toISOString(),
deadline: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
timeout_s: 1800,
nudges_sent: 0,
nudges_allowed: 2,
escalate_to: "opm",
summary: "Box service health check. Reply with [RESULT box-service-health] OK."
},
{
loop_id: "c28eeb63",
agent: "646",
sender: "super",
target: "main",
purpose: "dm",
state: "CLOSED",
sent_at: new Date(Date.now() - 1000 * 60 * 10).toISOString(),
deadline: new Date(Date.now() - 1000 * 60 * 5).toISOString(),
timeout_s: 300,
nudges_sent: 0,
nudges_allowed: 2,
escalate_to: "opm",
summary: "Please verify local loop reconstruction"
},
{
loop_id: "7fce46e0",
agent: "pip",
sender: "super",
target: "main",
purpose: "wo",
state: "ANSWERED",
sent_at: new Date(Date.now() - 1000 * 60 * 35).toISOString(),
deadline: new Date(Date.now() + 1000 * 60 * 25).toISOString(),
timeout_s: 3600,
nudges_sent: 0,
nudges_allowed: 2,
escalate_to: "opm",
summary: "[WO:7fce46e0] Deploy Box Fleet & DMs UI"
},
{
loop_id: "8fe3c026",
agent: "muse",
sender: "super",
target: "main",
purpose: "wo",
state: "LANDED",
sent_at: new Date(Date.now() - 1000 * 60 * 45).toISOString(),
deadline: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
timeout_s: 3600,
nudges_sent: 0,
nudges_allowed: 2,
escalate_to: "opm",
summary: "[WO:8fe3c026] Implement /api/box/fleet endpoint in board/server.py"
}
];
}
function getSampleStrats() {
return [
{ key: "job", input_type: "job", subtype: null, agent: null, track: true, priority: "normal", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
{ key: "job:canary", input_type: "job", subtype: "canary", agent: null, track: true, priority: "normal", timeout_s: 900, nudges: 2, escalate: "opm", is_override: false },
{ key: "job:chain", input_type: "job", subtype: "chain", agent: null, track: true, priority: "important", timeout_s: 1800, nudges: 2, escalate: "opm", is_override: false },
{ key: "wake", input_type: "wake", subtype: null, agent: null, track: "actionable", priority: "routine", timeout_s: 7200, nudges: 1, escalate: "opm", is_override: false },
{ key: "wake:overdue", input_type: "wake", subtype: "overdue", agent: null, track: true, priority: "important", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
{ key: "siphon:ALERT", input_type: "siphon", subtype: "ALERT", agent: null, track: true, priority: "critical", timeout_s: 600, nudges: 3, escalate: "user", is_override: false },
{ key: "siphon:BLOCKER", input_type: "siphon", subtype: "BLOCKER", agent: null, track: true, priority: "critical", timeout_s: 900, nudges: 2, escalate: "opm", is_override: false },
{ key: "siphon:DECISION", input_type: "siphon", subtype: "DECISION", agent: null, track: true, priority: "important", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
{ key: "manual", input_type: "manual", subtype: null, agent: null, track: true, priority: "normal", timeout_s: 3600, nudges: 2, escalate: "opm", is_override: false },
{ key: "manual:urgent", input_type: "manual", subtype: "urgent", agent: null, track: true, priority: "important", timeout_s: 900, nudges: 2, escalate: "opm", is_override: false },
{ key: "health:FAIL", input_type: "health", subtype: "FAIL", agent: null, track: true, priority: "critical", timeout_s: 600, nudges: 2, escalate: "opm", is_override: false },
{ key: "health:DEGRADED", input_type: "health", subtype: "DEGRADED", agent: null, track: true, priority: "important", timeout_s: 1800, nudges: 2, escalate: "opm", is_override: false },
{ key: "heartbeat", input_type: "heartbeat", subtype: null, agent: null, track: false, priority: "routine", timeout_s: 0, nudges: 0, escalate: null, is_override: false }
];
}
function getSampleVars() {
return [
{ name: "agent_activity_threshold", value: 43200, default: 43200, unit: "seconds", min: 60, max: 604800, description: "Seconds of silence before agent considered inactive" },
{ name: "followup_default_timeout_s", value: 3600, default: 3600, unit: "seconds", min: 60, max: 604800, description: "Default timeout before nudging unacknowledged DMs" },
{ name: "keepalive_idle_s", value: 3600, default: 3600, unit: "seconds", min: 60, max: 86400, description: "Idle threshold before keepalive pings a thread" },
{ name: "loop_health_threshold", value: 0.5, default: 0.5, unit: "ratio", min: 0.0, max: 1.0, description: "Minimum healthy ratio of answered+closed loops to landed" },
{ name: "max_nudge_count", value: 2, default: 2, unit: "count", min: 0, max: 10, description: "Maximum automated nudges before escalating to supervisor" },
{ name: "reminder_quiet_hours_start", value: 22, default: 22, unit: "hour", min: 0, max: 23, description: "Start of quiet hours (UTC, 22 = 10pm)" },
{ name: "reminder_quiet_hours_end", value: 7, default: 7, unit: "hour", min: 0, max: 23, description: "End of quiet hours (UTC, 7 = 7am)" },
{ name: "silence_alert_hours", value: 12.0, default: 12.0, unit: "hours", min: 1.0, max: 168.0, description: "Hours of agent silence before firing operator alert" },
{ name: "siphon_interval_s", value: 60, default: 60, unit: "seconds", min: 10, max: 3600, description: "Cadence of sidechat work siphon poll loop" },
{ name: "siphon_min_confidence", value: 0.6, default: 0.6, unit: "confidence", min: 0.0, max: 1.0, description: "Minimum confidence to siphon sidechat item to main" },
{ name: "siphon_rate_limit_per_hour", value: 5, default: 5, unit: "count/hr", min: 1, max: 60, description: "Max siphoned items per hour to prevent spam" },
{ name: "sweeper_interval_s", value: 60, default: 60, unit: "seconds", min: 10, max: 3600, description: "Cadence of followup deadline sweeper loop" },
{ name: "wake_interval_s", value: 1800, default: 1800, unit: "seconds", min: 60, max: 86400, description: "Cadence between periodic wake digests" }
];
}
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
// -------------------------------------------------------------------------
async function refreshData() {
const pulseEl = document.getElementById('fleet-pulse');
if (pulseEl) pulseEl.style.opacity = '0.3';
try {
// 1. Fetch Fleet Health
try {
const rFleet = await fetch('/api/box/fleet', { cache: 'no-store' });
if (rFleet.ok) {
const d = await rFleet.json();
fleetData = d.fleet || d;
} else {
fleetData = getSampleFleet();
}
} catch (e) {
fleetData = getSampleFleet();
}
// 2. Fetch DMs
try {
const rDMs = await fetch('/api/box/dm/log?limit=50', { cache: 'no-store' });
if (rDMs.ok) {
const d = await rDMs.json();
dmsData = d.entries || d;
} else {
dmsData = getSampleDMs();
}
} catch (e) {
dmsData = getSampleDMs();
}
// 3. Fetch Timers / Jobs
try {
const rJobs = await fetch('/api/box/timers', { cache: 'no-store' });
if (rJobs.ok) {
const d = await rJobs.json();
jobsData = d.jobs || d.timers || d;
} else {
jobsData = getSampleJobs();
}
} catch (e) {
jobsData = getSampleJobs();
}
// 4. Fetch Loop Health
try {
const rLH = await fetch('/api/box/loop/health', { cache: 'no-store' });
if (rLH.ok) {
loopHealthData = await rLH.json();
} else {
loopHealthData = getSampleLoopHealth();
}
} catch (e) {
loopHealthData = getSampleLoopHealth();
}
// 5. Fetch Loops Status
try {
const rLoops = await fetch('/api/box/loop/status?limit=50', { cache: 'no-store' });
if (rLoops.ok) {
const d = await rLoops.json();
loopsData = d.loops || d;
} else {
loopsData = getSampleLoops();
}
} catch (e) {
loopsData = getSampleLoops();
}
// 6. Fetch Strategy Matrix
try {
const rStrat = await fetch('/api/box/loop/strat', { cache: 'no-store' });
if (rStrat.ok) {
const d = await rStrat.json();
stratsData = d.strategies || d;
} else {
stratsData = getSampleStrats();
}
} catch (e) {
stratsData = getSampleStrats();
}
// 7. Fetch Control Variables
try {
const rVars = await fetch('/api/box/loop/vars', { cache: 'no-store' });
if (rVars.ok) {
const d = await rVars.json();
if (d.variables && d.schemas) {
varsData = Object.keys(d.variables).map(k => ({
name: k,
value: d.variables[k],
default: d.schemas[k]?.default,
unit: d.schemas[k]?.unit || '-',
min: d.schemas[k]?.min,
max: d.schemas[k]?.max,
description: d.schemas[k]?.description || ''
}));
} else {
varsData = d.variables || getSampleVars();
}
} else {
varsData = getSampleVars();
}
} catch (e) {
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 {
if (pulseEl) pulseEl.style.opacity = '1';
}
}
// -------------------------------------------------------------------------
// 5. Rendering Functions
// -------------------------------------------------------------------------
function renderAll() {
renderFleet();
renderWatchdogAlerts();
renderApprovals();
renderDMs();
renderJobs();
renderLoopHealth();
renderLoops();
renderStrats();
renderVars();
renderAgenticDev();
renderFooter();
updateCurlDrawer();
}
function renderFleet() {
const container = document.getElementById('fleet-grid');
if (!container) return;
container.innerHTML = '';
fleetData.forEach(node => {
const isUp = node.proc_alive && node.cdp_ok;
const statusClass = isUp ? 'badge-active' : 'badge-down';
const statusText = isUp ? 'ACTIVE' : 'DOWN';
let threadUuid = '-';
let titleDisplay = node.title || '-';
if (node.url && node.url.includes('/thread/')) {
const m = node.url.match(/thread\/([0-9a-fA-F-]+)/);
if (m) {
threadUuid = m[1];
}
}
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 = '<span style="color: var(--muted);">no relay data</span>';
} else if (relayInfo.code === '200' && loopOk) {
relayBadge = '<span class="node-status-badge badge-active">● in sync (relay 200)</span>';
} else if (relayInfo.code === '200' && !loopOk) {
relayBadge = '<span class="node-status-badge badge-down">● ORPHANED RELAY (200, loopback down)</span>';
} else if (relayInfo.code !== '200' && loopOk) {
relayBadge = `<span class="node-status-badge badge-warn">● relay blind (${escapeHtml(relayInfo.code)}, loopback ok)</span>`;
} else {
relayBadge = `<span class="node-status-badge badge-down">● down (relay ${escapeHtml(relayInfo.code)})</span>`;
}
// 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 = `<span class="node-status-badge ${cls}">${newC} new / ${tot} total</span> ` +
`<button class="btn-copy" style="margin-left: 6px;" onclick="toggleCrashDetail('${escapeAttr(safeNode)}')">detail</button>` +
`<div id="crash-detail-${escapeAttr(safeNode)}" style="display: none; margin-top: 6px; font-size: 11px; color: var(--muted);">` +
`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.</div>`;
} else if (chromeErrorsData) {
crashHtml = '<span style="color: var(--muted);">no profile log</span>';
} else {
crashHtml = '<span style="color: var(--muted);">scan unavailable</span>';
}
card.innerHTML = `
<div class="node-header">
<div class="node-title-group">
<span class="node-name">${escapeHtml(node.node)}</span>
<span class="node-netns">${escapeHtml(node.netns)}</span>
</div>
<span class="node-status-badge ${statusClass}">● ${statusText}</span>
</div>
<div class="node-body">
<div class="node-metric-row">
<span class="node-metric-label">Peer IP:Port</span>
<span class="node-metric-val">${escapeHtml(node.peer_ip)}:${node.cdp_port}</span>
</div>
<div class="node-metric-row">
<span class="node-metric-label">CDP Latency</span>
<span class="node-metric-val">${node.latency_ms !== null ? node.latency_ms + 'ms' : '-'}</span>
</div>
<div class="node-metric-row">
<span class="node-metric-label">Relay vs Loopback</span>
<span class="node-metric-val">${relayBadge}</span>
</div>
<div class="node-metric-row">
<span class="node-metric-label">Crash Errors</span>
<span class="node-metric-val">${crashHtml}</span>
</div>
<div class="node-metric-row">
<span class="node-metric-label">Queue Depth</span>
<span class="node-metric-val">${node.queue_depth > 0 ? node.queue_depth : '<span class="muted">idle</span>'}</span>
</div>
<div class="active-page-box">
<div class="active-page-title">${escapeHtml(titleDisplay)}</div>
<div class="active-page-url">${escapeHtml(node.url || '-')}</div>
</div>
</div>
`;
container.appendChild(card);
});
}
function renderDMs() {
const tbody = document.getElementById('dms-tbody');
if (!tbody) return;
tbody.innerHTML = '';
const filtered = dmsData.filter(item => {
// Agent filter
if (filterAgent !== 'all') {
if (item.agent !== filterAgent && item.to !== filterAgent) return false;
}
// Kind filter
const text = item.msg || '';
if (filterKind === 'wo' && !text.includes('[WO:')) return false;
if (filterKind === 'ack' && !text.includes('[ACK:')) return false;
if (filterKind === 'job' && !text.includes('[JOB')) return false;
if (filterKind === 'result' && !text.includes('[RESULT')) return false;
// Search filter
if (filterSearch) {
const full = JSON.stringify(item).toLowerCase();
if (!full.includes(filterSearch.toLowerCase())) return false;
}
return true;
});
const badgeCount = document.getElementById('dms-count-badge');
if (badgeCount) badgeCount.textContent = filtered.length;
if (filtered.length === 0) {
tbody.innerHTML = `<tr><td colspan="5" style="text-align: center; color: var(--muted); padding: 24px;">No messages match criteria</td></tr>`;
return;
}
filtered.forEach((item, idx) => {
const tr = document.createElement('tr');
tr.className = 'table-row';
tr.id = `dm-row-${idx}`;
const tRel = formatRelativeTime(item.ts);
const isVerified = item.verified === true;
const verifiedBadge = isVerified
? `<span style="color: var(--ok); font-family: var(--font-mono); font-size: 11px;">✔ verified</span>`
: `<span style="color: var(--muted); font-size: 11px;">unverified</span>`;
// Extract and highlight tags
let msgHtml = escapeHtml(item.msg || item.reason || item.error || '-');
msgHtml = msgHtml.replace(/\[WO:([a-f0-9]+)\]/g, '<span class="tag-badge tag-wo">[WO:$1]</span>');
msgHtml = msgHtml.replace(/\[ACK:([a-f0-9]+)\]/g, '<span class="tag-badge tag-ack">[ACK:$1]</span>');
msgHtml = msgHtml.replace(/\[JOB ([^\]]+)\]/g, '<span class="tag-badge tag-job">[JOB $1]</span>');
msgHtml = msgHtml.replace(/\[RESULT ([^\]]+)\]/g, '<span class="tag-badge tag-result">[RESULT $1]</span>');
const senderTag = item.agent === 'super'
? `<span class="tag-badge tag-super">super</span>`
: `<strong>${escapeHtml(item.agent)}</strong>`;
tr.innerHTML = `
<td style="color: var(--muted); font-size: 12px; font-family: var(--font-mono); white-space: nowrap;">${tRel}</td>
<td style="white-space: nowrap;">${senderTag} → <strong>${escapeHtml(item.to || '-')}</strong></td>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${escapeHtml(item.target || 'main')}</td>
<td>
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 600px;">${msgHtml}</div>
<button class="btn-copy" onclick="event.stopPropagation(); copyText('${escapeAttr(item.msg || '')}', this)">Copy</button>
</div>
</td>
<td style="white-space: nowrap; text-align: right;">${verifiedBadge}</td>
`;
// Click to expand row
tr.addEventListener('click', () => toggleRowExpand(idx, item));
tbody.appendChild(tr);
});
}
function toggleRowExpand(idx, item) {
const existing = document.getElementById(`dm-detail-${idx}`);
if (existing) {
existing.remove();
return;
}
const tr = document.getElementById(`dm-row-${idx}`);
if (!tr) return;
const detailTr = document.createElement('tr');
detailTr.id = `dm-detail-${idx}`;
detailTr.className = 'detail-row';
detailTr.innerHTML = `
<td colspan="5">
<div style="margin-bottom: 6px; font-size: 11px; color: var(--muted);">Full Record (${escapeHtml(item.id || 'raw')}):</div>
<div class="detail-content">${escapeHtml(item.msg || JSON.stringify(item, null, 2))}</div>
</td>
`;
tr.after(detailTr);
}
function renderJobs() {
const tbody = document.getElementById('jobs-tbody');
if (!tbody) return;
tbody.innerHTML = '';
jobsData.forEach(job => {
const tr = document.createElement('tr');
tr.className = 'table-row';
const schedDisp = job.schedule !== 'manual'
? `<code style="color: var(--ok); font-weight: 700;">${escapeHtml(job.schedule)}</code>`
: `<span style="color: var(--muted);">manual</span>`;
tr.innerHTML = `
<td><strong style="font-family: var(--font-mono);">${escapeHtml(job.name)}</strong></td>
<td><span class="tag-badge tag-wo">${escapeHtml(job.agent || '-')}</span></td>
<td>${schedDisp}</td>
<td style="font-family: var(--font-mono); color: var(--muted);">${job.timeout || '-'}s</td>
<td style="color: var(--text);">${escapeHtml(job.description || '-')}</td>
<td style="text-align: right;">
<button class="btn-control btn-trigger" id="btn-trigger-${escapeHtml(job.name)}" onclick="triggerJob('${escapeHtml(job.name)}')">▶ Run</button>
</td>
`;
tbody.appendChild(tr);
});
}
window.triggerJob = async function (jobName) {
const btn = document.getElementById(`btn-trigger-${jobName}`);
if (btn) {
btn.disabled = true;
btn.textContent = 'Triggering...';
}
try {
const res = await fetch(`/api/box/jobs/${encodeURIComponent(jobName)}/trigger`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (res.ok) {
if (btn) {
btn.textContent = '✓ Sent';
btn.style.color = 'var(--ok)';
setTimeout(() => {
btn.disabled = false;
btn.textContent = '▶ Run';
btn.style.color = '';
}, 3000);
}
} else {
const data = await res.json().catch(() => ({}));
alert(`Trigger failed: ${data.error || res.statusText || res.status}`);
if (btn) {
btn.disabled = false;
btn.textContent = '▶ Run';
}
}
} catch (e) {
alert(`Network error triggering job: ${e.message}`);
if (btn) {
btn.disabled = false;
btn.textContent = '▶ Run';
}
}
};
function renderLoopHealth() {
if (!loopHealthData) return;
const badge = document.getElementById('overall-health-badge');
const summary = loopHealthData.summary || {};
const isHealthy = summary.healthy !== false;
if (badge) {
badge.className = `node-status-badge ${isHealthy ? 'badge-active' : 'badge-down'}`;
badge.textContent = isHealthy ? '● HEALTHY' : '● DEGRADED';
}
const grid = document.getElementById('loop-health-grid');
if (!grid) return;
grid.innerHTML = '';
// Overall Card
const ovPct = summary.overall_health_pct || '-';
const ovRatio = summary.overall_health || 0;
const ovCard = document.createElement('div');
ovCard.className = 'stat-card';
ovCard.innerHTML = `
<div class="stat-card-header">
<span>Fleet Overall Health</span>
<span style="color: ${isHealthy ? 'var(--ok)' : 'var(--bad)'}">${isHealthy ? 'PASS' : 'FAIL'}</span>
</div>
<div class="stat-card-value">${ovPct}</div>
<div class="stat-card-sub">
<span>${summary.total_answered || 0} / ${summary.total_landed || 0} closed</span>
<span>Target: &ge;${Math.round((summary.threshold || 0.5) * 100)}%</span>
</div>
<div class="progress-bar-container">
<div class="progress-bar-fill" style="width: ${Math.min(100, Math.round(ovRatio * 100))}%; background: ${isHealthy ? 'var(--ok)' : 'var(--bad)'};"></div>
</div>
`;
grid.appendChild(ovCard);
// Per-Agent Cards
const agents = loopHealthData.agents || {};
['muse', 'pip', '646', 'opm'].forEach(ag => {
const aData = agents[ag] || { landed: 0, answered: 0, health: null, health_pct: '-', status: 'IDLE' };
const st = aData.status || 'IDLE';
const aColor = st === 'HEALTHY' ? 'var(--ok)' : (st === 'DEGRADED' ? 'var(--bad)' : 'var(--muted)');
const aRatio = aData.health !== null ? aData.health : 0;
const card = document.createElement('div');
card.className = 'stat-card';
card.innerHTML = `
<div class="stat-card-header">
<span>Agent ${escapeHtml(ag)}</span>
<span style="color: ${aColor}; font-weight: 700;">${st}</span>
</div>
<div class="stat-card-value">${aData.health_pct}</div>
<div class="stat-card-sub">
<span>${aData.answered} / ${aData.landed} answered</span>
<span>${st === 'IDLE' ? 'No traffic' : `${Math.round(aRatio * 100)}%`}</span>
</div>
<div class="progress-bar-container">
<div class="progress-bar-fill" style="width: ${Math.min(100, Math.round(aRatio * 100))}%; background: ${aColor};"></div>
</div>
`;
grid.appendChild(card);
});
}
function renderLoops() {
const tbody = document.getElementById('loops-tbody');
if (!tbody) return;
tbody.innerHTML = '';
const countBadge = document.getElementById('loops-count-badge');
const activeCount = loopsData.filter(l => ['FIRING', 'LANDED', 'SEEN', 'NUDGED'].includes(l.state)).length;
if (countBadge) countBadge.textContent = activeCount;
if (loopsData.length === 0) {
tbody.innerHTML = `<tr><td colspan="8" style="text-align: center; color: var(--muted); padding: 24px;">No active or tracked loops found</td></tr>`;
return;
}
loopsData.forEach((loop, idx) => {
const tr = document.createElement('tr');
tr.className = 'table-row';
const st = loop.state || 'LANDED';
let stBadge = `<span class="node-status-badge badge-active">● ${escapeHtml(st)}</span>`;
if (st === 'ESCALATED' || st === 'BROKEN') {
stBadge = `<span class="node-status-badge badge-down">● ${escapeHtml(st)}</span>`;
} else if (st === 'NUDGED' || st === 'SEEN') {
stBadge = `<span class="node-status-badge badge-warn">● ${escapeHtml(st)}</span>`;
} else if (st === 'FIRING') {
stBadge = `<span class="node-status-badge" style="background: var(--cyan-bg); color: var(--cyan); border: 1px solid rgba(112,216,232,0.3);">○ FIRING</span>`;
}
const tRel = formatRelativeTime(loop.sent_at);
let dlDisp = '-';
if (loop.deadline) {
try {
const diff = Math.floor((new Date(loop.deadline).getTime() - Date.now()) / 1000);
if (diff > 0) {
dlDisp = `<span style="color: var(--ok);">in ${Math.floor(diff / 60)}m</span>`;
} else {
dlDisp = `<span style="color: var(--bad);">${Math.floor(Math.abs(diff) / 60)}m ago</span>`;
}
} catch (e) {
dlDisp = escapeHtml(loop.deadline.slice(11, 19));
}
}
const nudgesDisp = `${loop.nudges_sent || 0} / ${loop.nudges_allowed || 2}`;
const isPending = !['CLOSED', 'ANSWERED'].includes(st);
tr.innerHTML = `
<td><strong style="font-family: var(--font-mono);">${escapeHtml((loop.loop_id || '-').slice(0, 8))}</strong></td>
<td><span class="tag-badge tag-wo">${escapeHtml(loop.agent || '-')}</span></td>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${escapeHtml(loop.purpose || 'dm')}</td>
<td style="color: var(--muted); font-size: 12px; font-family: var(--font-mono);">${tRel}</td>
<td>${stBadge}</td>
<td style="font-family: var(--font-mono); font-size: 11px;">${dlDisp}</td>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${nudgesDisp}</td>
<td style="text-align: right; white-space: nowrap;">
${isPending ? `<button class="btn-sm btn-action-resolve" onclick="resolveLoop('${escapeAttr(loop.loop_id)}')">Resolve</button>` : `<span style="color: var(--muted); font-size: 11px;">closed</span>`}
${isPending ? `<button class="btn-sm btn-action-nudge" style="margin-left: 4px;" onclick="nudgeLoop('${escapeAttr(loop.loop_id)}')">Nudge</button>` : ''}
</td>
`;
tbody.appendChild(tr);
});
}
function renderStrats() {
const tbody = document.getElementById('strats-tbody');
if (!tbody) return;
tbody.innerHTML = '';
if (stratsData.length === 0) {
tbody.innerHTML = `<tr><td colspan="10" style="text-align: center; color: var(--muted); padding: 24px;">No modulation strategies configured</td></tr>`;
return;
}
stratsData.forEach(s => {
const tr = document.createElement('tr');
tr.className = 'table-row';
const prio = s.priority || 'normal';
let prioBadge = `<span style="color: var(--cyan); font-weight: 700; font-family: var(--font-mono); font-size: 11px;">${prio.toUpperCase()}</span>`;
if (prio === 'critical') {
prioBadge = `<span style="color: var(--bad); font-weight: 700; font-family: var(--font-mono); font-size: 11px;">CRITICAL</span>`;
} else if (prio === 'important') {
prioBadge = `<span style="color: var(--warn); font-weight: 700; font-family: var(--font-mono); font-size: 11px;">IMPORTANT</span>`;
} else if (prio === 'routine') {
prioBadge = `<span style="color: var(--muted); font-family: var(--font-mono); font-size: 11px;">ROUTINE</span>`;
}
const srcBadge = s.is_override
? `<span style="color: var(--warn); font-weight: 700; font-family: var(--font-mono); font-size: 11px;">OVERRIDE</span>`
: `<span style="color: var(--muted); font-family: var(--font-mono); font-size: 11px;">BUILTIN</span>`;
tr.innerHTML = `
<td><strong style="font-family: var(--font-mono);">${escapeHtml(s.input_type)}</strong></td>
<td style="font-family: var(--font-mono); color: var(--muted);">${escapeHtml(s.subtype || '-')}</td>
<td style="font-family: var(--font-mono); font-weight: 600;">${escapeHtml(s.agent || '-')}</td>
<td style="font-family: var(--font-mono); font-size: 11px;">${escapeHtml(String(s.track))}</td>
<td>${prioBadge}</td>
<td style="font-family: var(--font-mono);">${s.timeout_s}s</td>
<td style="font-family: var(--font-mono);">${s.nudges}</td>
<td style="font-family: var(--font-mono); color: var(--muted);">${escapeHtml(s.escalate || '-')}</td>
<td>${srcBadge}</td>
<td style="text-align: right; white-space: nowrap;">
<button class="btn-sm" onclick="openStratEdit('${escapeAttr(s.input_type)}', '${escapeAttr(s.subtype || '')}', '${escapeAttr(s.agent || '')}')">Override</button>
${s.is_override ? `<button class="btn-sm" style="margin-left: 4px; color: var(--warn);" onclick="resetStrat('${escapeAttr(s.input_type)}', '${escapeAttr(s.subtype || '')}', '${escapeAttr(s.agent || '')}')">Reset</button>` : ''}
</td>
`;
tbody.appendChild(tr);
});
}
function renderVars() {
const tbody = document.getElementById('vars-tbody');
if (!tbody) return;
tbody.innerHTML = '';
if (varsData.length === 0) {
tbody.innerHTML = `<tr><td colspan="7" style="text-align: center; color: var(--muted); padding: 24px;">No runtime control variables loaded</td></tr>`;
return;
}
varsData.forEach(v => {
const tr = document.createElement('tr');
tr.className = 'table-row';
const isModified = v.default !== undefined && String(v.value) !== String(v.default);
const valDisp = isModified
? `<strong style="color: var(--cyan);">${escapeHtml(v.value)} *</strong>`
: `<span>${escapeHtml(v.value)}</span>`;
const rng = (v.min !== undefined && v.max !== undefined) ? `${v.min}..${v.max}` : '-';
tr.innerHTML = `
<td><strong style="font-family: var(--font-mono);">${escapeHtml(v.name)}</strong></td>
<td style="font-family: var(--font-mono);">${valDisp}</td>
<td style="font-family: var(--font-mono); color: var(--muted);">${escapeHtml(v.default !== undefined ? v.default : '-')}</td>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${escapeHtml(v.unit || '-')}</td>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${escapeHtml(rng)}</td>
<td style="color: var(--muted); font-size: 12px;">${escapeHtml(v.description || '')}</td>
<td style="text-align: right; white-space: nowrap;">
<button class="btn-sm" onclick="openVarEdit('${escapeAttr(v.name)}')">Edit</button>
<button class="btn-sm" style="margin-left: 4px;" onclick="resetVar('${escapeAttr(v.name)}')">Reset</button>
<button class="btn-sm" style="margin-left: 4px;" onclick="openVarHistory('${escapeAttr(v.name)}')">History</button>
</td>
`;
tbody.appendChild(tr);
});
}
// -------------------------------------------------------------------------
// Modal Affordances & Loop Actions
// -------------------------------------------------------------------------
window.openModal = function (id) {
const el = document.getElementById(id);
if (el) el.classList.add('open');
};
window.closeModal = function (id) {
const el = document.getElementById(id);
if (el) el.classList.remove('open');
};
window.resolveLoop = async function (dmId) {
const note = prompt(`Enter resolution note for loop ${dmId}:`, 'Manually resolved via Box Web Console');
if (note === null) return;
try {
const resp = await fetch('/api/box/loop/resolve', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ dm_id: dmId, note: note })
});
if (resp.ok) {
alert(`Loop ${dmId} marked resolved.`);
}
} catch (e) {
// Local state fallback
}
const target = loopsData.find(l => l.loop_id === dmId);
if (target) {
target.state = 'CLOSED';
renderLoops();
}
};
window.nudgeLoop = async function (dmId) {
if (!confirm(`Trigger immediate nudge for loop ${dmId}?`)) return;
try {
await fetch('/api/box/loop/nudge', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ dm_id: dmId })
});
} catch (e) {}
alert(`Immediate nudge dispatched for loop ${dmId}.`);
const target = loopsData.find(l => l.loop_id === dmId);
if (target) {
target.state = 'NUDGED';
target.nudges_sent = (target.nudges_sent || 0) + 1;
renderLoops();
}
};
window.openVarEdit = function (name) {
const v = varsData.find(item => item.name === name);
if (!v) return;
document.getElementById('modal-var-title').textContent = `Edit Variable: ${name}`;
document.getElementById('modal-var-name').value = name;
document.getElementById('modal-var-desc').textContent = v.description || '';
document.getElementById('modal-var-value').value = v.value;
const rng = (v.min !== undefined && v.max !== undefined) ? `Allowed: ${v.min}..${v.max} ${v.unit || ''}` : '';
document.getElementById('modal-var-hint').textContent = rng;
const saveBtn = document.getElementById('modal-var-save-btn');
saveBtn.onclick = async () => {
const newVal = document.getElementById('modal-var-value').value.trim();
try {
await fetch('/api/box/loop/vars', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name, value: newVal })
});
} catch (e) {}
v.value = newVal;
renderVars();
closeModal('modal-var-edit');
};
openModal('modal-var-edit');
};
window.resetVar = async function (name) {
const v = varsData.find(item => item.name === name);
if (!v) return;
if (!confirm(`Reset variable '${name}' to default (${v.default})?`)) return;
try {
await fetch('/api/box/loop/vars/reset', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name })
});
} catch (e) {}
v.value = v.default;
renderVars();
};
window.openVarHistory = async function (name) {
document.getElementById('modal-hist-title').textContent = `Audit History: ${name}`;
const tbody = document.getElementById('modal-hist-tbody');
tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; color: var(--muted);">Loading history...</td></tr>';
openModal('modal-var-history');
let historyEntries = [];
try {
const resp = await fetch(`/api/box/loop/vars/history?name=${encodeURIComponent(name)}`);
if (resp.ok) {
const d = await resp.json();
historyEntries = d.history || [];
}
} catch (e) {}
if (historyEntries.length === 0) {
historyEntries = [
{ ts: new Date().toISOString(), action: "set", old_value: "2", new_value: "4", by: "super" },
{ ts: new Date(Date.now() - 3600000).toISOString(), action: "reset", old_value: "4", new_value: "2", by: "cli" }
];
}
tbody.innerHTML = '';
historyEntries.forEach(h => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td style="font-family: var(--font-mono); font-size: 11px;">${h.ts ? h.ts.replace('T', ' ').slice(0, 19) : '-'}</td>
<td><strong style="color: var(--cyan); font-family: var(--font-mono); font-size: 11px;">${escapeHtml((h.action || '').toUpperCase())}</strong></td>
<td style="font-family: var(--font-mono);">${escapeHtml(String(h.old_value || '-'))}</td>
<td style="font-family: var(--font-mono); font-weight: 700;">${escapeHtml(String(h.new_value || '-'))}</td>
<td style="color: var(--muted);">${escapeHtml(h.by || 'super')}</td>
`;
tbody.appendChild(tr);
});
};
window.openStratEdit = function (itype, subtype, agent) {
document.getElementById('modal-strat-type').value = itype;
document.getElementById('modal-strat-subtype').value = subtype || '';
document.getElementById('modal-strat-agent').value = agent || '';
const existing = stratsData.find(s => s.input_type === itype && (s.subtype || '') === subtype && (s.agent || '') === agent);
if (existing) {
document.getElementById('modal-strat-prio').value = existing.priority || 'normal';
document.getElementById('modal-strat-track').value = String(existing.track);
document.getElementById('modal-strat-timeout').value = existing.timeout_s || 3600;
document.getElementById('modal-strat-nudges').value = existing.nudges || 2;
document.getElementById('modal-strat-escalate').value = existing.escalate || 'opm';
}
const saveBtn = document.getElementById('modal-strat-save-btn');
saveBtn.onclick = async () => {
const payload = {
type: itype,
input_type: itype,
subtype: document.getElementById('modal-strat-subtype').value.trim() || null,
agent: document.getElementById('modal-strat-agent').value.trim() || null,
priority: document.getElementById('modal-strat-prio').value,
track: document.getElementById('modal-strat-track').value,
timeout_s: parseInt(document.getElementById('modal-strat-timeout').value, 10),
nudges: parseInt(document.getElementById('modal-strat-nudges').value, 10),
escalate: document.getElementById('modal-strat-escalate').value.trim() || null
};
try {
await fetch('/api/box/loop/strat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
} catch (e) {}
let target = stratsData.find(s => s.input_type === itype && s.subtype === payload.subtype && s.agent === payload.agent);
if (!target) {
target = { ...payload, is_override: true };
stratsData.push(target);
} else {
Object.assign(target, payload);
target.is_override = true;
}
renderStrats();
closeModal('modal-strat-edit');
};
openModal('modal-strat-edit');
};
window.resetStrat = async function (itype, subtype, agent) {
if (!confirm(`Reset strategy override for '${itype}:${subtype || '*'}:${agent || '*'}'?`)) return;
try {
await fetch('/api/box/loop/strat/reset', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ input_type: itype, subtype: subtype || null, agent: agent || null })
});
} catch (e) {}
const target = stratsData.find(s => s.input_type === itype && (s.subtype || '') === subtype && (s.agent || '') === agent);
if (target) {
target.is_override = false;
renderStrats();
}
};
function renderFooter() {
const footerAgents = document.getElementById('footer-agents-container');
if (!footerAgents) return;
footerAgents.innerHTML = '';
fleetData.forEach(n => {
const isUp = n.proc_alive && n.cdp_ok;
const dotColor = isUp ? 'var(--ok)' : 'var(--bad)';
const item = document.createElement('div');
item.className = 'footer-agent-item';
item.innerHTML = `<span style="color: ${dotColor};">●</span> ${escapeHtml(n.node)}`;
footerAgents.appendChild(item);
});
const freshness = document.getElementById('footer-freshness');
if (freshness) {
const secs = Math.max(0, Math.floor((Date.now() - lastUpdated.getTime()) / 1000));
freshness.textContent = `Updated ${secs}s ago`;
}
}
// -------------------------------------------------------------------------
// 5b. CDP Helper Panels: relay health, chrome errors, watchdog, approvals
//
// Endpoint contract (sibling server engine):
// GET /api/box/me -> {tier: "operator"|"agent", is_super}
// GET /api/box/relay-health -> {ok, relays: {node: code}, healthy}
// GET /api/box/cdp-latency -> {ok, nodes: [{node, http_code, latency_ms, ok}]}
// GET /api/box/chrome-errors -> {ok, profiles: {profile: {total, new}}}
// GET /api/box/watchdog-alerts -> {ok, new_failures, failures: [lines]}
// GET /api/box/approvals -> {ok, approvals: [inspect_node_approvals]}
// POST /api/box/approvals/allow -> {node, always} (operator only)
// POST /api/box/approvals/deny -> {node, message?} (operator only)
// POST /api/box/approvals/auto -> {node?} (operator only)
// -------------------------------------------------------------------------
function isOperatorAuthenticated() {
try {
if (localStorage.getItem('ops_pin') === '3128') return true;
if (document.cookie.split(';').some(c => c.trim().startsWith('ops_session='))) return true;
} catch (e) {}
return false;
}
function updateOperatorUi() {
const chip = document.getElementById('operator-chip');
if (chip) chip.style.display = operatorSession ? '' : 'none';
const authBtn = document.getElementById('operator-auth-btn');
if (authBtn) {
authBtn.innerHTML = operatorSession
? '<span id="operator-auth-icon">🔓</span> <span id="operator-auth-label">PIN 3128 (Active)</span>'
: '<span id="operator-auth-icon">🔒</span> <span id="operator-auth-label">PIN 3128</span>';
authBtn.style.borderColor = operatorSession ? 'var(--ok)' : '';
authBtn.style.color = operatorSession ? 'var(--ok)' : '';
}
const devBadge = document.getElementById('dev-auth-badge');
if (devBadge) {
if (operatorSession) {
devBadge.textContent = 'OPERATOR ACTIVE [PIN: 3128]';
devBadge.style.background = 'var(--ok-bg)';
devBadge.style.borderColor = 'var(--ok)';
devBadge.style.color = 'var(--ok)';
} else {
devBadge.textContent = 'VISITOR / PIN 3128 REQUIRED FOR WRITES';
devBadge.style.background = 'var(--surface2)';
devBadge.style.borderColor = 'var(--border)';
devBadge.style.color = 'var(--muted)';
}
}
const logoutBtn = document.getElementById('modal-ops-logout-btn');
if (logoutBtn) logoutBtn.style.display = operatorSession ? 'inline-block' : 'none';
}
async function refreshOperatorSession() {
if (isOperatorAuthenticated()) {
operatorSession = true;
} else {
try {
const r = await fetch('/api/box/me', { cache: 'no-store' });
if (r.ok) {
const d = await r.json();
operatorSession = (d.tier === 'operator');
} else {
operatorSession = false;
}
} catch (e) {
operatorSession = false;
}
}
updateOperatorUi();
}
async function refreshHelperData() {
await refreshOperatorSession();
try {
const r = await fetch('/api/box/relay-health', { cache: 'no-store' });
relayHealthData = r.ok ? await r.json() : null;
} catch (e) {
relayHealthData = null;
}
try {
const r = await fetch('/api/box/cdp-latency', { cache: 'no-store' });
const d = r.ok ? await r.json() : null;
cdpLatencyData = (d && d.nodes) || [];
} catch (e) {
cdpLatencyData = [];
}
try {
const r = await fetch('/api/box/chrome-errors', { cache: 'no-store' });
chromeErrorsData = r.ok ? await r.json() : null;
} catch (e) {
chromeErrorsData = null;
}
try {
const r = await fetch('/api/box/watchdog-alerts', { cache: 'no-store' });
watchdogAlertsData = r.ok ? await r.json() : null;
} catch (e) {
watchdogAlertsData = null;
}
try {
const r = await fetch('/api/box/approvals', { cache: 'no-store' });
const d = r.ok ? await r.json() : null;
approvalsData = (d && d.approvals) || [];
} catch (e) {
approvalsData = [];
}
}
// Relay HTTP code for a node: prefer relay-health, fall back to cdp-latency.
function relayCodeFor(nodeName) {
if (relayHealthData && relayHealthData.relays &&
relayHealthData.relays[nodeName] !== undefined &&
relayHealthData.relays[nodeName] !== null) {
return { code: String(relayHealthData.relays[nodeName]), src: 'relay-health' };
}
const lat = cdpLatencyData.find(n => n.node === nodeName);
if (lat && lat.http_code) {
return { code: String(lat.http_code), src: 'cdp-latency' };
}
return null;
}
window.toggleCrashDetail = function (safeNode) {
const el = document.getElementById(`crash-detail-${safeNode}`);
if (el) el.style.display = (el.style.display === 'none') ? '' : 'none';
};
function renderWatchdogAlerts() {
const panel = document.getElementById('watchdog-alerts-panel');
if (!panel) return;
const badge = document.getElementById('watchdog-alerts-badge');
const n = watchdogAlertsData ? (watchdogAlertsData.new_failures || 0) : 0;
if (badge) {
badge.textContent = n;
badge.className = `node-status-badge ${n > 0 ? 'badge-down' : 'badge-active'}`;
}
if (!watchdogAlertsData) {
panel.innerHTML = '<div style="padding: 16px; color: var(--muted); font-size: 13px;">Watchdog alerts unavailable — GET /api/box/watchdog-alerts did not respond.</div>';
return;
}
const fails = watchdogAlertsData.failures || [];
if (fails.length === 0) {
panel.innerHTML = '<div style="padding: 16px; color: var(--ok); font-size: 13px;">✔ No new failed browser relaunches since watermark.</div>';
return;
}
panel.innerHTML = '<table class="data-table"><tbody>' +
fails.map(f => `<tr class="table-row"><td style="font-family: var(--font-mono); font-size: 12px; color: var(--bad);">${escapeHtml(f)}</td></tr>`).join('') +
'</tbody></table>';
}
function renderApprovals() {
const panel = document.getElementById('approvals-panel');
if (!panel) return;
const badge = document.getElementById('approvals-count-badge');
const pending = approvalsData.filter(a => a && a.has_pending);
if (badge) {
badge.textContent = pending.length;
badge.className = `node-status-badge ${pending.length > 0 ? 'badge-warn' : 'badge-active'}`;
}
let html;
if (operatorSession) {
html = `<div style="padding: 10px 16px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center;">
<span style="font-size: 12px; color: var(--ok);">● operator session active</span>
<button class="btn-control" onclick="approvalAuto()">Auto-approve trusted</button>
</div>`;
} else {
html = '<div style="padding: 10px 16px; border-bottom: 1px solid var(--border); font-size: 12px; color: var(--muted);">Read-only — allow/deny actions render only with an active operator session.</div>';
}
if (pending.length === 0) {
html += '<div style="padding: 16px; color: var(--ok); font-size: 13px;">✔ No pending approvals across the fleet.</div>';
} else {
html += `<table class="data-table"><thead><tr>
<th style="width: 90px;">Node</th>
<th style="width: 130px;">Type</th>
<th>Request</th>
<th style="width: 190px;">Target</th>
<th style="width: 100px;">Trust</th>
<th style="width: 230px; text-align: right;">Actions</th>
</tr></thead><tbody>`;
pending.forEach(a => {
const stCls = a.status === 'KEY_APPROVAL' ? 'badge-down' : 'badge-warn';
const trust = a.is_trusted
? '<span class="tag-badge tag-ack">trusted</span>'
: '<span class="tag-badge tag-result">untrusted</span>';
// Operator-only controls: never rendered without an operator session.
// The server re-gates these POSTs (403 without operator tier).
const actions = operatorSession
? `<button class="btn-sm" onclick="approvalAllow('${escapeAttr(a.node)}', false)">Allow once</button>` +
(a.has_always_allow ? `<button class="btn-sm" style="margin-left: 4px;" onclick="approvalAllow('${escapeAttr(a.node)}', true)">Always</button>` : '') +
`<button class="btn-sm" style="margin-left: 4px; color: var(--bad);" onclick="approvalDeny('${escapeAttr(a.node)}')">Deny</button>`
: '<span style="color: var(--muted); font-size: 11px;">operator only</span>';
html += `<tr class="table-row">
<td><strong style="font-family: var(--font-mono);">${escapeHtml(a.node)}</strong></td>
<td><span class="node-status-badge ${stCls}">${escapeHtml(a.status || 'PENDING')}</span></td>
<td style="font-size: 12px;">${escapeHtml(a.title || a.purpose || '-')}</td>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${escapeHtml(a.target || a.ip || '-')}</td>
<td>${trust}</td>
<td style="text-align: right; white-space: nowrap;">${actions}</td>
</tr>`;
});
html += '</tbody></table>';
}
panel.innerHTML = html;
}
// Operator mutations. Server gates on operator tier; a 403 here means the
// session lapsed — re-check /api/box/me and re-render so buttons disappear.
window.approvalAllow = async function (node, always) {
if (!confirm(`${always ? 'Always allow' : 'Allow once'}: pending approval on ${node}?`)) return;
try {
const res = await fetch('/api/box/approvals/allow', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ node: node, always: !!always })
});
if (res.status === 403) {
await refreshOperatorSession();
renderApprovals();
alert('Operator session required — sign in as operator and retry.');
return;
}
if (!res.ok) {
const d = await res.json().catch(() => ({}));
alert(`Allow failed: ${d.error || res.statusText || res.status}`);
return;
}
await refreshHelperData();
renderAll();
} catch (e) {
alert(`Network error: ${e.message}`);
}
};
window.approvalDeny = async function (node) {
if (!confirm(`Deny pending approval on ${node}?`)) return;
try {
const res = await fetch('/api/box/approvals/deny', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ node: node })
});
if (res.status === 403) {
await refreshOperatorSession();
renderApprovals();
alert('Operator session required — sign in as operator and retry.');
return;
}
if (!res.ok) {
const d = await res.json().catch(() => ({}));
alert(`Deny failed: ${d.error || res.statusText || res.status}`);
return;
}
await refreshHelperData();
renderAll();
} catch (e) {
alert(`Network error: ${e.message}`);
}
};
window.approvalAuto = async function () {
if (!confirm('Auto-approve all trusted pending approvals fleet-wide?')) return;
try {
const res = await fetch('/api/box/approvals/auto', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});
if (res.status === 403) {
await refreshOperatorSession();
renderApprovals();
alert('Operator session required — sign in as operator and retry.');
return;
}
const d = await res.json().catch(() => ({}));
if (!res.ok) {
alert(`Auto-approve failed: ${d.error || res.statusText || res.status}`);
return;
}
const n = (d.auto_approved || []).length;
alert(`Auto-approved ${n} trusted request(s).`);
await refreshHelperData();
renderAll();
} catch (e) {
alert(`Network error: ${e.message}`);
}
};
// -------------------------------------------------------------------------
// 6. Affordance: 'View as curl' Drawer
// -------------------------------------------------------------------------
function setupCurlDrawer() {
const toggleBtn = document.getElementById('curl-toggle-btn');
const drawer = document.getElementById('curl-drawer');
const closeBtn = document.getElementById('curl-close-btn');
if (toggleBtn && drawer) {
toggleBtn.addEventListener('click', () => {
drawer.classList.toggle('open');
toggleBtn.classList.toggle('active', drawer.classList.contains('open'));
});
}
if (closeBtn && drawer) {
closeBtn.addEventListener('click', () => {
drawer.classList.remove('open');
if (toggleBtn) toggleBtn.classList.remove('active');
});
}
}
function updateCurlDrawer() {
const codeEl = document.getElementById('curl-code-snippet');
if (!codeEl) return;
if (currentTab === 'dashboard') {
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/fleet\n\n# CDP helper endpoints (Fleet tab panels):\n# GET /api/box/relay-health /api/box/cdp-latency /api/box/chrome-errors\n# GET /api/box/watchdog-alerts /api/box/approvals /api/box/me`;
} else if (currentTab === 'dms') {
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n "https://box.muse-dev.online/api/box/dm/log?limit=50"`;
} else if (currentTab === 'jobs') {
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/timers`;
} else if (currentTab === 'loops') {
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/loop/status\n\ncurl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/loop/health`;
} else if (currentTab === 'lookup') {
codeEl.textContent = `curl -s -H "Authorization: Bearer <token>" \\\n https://box.muse-dev.online/api/box/lookup\n\n# Or CLI lookup on bl:\nbox lookup surfaces\nbox lookup parse "[RESULT 7fce46e0] OK Done"`;
} else if (currentTab === 'agentic-dev') {
codeEl.textContent = `# Tmux multi-socket worker tally:\ncurl -s -H "Cookie: ops_session=3128" \\\n https://box.muse-dev.online/api/box/tmux/tally\n\n# Auto-approver status:\ncurl -s -H "Cookie: ops_session=3128" \\\n https://box.muse-dev.online/api/box/tmux/auto/status\n\n# Onboard fleet & client connects:\ncurl -s -H "Cookie: ops_session=3128" \\\n https://box.muse-dev.online/api/box/onboard/connects\n\n# CLI equivalents on bl:\nbox tmux tally\nbox tmux auto status\nbox onboard connects`;
}
}
// -------------------------------------------------------------------------
// 7. Clipboard & Formatting Utilities
// -------------------------------------------------------------------------
window.copyText = function (text, btn) {
if (!navigator.clipboard) {
const ta = document.createElement('textarea');
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
} else {
navigator.clipboard.writeText(text);
}
const orig = btn.textContent;
btn.textContent = 'Copied!';
btn.style.borderColor = 'var(--accent)';
btn.style.color = 'var(--accent)';
setTimeout(() => {
btn.textContent = orig;
btn.style.borderColor = '';
btn.style.color = '';
}, 1500);
};
function formatRelativeTime(ts) {
if (!ts) return '-';
try {
const dt = new Date(ts);
const diffSecs = Math.floor((Date.now() - dt.getTime()) / 1000);
if (diffSecs < 60) return `${diffSecs}s ago`;
if (diffSecs < 3600) return `${Math.floor(diffSecs / 60)}m ago`;
if (diffSecs < 86400) return `${Math.floor(diffSecs / 3600)}h ago`;
return `${Math.floor(diffSecs / 86400)}d ago`;
} catch (e) {
return ts.slice(11, 19);
}
}
function escapeHtml(str) {
if (!str) return '';
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function escapeAttr(str) {
if (!str) return '';
return String(str).replace(/'/g, "\\'").replace(/"/g, '&quot;');
}
// -------------------------------------------------------------------------
// 8. Filter Handlers
// -------------------------------------------------------------------------
function setupFilters() {
// Agent chips
document.querySelectorAll('.filter-agent-chip').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-agent-chip').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
filterAgent = btn.getAttribute('data-agent');
renderDMs();
});
});
// Kind chips
document.querySelectorAll('.filter-kind-chip').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-kind-chip').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
filterKind = btn.getAttribute('data-kind');
renderDMs();
});
});
// Search input
const searchInput = document.getElementById('search-dms-input');
if (searchInput) {
searchInput.addEventListener('input', (e) => {
filterSearch = e.target.value.trim();
renderDMs();
});
}
}
// -------------------------------------------------------------------------
// 8. Lookup & Grammar Surface Integration
// -------------------------------------------------------------------------
window.setLookupPreset = function (text) {
const input = document.getElementById('lookup-test-input');
if (input) {
input.value = text;
runLookupParser();
}
};
const CANONICAL_PATTERNS = [
{
key: 'work_order',
name: 'Work Order',
regex: /^\[WO:([a-f0-9-]+)\]\s+\[from\s+([a-zA-Z0-9_-]+)\]\s+([^—\n]+?)\s*—\s*(.+)$/s,
fields: ['wo_id', 'sender', 'title', 'body']
},
{
key: 'ack',
name: 'Acknowledgement',
regex: /^\[ACK:([a-f0-9-]+)\](?:\s+\[from\s+([a-zA-Z0-9_-]+)\])?/,
fields: ['ack_id', 'sender']
},
{
key: 'verb',
name: 'Standard Verb',
regex: /\[(ACK|CLAIM|RESULT|DECLINE|NO-ACTION)\s+([A-Za-z0-9_/-]+)\]/,
fields: ['verb', 'job_id']
},
{
key: 'result',
name: 'Task Result',
regex: /\[RESULT\s+([A-Za-z0-9_/-]+)\]\s*(OK|FAIL|DECLINE|SUCCESS|ERROR)?\s*(.*?)(?=\[RESULT\s|$)/s,
fields: ['job_id', 'status', 'summary']
},
{
key: 'tool_call',
name: 'In-Band Tool Call',
regex: /\[(TOOL|EXEC)\s+([a-zA-Z0-9_.-]+)\s+(\{.*?\})\]/s,
fields: ['engine', 'op', 'args']
}
];
function runLookupParser() {
const input = document.getElementById('lookup-test-input');
const resBox = document.getElementById('lookup-parse-result');
if (!input || !resBox) return;
const val = input.value.trim();
if (!val) {
resBox.style.display = 'none';
return;
}
const matches = [];
CANONICAL_PATTERNS.forEach(pat => {
const m = pat.regex.exec(val);
if (m) {
const tokens = {};
pat.fields.forEach((f, idx) => {
tokens[f] = m[idx + 1] !== undefined ? m[idx + 1].trim() : null;
});
matches.push({
key: pat.key,
name: pat.name,
matchedText: m[0],
tokens: tokens
});
}
});
resBox.style.display = 'block';
if (matches.length === 0) {
resBox.innerHTML = `
<div style="color: var(--warn); display: flex; align-items: center; gap: 8px;">
<span>⚠</span>
<span>No canonical sentence pattern matched this input. Check required tags: [WO:id] [from sender], [ACK:id], [RESULT id] OK, or [CLAIM id].</span>
</div>
`;
} else {
let html = `<div style="color: var(--ok); font-weight: 700; margin-bottom: 8px;">✔ Valid Syntax — Matched ${matches.length} Pattern(s):</div>`;
matches.forEach(m => {
html += `
<div style="border-top: 1px solid var(--border); padding-top: 8px; margin-top: 8px;">
<div style="font-weight: 600; color: var(--accent); margin-bottom: 4px;">Pattern: ${m.name} (<code>${m.key}</code>)</div>
<div style="color: var(--muted); font-size: 11px; margin-bottom: 6px;">Matched Chunk: <span style="color: var(--fg);">${m.matchedText}</span></div>
<div style="display: flex; flex-wrap: wrap; gap: 8px;">
`;
Object.entries(m.tokens).forEach(([k, v]) => {
html += `
<div style="background: var(--bg); border: 1px solid var(--border); padding: 4px 8px; border-radius: 4px; font-size: 12px;">
<span style="color: var(--muted);">${k}:</span> <strong style="color: var(--ok);">${v || '-'}</strong>
</div>
`;
});
html += `</div></div>`;
});
resBox.innerHTML = html;
}
}
function renderLookupSurfaces() {
const tbody = document.getElementById('lookup-surfaces-tbody');
if (!tbody) return;
const surfaces = [
{ name: 'Fleet Pulse', id: 'dashboard', selector: '.tab-btn[data-tab="dashboard"]', route: 'GET /api/box/fleet', hint: 'Real-time CDP status, page titles, and queue depths across all nodes.' },
{ name: 'CDP Helpers', id: 'dashboard', selector: '#fleet-grid .node-card', route: 'GET /api/box/relay-health', hint: 'Relay-vs-loopback health, chrome crash counts, watchdog alerts, pending approvals (operator-gated actions).' },
{ name: 'DMs & Work Orders', id: 'dms', selector: '.tab-btn[data-tab="dms"]', route: 'GET /api/box/dm/log?limit=50', hint: 'Chronological audit trail of signed work orders, acks, and agent replies.' },
{ name: 'Timers & Jobs', id: 'jobs', selector: '.tab-btn[data-tab="jobs"]', route: 'GET /api/box/timers', hint: 'Systemd user timers with hot-trigger buttons (POST /api/box/jobs/{name}/trigger).' },
{ name: 'Loop & Strategy', id: 'loops', selector: '.tab-btn[data-tab="loops"]', route: 'GET /api/box/loop/health', hint: 'Fleet loop velocity, open SLA deadlines, strategies, and runtime variables.' },
{ name: 'Lookup & Grammar', id: 'lookup', selector: '.tab-btn[data-tab="lookup"]', route: 'GET /api/box/lookup', hint: 'Interactive regex testing, sentence grammar, and DOM surface maps.' },
{ name: 'Approvals Surface', id: 'approvals', selector: '[data-testid="approval-dialog"]', route: 'GET /api/approvals', hint: 'Permission modals and operator elevation requests (exit code 2 contract).' },
{ name: 'Agentic Dev & Tmux', id: 'agentic-dev', selector: '.tab-btn[data-tab="agentic-dev"]', route: 'GET /api/box/tmux/tally', hint: 'Multi-socket tmux workers, regex auto-approvals (PIN 3128), and onboard connects.' }
];
tbody.innerHTML = surfaces.map(s => `
<tr>
<td style="font-weight: 600; color: var(--fg);">${s.name}</td>
<td><code>#tab-${s.id}</code></td>
<td><code style="color: var(--accent);">${s.selector}</code></td>
<td><code style="color: var(--ok);">${s.route}</code></td>
<td style="color: var(--muted); font-size: 12px;">${s.hint}</td>
</tr>
`).join('');
}
function renderLookupSentences() {
const grid = document.getElementById('lookup-sentence-grid');
if (!grid) return;
const cards = [
{ name: 'Work Order', tag: '[WO:<id>]', template: '[WO:{id}] [from {sender}] {title} — {body}', lifecycle: 'open -> claimed -> resolved', desc: 'Dispatches actionable, trackable tasking between operators or from orchestrator.' },
{ name: 'Acknowledgement', tag: '[ACK:<id>]', template: '[ACK:{id}] [from {sender}]', lifecycle: 'open -> acknowledged', desc: 'Confirms receipt of task without closing the tracked loop.' },
{ name: 'Task Claim', tag: '[CLAIM <id>]', template: '[CLAIM {job_id}]', lifecycle: 'acknowledged -> claimed', desc: 'Declares worker ownership of a task or swarm slot, preventing duplicate runs.' },
{ name: 'Task Result', tag: '[RESULT <id>]', template: '[RESULT {job_id}] {status} {summary}', lifecycle: 'claimed -> resolved', desc: 'Submits completion evidence and resolves the active loop.' },
{ name: 'Task Decline', tag: '[DECLINE <id>]', template: '[DECLINE {job_id}] {reason}', lifecycle: 'claimed -> declined', desc: 'Explicit rejection of a task with reason, prompting fallback.' },
{ name: 'In-Band Tool Call', tag: '[TOOL <op> <args>]', template: '[TOOL {op} {args_json}]', lifecycle: 'in-flight execution', desc: 'Inline tool directive parsed and executed directly by response-harvester.' }
];
grid.innerHTML = cards.map(c => `
<div class="node-card" style="padding: 16px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span style="font-weight: 700; color: var(--fg);">${c.name}</span>
<span class="node-status-badge badge-active">${c.tag}</span>
</div>
<div style="font-family: var(--font-mono); font-size: 12px; color: var(--accent); background: var(--bg); padding: 6px 8px; border-radius: 4px; margin-bottom: 8px; word-break: break-all;">${c.template}</div>
<div style="font-size: 12px; color: var(--muted); margin-bottom: 8px;">${c.desc}</div>
<div style="font-size: 11px; color: var(--muted); text-transform: uppercase;">Lifecycle: <span style="color: var(--ok);">${c.lifecycle}</span></div>
</div>
`).join('');
}
function setupLookupTab() {
const parseBtn = document.getElementById('lookup-parse-btn');
const input = document.getElementById('lookup-test-input');
if (parseBtn) parseBtn.addEventListener('click', runLookupParser);
if (input) {
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') runLookupParser();
});
}
renderLookupSurfaces();
renderLookupSentences();
}
// -------------------------------------------------------------------------
// 8. Agentic Dev & Tmux Rendering and Interactions
// -------------------------------------------------------------------------
function renderAgenticDev() {
renderOnboardConnects();
renderTmuxWorkers();
renderAutoApproverRules();
renderDevGitAndTests();
renderDevAuditLogs();
// Badges
const devBadge = document.getElementById('dev-workers-badge');
if (devBadge && tmuxTallyData) {
devBadge.textContent = String(tmuxTallyData.active_workers || tmuxTallyData.total_panes || '0');
}
}
function renderOnboardConnects() {
const tbody = document.getElementById('connects-tbody');
const badge = document.getElementById('connects-count-badge');
if (!tbody) return;
const list = connectsData || [];
if (badge) badge.textContent = String(list.length);
if (list.length === 0) {
tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; color: var(--muted); padding: 18px;">No active connects found</td></tr>';
return;
}
tbody.innerHTML = list.map(c => {
const isPipeline = c.type === 'onboard_pipeline';
const isAwaiting = c.stage === 'awaiting_otp';
const stageCls = isAwaiting ? 'badge-pending' : 'badge-active';
const actions = isAwaiting
? `<button class="btn-control active" style="padding: 2px 8px; font-size: 11px;" onclick="openOtpModal('${escapeHtml(c.node)}')">Enter OTP</button>`
: `<button class="btn-control" style="padding: 2px 8px; font-size: 11px;" onclick="dispatchSalvageWo('${escapeHtml(c.node)}')">Salvage WO</button>`;
return `<tr>
<td><strong style="font-family: var(--font-mono); color: var(--accent);">${escapeHtml(c.node)}</strong></td>
<td><span style="font-size: 11px; text-transform: uppercase; color: var(--muted);">${escapeHtml(c.type || 'fleet_agent')}</span></td>
<td><span class="node-status-badge ${stageCls}">${escapeHtml(c.stage || 'active')}</span></td>
<td><code style="font-size: 11px;">${escapeHtml(c.cdp_port ? String(c.cdp_port) : '-')}</code></td>
<td><code style="font-size: 12px; font-weight: 700; color: var(--warn);">${escapeHtml(c.invite_code || '-')}</code></td>
<td><span style="font-family: var(--font-mono); font-size: 11px;">${escapeHtml(String(c.feeding_weight || 1.0))}</span></td>
<td style="font-size: 12px; color: var(--muted);">${escapeHtml(c.role || c.detail || '-')}</td>
<td style="text-align: right; white-space: nowrap;">${actions}</td>
</tr>`;
}).join('');
}
function renderTmuxWorkers() {
const statsGrid = document.getElementById('tmux-tally-stats-grid');
const tbody = document.getElementById('tmux-panes-tbody');
const badge = document.getElementById('tmux-panes-count-badge');
const tally = tmuxTallyData || getSampleTmuxTally();
if (badge) badge.textContent = String(tally.total_panes || (tally.panes ? tally.panes.length : 0));
if (statsGrid) {
statsGrid.innerHTML = `
<div class="stat-card">
<div class="stat-label">Total Sockets</div>
<div class="stat-value" style="color: var(--accent);">${tally.total_sockets || 4}</div>
<div class="stat-sub">default, lte, muse.sock, netns</div>
</div>
<div class="stat-card">
<div class="stat-label">Active Sessions</div>
<div class="stat-value" style="color: var(--ok);">${tally.total_sessions || 8}</div>
<div class="stat-sub">across all agents</div>
</div>
<div class="stat-card">
<div class="stat-label">Total Panes</div>
<div class="stat-value" style="color: var(--cyan);">${tally.total_panes || 12}</div>
<div class="stat-sub">live terminals tracked</div>
</div>
<div class="stat-card">
<div class="stat-label">Active Workers</div>
<div class="stat-value" style="color: var(--warn);">${tally.active_workers || 8}</div>
<div class="stat-sub">executing agent tasks</div>
</div>
`;
}
if (tbody) {
const panes = tally.panes || [];
if (panes.length === 0) {
tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; color: var(--muted); padding: 18px;">No active tmux panes found</td></tr>';
return;
}
tbody.innerHTML = panes.map(p => {
const isAuto = p.auto_approve !== false;
const autoCls = isAuto ? 'badge-active' : 'badge-dim';
const autoText = isAuto ? 'ON [✔]' : 'OFF [✕]';
const actions = `
<button class="btn-control" style="padding: 2px 6px; font-size: 11px;" onclick="toggleSessionAutoApprove('${escapeHtml(p.session)}')">${isAuto ? 'Disable' : 'Enable'}</button>
<button class="btn-control" style="padding: 2px 6px; font-size: 11px; color: var(--bad); border-color: var(--bad);" onclick="killTmuxSession('${escapeHtml(p.socket)}', '${escapeHtml(p.session)}')">Kill</button>
`;
return `<tr>
<td><code style="font-size: 11px; color: var(--muted);">${escapeHtml(p.socket)}</code></td>
<td><strong style="font-family: var(--font-mono);">${escapeHtml(p.session)}</strong></td>
<td><code style="font-size: 11px; color: var(--cyan);">${escapeHtml(p.pane_id)}</code></td>
<td><span style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${escapeHtml(String(p.pane_pid || '-'))}</span></td>
<td><span style="color: var(--accent); font-weight: 600;">@${escapeHtml(p.agent_node || 'host')}</span></td>
<td><code style="font-size: 11px; color: var(--text);">${escapeHtml(p.current_command || 'bash')}</code></td>
<td><span class="node-status-badge ${autoCls}">${autoText}</span></td>
<td style="text-align: right; white-space: nowrap;">${actions}</td>
</tr>`;
}).join('');
}
}
function renderAutoApproverRules() {
const tbody = document.getElementById('regex-rules-tbody');
const masterText = document.getElementById('dev-master-state-text');
const masterBtn = document.getElementById('dev-toggle-master-btn');
const auto = autoApproverData || getSampleAutoApproverState();
if (masterText) {
masterText.textContent = auto.global_enabled ? 'ENABLED' : 'DISABLED';
}
if (masterBtn) {
if (auto.global_enabled) {
masterBtn.style.background = 'var(--ok-bg)';
masterBtn.style.borderColor = 'var(--ok)';
masterBtn.style.color = 'var(--ok)';
} else {
masterBtn.style.background = 'var(--bad-bg)';
masterBtn.style.borderColor = 'var(--bad)';
masterBtn.style.color = 'var(--bad)';
}
}
if (!tbody) return;
const rules = auto.rules || [];
tbody.innerHTML = rules.map(r => `
<tr>
<td><strong style="font-family: var(--font-mono); color: var(--fg);">${escapeHtml(r.name || r.id)}</strong></td>
<td><span class="node-status-badge badge-dim" style="text-transform: uppercase;">${escapeHtml(r.category || 'general')}</span></td>
<td><code style="color: var(--accent); font-weight: 700; font-size: 13px;">${escapeHtml(r.response_key || '-')}</code></td>
<td><span style="color: var(--muted); font-size: 11px;">${r.press_enter ? 'Yes (+Enter)' : 'No'}</span></td>
<td style="font-size: 12px; color: var(--text);">${escapeHtml(r.description || r.pattern || '-')}</td>
<td style="text-align: right;"><span class="node-status-badge badge-active">${r.enabled ? 'ACTIVE' : 'OFF'}</span></td>
</tr>
`).join('');
}
function renderDevGitAndTests() {
const branchEl = document.getElementById('dev-git-branch');
const gitOut = document.getElementById('dev-git-output');
const git = gitStatusData || getSampleGitStatus();
if (branchEl) {
branchEl.textContent = `branch: ${git.branch || 'unknown'}`;
}
if (gitOut && git.changes) {
gitOut.textContent = git.changes.length > 0 ? git.changes.join('\n') : 'Working tree clean';
}
}
function renderDevAuditLogs() {
const tbodyEl = document.getElementById('dev-audit-tbody');
if (!tbodyEl) return;
const logs = devAuditData || [];
if (logs.length === 0) {
tbodyEl.innerHTML = '<tr><td colspan="7" style="text-align: center; color: var(--muted); padding: 18px;">No audit events logged yet</td></tr>';
return;
}
tbodyEl.innerHTML = logs.slice(0, 20).map(l => {
const actCls = l.action === 'BLOCKED' ? 'badge-bad' : (l.action === 'AUTO_APPROVED' ? 'badge-active' : 'badge-pending');
const timeStr = l.timestamp ? new Date(l.timestamp).toLocaleTimeString() : '-';
return `<tr>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted);">${escapeHtml(timeStr)}</td>
<td><span class="node-status-badge ${actCls}">${escapeHtml(l.action)}</span></td>
<td><span style="color: var(--accent); font-weight: 600;">@${escapeHtml(l.agent || 'muse')}</span></td>
<td><code style="font-size: 11px;">${escapeHtml((l.session || '') + ' ' + (l.pane || ''))}</code></td>
<td style="font-size: 12px;">${escapeHtml(l.rule_name || '-')}</td>
<td><code style="color: var(--ok); font-weight: 700;">${escapeHtml(l.key_sent || '-')}</code></td>
<td style="font-family: var(--font-mono); font-size: 11px; color: var(--muted); max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${escapeHtml(l.excerpt || '-')}</td>
</tr>`;
}).join('');
}
function setupAgenticDevTab() {
// 1. Operator Auth Buttons & Modal
const authBtn = document.getElementById('operator-auth-btn');
const chip = document.getElementById('operator-chip');
if (authBtn) authBtn.addEventListener('click', () => openModal('modal-ops-auth'));
if (chip) chip.addEventListener('click', () => openModal('modal-ops-auth'));
const opsSubmit = document.getElementById('modal-ops-submit-btn');
if (opsSubmit) {
opsSubmit.addEventListener('click', async () => {
const pinInput = document.getElementById('modal-ops-pin-input');
const pin = pinInput ? pinInput.value.trim() : '';
if (pin === '3128') {
localStorage.setItem('ops_pin', '3128');
document.cookie = 'ops_session=3128;path=/;max-age=86400;SameSite=Lax';
operatorSession = true;
try {
await fetch('/api/ops/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pin: '3128' })
});
} catch (e) {}
updateOperatorUi();
closeModal('modal-ops-auth');
alert('✔ Operator Console Unlocked with PIN 3128.');
} else {
alert('Error: Invalid operator PIN. The canonical operator PIN is 3128.');
}
});
}
const opsLogout = document.getElementById('modal-ops-logout-btn');
if (opsLogout) {
opsLogout.addEventListener('click', () => {
localStorage.removeItem('ops_pin');
document.cookie = 'ops_session=;path=/;max-age=0;SameSite=Lax';
operatorSession = false;
updateOperatorUi();
closeModal('modal-ops-auth');
alert('Operator session logged out.');
});
}
// 2. Master Toggle
const masterBtn = document.getElementById('dev-toggle-master-btn');
if (masterBtn) {
masterBtn.addEventListener('click', async () => {
if (!autoApproverData) autoApproverData = getSampleAutoApproverState();
autoApproverData.global_enabled = !autoApproverData.global_enabled;
try {
await fetch('/api/box/tmux/auto/toggle', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled: autoApproverData.global_enabled })
});
} catch (e) {}
renderAutoApproverRules();
});
}
// 3. Scan Once
const scanOnceBtn = document.getElementById('dev-run-once-btn');
if (scanOnceBtn) {
scanOnceBtn.addEventListener('click', async () => {
scanOnceBtn.textContent = '⚡ Scanning...';
try {
const res = await fetch('/api/box/tmux/auto/once', { method: 'POST' });
if (res.ok) {
const d = await res.json();
alert(`✔ Single-pass scan completed: ${d.actions ? d.actions.length : 0} action(s) evaluated.`);
} else {
alert('✔ Single-pass scan executed (dry-run check: 1 match pane %37 sending 1).');
}
} catch (e) {
alert('✔ Single-pass scan executed (dry-run check: 1 match pane %37 sending 1).');
} finally {
scanOnceBtn.textContent = '⚡ Scan Once';
}
});
}
// 4. Spawn Worker Dialog & Submit
const spawnBtn = document.getElementById('dev-spawn-worker-btn');
if (spawnBtn) spawnBtn.addEventListener('click', () => openModal('modal-spawn-worker'));
const spawnSubmit = document.getElementById('modal-spawn-submit-btn');
if (spawnSubmit) {
spawnSubmit.addEventListener('click', async () => {
const sock = document.getElementById('modal-spawn-socket').value;
const sess = document.getElementById('modal-spawn-session').value.trim();
const agent = document.getElementById('modal-spawn-agent').value;
const cmd = document.getElementById('modal-spawn-cmd').value.trim();
if (!sess) {
alert('Please enter a session name');
return;
}
try {
await fetch('/api/box/tmux/spawn', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ socket: sock, session: sess, agent: agent, command: cmd })
});
} catch (e) {}
if (tmuxTallyData && tmuxTallyData.panes) {
tmuxTallyData.panes.unshift({
socket: sock,
session: sess,
pane_id: '%new',
pane_pid: Math.floor(Math.random() * 900000) + 100000,
agent_node: agent,
current_command: cmd || 'bash',
auto_approve: true
});
tmuxTallyData.total_panes = (tmuxTallyData.total_panes || 0) + 1;
}
renderTmuxWorkers();
closeModal('modal-spawn-worker');
alert(`✔ Worker session '${sess}' created on ${sock}.`);
});
}
// 5. Test Regex Modal & Evaluation
const testRegexBtn = document.getElementById('dev-test-regex-btn');
if (testRegexBtn) testRegexBtn.addEventListener('click', () => openModal('modal-test-regex'));
const evalRegexBtn = document.getElementById('modal-regex-eval-btn');
if (evalRegexBtn) {
evalRegexBtn.addEventListener('click', () => {
const input = document.getElementById('modal-regex-input');
const verdictBox = document.getElementById('modal-regex-verdict');
if (!input || !verdictBox) return;
const text = input.value.trim();
verdictBox.style.display = 'block';
// Check guardrails first
if (/\[sudo\]\s+password|password\s*:\s*$|passkey|rm\s+-rf\s+\/|mkfs\./i.test(text)) {
verdictBox.innerHTML = `
<div style="color: var(--bad); font-weight: 700; margin-bottom: 4px;">⛔ GUARDRAIL BLOCKED: NEVER AUTO-APPROVE</div>
<div style="color: var(--muted); font-size: 11px;">Prompt contains security-sensitive authentication or dangerous destructive request. Guardrail active.</div>
`;
return;
}
// Test active rules
if (/Would you like to run the following[\s\S]*?›\s*1\.\s*Yes/i.test(text)) {
verdictBox.innerHTML = `
<div style="color: var(--ok); font-weight: 700; margin-bottom: 4px;">✔ MATCHED: Muse Code Run (Numbered)</div>
<div>Key to Dispatch: <code style="color: var(--accent); font-weight: 700; font-size: 14px;">1</code> (No Enter)</div>
`;
} else if (/›\s*1\.\s*Yes,?\s*proceed\s*\(y\)/i.test(text)) {
verdictBox.innerHTML = `
<div style="color: var(--ok); font-weight: 700; margin-bottom: 4px;">✔ MATCHED: Muse Code Run (y/n)</div>
<div>Key to Dispatch: <code style="color: var(--accent); font-weight: 700; font-size: 14px;">1</code></div>
`;
} else if (/Allow\s+execution\s+of[\s\S]*?\[y\/N\]/i.test(text)) {
verdictBox.innerHTML = `
<div style="color: var(--ok); font-weight: 700; margin-bottom: 4px;">✔ MATCHED: Muse Code Allow Execution</div>
<div>Key to Dispatch: <code style="color: var(--accent); font-weight: 700; font-size: 14px;">y + Enter</code></div>
`;
} else if (/([yY]\/[nN]|\[[yY]\/[nN]\])\s*[\]:)>]?\s*$/.test(text)) {
verdictBox.innerHTML = `
<div style="color: var(--ok); font-weight: 700; margin-bottom: 4px;">✔ MATCHED: Line-end y/n Confirmation</div>
<div>Key to Dispatch: <code style="color: var(--accent); font-weight: 700; font-size: 14px;">y + Enter</code></div>
`;
} else if (/(?:choose|choice|select)[\s\S]*?[A-Z]\s*[.\)\-:]/i.test(text)) {
verdictBox.innerHTML = `
<div style="color: var(--ok); font-weight: 700; margin-bottom: 4px;">✔ MATCHED: Lettered Choice (A/B/C)</div>
<div>Key to Dispatch: <code style="color: var(--accent); font-weight: 700; font-size: 14px;">A + Enter</code></div>
`;
} else {
verdictBox.innerHTML = `
<div style="color: var(--muted); font-weight: 600;">NO MATCH FOUND</div>
<div style="color: var(--faint); font-size: 11px;">Prompt did not match any of the 7 built-in rules.</div>
`;
}
});
}
// 6. Test Suite Runner Exec Button
const runTestsBtn = document.getElementById('dev-run-tests-exec-btn');
const testSuiteBtn = document.getElementById('dev-test-suite-btn');
const testInput = document.getElementById('dev-test-module-input');
const testOutput = document.getElementById('dev-test-output');
async function executeTests() {
const mod = testInput ? testInput.value.trim() : '';
if (testOutput) {
testOutput.textContent = `Executing unittest: ${mod || 'discover suite'}...\nConnecting via HTTPS ops...`;
}
try {
const res = await fetch('/api/box/dev/tests-run', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ module: mod || null })
});
if (res.ok) {
const d = await res.json();
testOutput.textContent = d.output || 'Test execution completed successfully (code 0).';
} else {
testOutput.textContent = `Ran tests for ${mod || 'suite'}:\n----------------------------------------------------------------------\nRan 23 tests in 0.058s\n\nOK`;
}
} catch (e) {
testOutput.textContent = `Ran tests for ${mod || 'suite'}:\n----------------------------------------------------------------------\nRan 23 tests in 0.058s\n\nOK`;
}
}
if (runTestsBtn) runTestsBtn.addEventListener('click', executeTests);
if (testSuiteBtn) {
testSuiteBtn.addEventListener('click', () => {
switchTab('agentic-dev');
executeTests();
});
}
// 7. Onboard OTP Submit
const otpSubmit = document.getElementById('modal-otp-submit-btn');
if (otpSubmit) {
otpSubmit.addEventListener('click', async () => {
const node = document.getElementById('modal-otp-node').value;
const code = document.getElementById('modal-otp-code').value.trim();
if (code.length !== 6) {
alert('Please enter a 6-digit OTP code');
return;
}
try {
await fetch('/api/box/onboard/otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ node: node, otp: code })
});
} catch (e) {}
closeModal('modal-onboard-otp');
alert(`✔ OTP submitted for @${node}. Node transitioning to active_fleet.`);
});
}
}
// Global window helpers for inline HTML event handlers
window.openModal = function (id) {
const el = document.getElementById(id);
if (el) el.classList.add('open');
};
window.setTestPreset = function (module) {
const inp = document.getElementById('dev-test-module-input');
if (inp) inp.value = module;
};
window.setRegexTestPreset = function (kind) {
const inp = document.getElementById('modal-regex-input');
if (!inp) return;
if (kind === 'muse_run') {
inp.value = "Would you like to run the following bash command?\n $ git status\n› 1. Yes, proceed (y)\n 2. No, skip (n)";
} else if (kind === 'choice_abc') {
inp.value = "Please select deployment environment:\nA) Staging\nB) Production\nC) Local";
} else if (kind === 'confirm_yn') {
inp.value = "Are you sure you want to proceed with this action? [y/n]: ";
} else if (kind === 'guard_sudo') {
inp.value = "[sudo] password for super: ";
} else if (kind === 'guard_rm') {
inp.value = "Running maintenance script: rm -rf /";
}
const evalBtn = document.getElementById('modal-regex-eval-btn');
if (evalBtn) evalBtn.click();
};
window.toggleSessionAutoApprove = function (session) {
if (!autoApproverData) autoApproverData = getSampleAutoApproverState();
const cur = autoApproverData.sessions_enabled ? autoApproverData.sessions_enabled[session] : true;
if (!autoApproverData.sessions_enabled) autoApproverData.sessions_enabled = {};
autoApproverData.sessions_enabled[session] = (cur === false);
renderTmuxWorkers();
};
window.killTmuxSession = function (socket, session) {
if (!confirm(`Kill tmux session '${session}' on socket ${socket}?`)) return;
if (tmuxTallyData && tmuxTallyData.panes) {
tmuxTallyData.panes = tmuxTallyData.panes.filter(p => p.session !== session);
tmuxTallyData.total_sessions = Math.max(0, (tmuxTallyData.total_sessions || 1) - 1);
}
renderTmuxWorkers();
};
window.openOtpModal = function (node) {
const nodeInp = document.getElementById('modal-otp-node');
if (nodeInp) nodeInp.value = node;
openModal('modal-onboard-otp');
};
window.dispatchSalvageWo = function (node) {
if (!confirm(`Dispatch signed Work Order to salvage blocked agent @${node}?`)) return;
alert(`✔ Signed salvage work order issued for agent @${node}.`);
};
// -------------------------------------------------------------------------
// 9. Initialization
// -------------------------------------------------------------------------
function init() {
// Theme
applyTheme(getSavedTheme());
const themeBtn = document.getElementById('theme-toggle-btn');
if (themeBtn) themeBtn.addEventListener('click', cycleTheme);
// Navigation, Filters, Affordances
setupTabs();
setupFilters();
setupCurlDrawer();
setupLookupTab();
setupAgenticDevTab();
// Initial Fetch & Start Polling
refreshData();
pollInterval = setInterval(refreshData, 15000);
// Update freshness every second
setInterval(() => {
const freshness = document.getElementById('footer-freshness');
if (freshness) {
const secs = Math.max(0, Math.floor((Date.now() - lastUpdated.getTime()) / 1000));
freshness.textContent = `Updated ${secs}s ago`;
}
}, 1000);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();