thevoidforge 21.0.0 → 21.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wizard/danger-room.config.json +5 -0
- package/dist/wizard/ui/app.js +1231 -0
- package/dist/wizard/ui/danger-room-prophecy.js +217 -0
- package/dist/wizard/ui/danger-room.html +626 -0
- package/dist/wizard/ui/danger-room.js +880 -0
- package/dist/wizard/ui/deploy.html +177 -0
- package/dist/wizard/ui/deploy.js +582 -0
- package/dist/wizard/ui/favicon.svg +11 -0
- package/dist/wizard/ui/index.html +394 -0
- package/dist/wizard/ui/lobby.html +228 -0
- package/dist/wizard/ui/lobby.js +783 -0
- package/dist/wizard/ui/login.html +110 -0
- package/dist/wizard/ui/login.js +184 -0
- package/dist/wizard/ui/rollback.js +107 -0
- package/dist/wizard/ui/styles.css +1029 -0
- package/dist/wizard/ui/tower.html +171 -0
- package/dist/wizard/ui/tower.js +444 -0
- package/dist/wizard/ui/war-room-prophecy.js +217 -0
- package/dist/wizard/ui/war-room.html +219 -0
- package/dist/wizard/ui/war-room.js +285 -0
- package/package.json +2 -2
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prophecy Visualizer — interactive SVG dependency graph for campaign missions.
|
|
3
|
+
*
|
|
4
|
+
* Reads campaign data from /api/war-room/campaign and renders a node/edge graph.
|
|
5
|
+
* Nodes = missions. Edges = dependency order. Color = status.
|
|
6
|
+
* Clickable nodes show mission details.
|
|
7
|
+
*/
|
|
8
|
+
(function () {
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
// ── Constants ─────────────────────────────────
|
|
12
|
+
|
|
13
|
+
var NODE_RADIUS = 24;
|
|
14
|
+
var NODE_SPACING_X = 120;
|
|
15
|
+
var NODE_SPACING_Y = 80;
|
|
16
|
+
var PADDING = 40;
|
|
17
|
+
|
|
18
|
+
var STATUS_COLORS = {
|
|
19
|
+
COMPLETE: '#34d399',
|
|
20
|
+
ACTIVE: '#fbbf24',
|
|
21
|
+
BLOCKED: '#ef4444',
|
|
22
|
+
PENDING: '#555',
|
|
23
|
+
STRUCTURAL: '#6366f1'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
var STATUS_LABELS = {
|
|
27
|
+
COMPLETE: 'Complete',
|
|
28
|
+
ACTIVE: 'In Progress',
|
|
29
|
+
BLOCKED: 'Blocked',
|
|
30
|
+
PENDING: 'Pending',
|
|
31
|
+
STRUCTURAL: 'Structural'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ── SVG helpers ───────────────────────────────
|
|
35
|
+
|
|
36
|
+
function svgEl(tag, attrs) {
|
|
37
|
+
var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
|
38
|
+
if (attrs) {
|
|
39
|
+
for (var key in attrs) {
|
|
40
|
+
if (Object.prototype.hasOwnProperty.call(attrs, key)) {
|
|
41
|
+
el.setAttribute(key, attrs[key]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return el;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function escapeText(str) {
|
|
49
|
+
var div = document.createElement('div');
|
|
50
|
+
div.appendChild(document.createTextNode(str));
|
|
51
|
+
return div.innerHTML;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── Layout ────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
function layoutNodes(missions) {
|
|
57
|
+
// Simple left-to-right grid layout
|
|
58
|
+
var cols = Math.ceil(Math.sqrt(missions.length));
|
|
59
|
+
return missions.map(function (m, i) {
|
|
60
|
+
var col = i % cols;
|
|
61
|
+
var row = Math.floor(i / cols);
|
|
62
|
+
return {
|
|
63
|
+
mission: m,
|
|
64
|
+
x: PADDING + col * NODE_SPACING_X + NODE_RADIUS,
|
|
65
|
+
y: PADDING + row * NODE_SPACING_Y + NODE_RADIUS
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── Rendering ─────────────────────────────────
|
|
71
|
+
|
|
72
|
+
function renderGraph(container, campaignData) {
|
|
73
|
+
container.innerHTML = '';
|
|
74
|
+
|
|
75
|
+
if (!campaignData || !campaignData.missions || campaignData.missions.length === 0) {
|
|
76
|
+
container.innerHTML = '<div style="padding:20px;color:var(--text-dim);font-size:13px;">No campaign data — run /campaign to see the prophecy graph.</div>';
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var nodes = layoutNodes(campaignData.missions);
|
|
81
|
+
var cols = Math.ceil(Math.sqrt(campaignData.missions.length));
|
|
82
|
+
var rows = Math.ceil(campaignData.missions.length / cols);
|
|
83
|
+
var svgWidth = PADDING * 2 + cols * NODE_SPACING_X;
|
|
84
|
+
var svgHeight = PADDING * 2 + rows * NODE_SPACING_Y;
|
|
85
|
+
|
|
86
|
+
var svg = svgEl('svg', {
|
|
87
|
+
viewBox: '0 0 ' + svgWidth + ' ' + svgHeight,
|
|
88
|
+
width: '100%',
|
|
89
|
+
height: Math.min(svgHeight, 400) + 'px',
|
|
90
|
+
role: 'group',
|
|
91
|
+
'aria-label': 'Campaign mission dependency graph'
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Draw edges (sequential dependency: mission N → mission N+1)
|
|
95
|
+
for (var i = 0; i < nodes.length - 1; i++) {
|
|
96
|
+
var from = nodes[i];
|
|
97
|
+
var to = nodes[i + 1];
|
|
98
|
+
var line = svgEl('line', {
|
|
99
|
+
x1: from.x,
|
|
100
|
+
y1: from.y,
|
|
101
|
+
x2: to.x,
|
|
102
|
+
y2: to.y,
|
|
103
|
+
stroke: '#444',
|
|
104
|
+
'stroke-width': '2',
|
|
105
|
+
'stroke-dasharray': '4,4'
|
|
106
|
+
});
|
|
107
|
+
svg.appendChild(line);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Draw nodes
|
|
111
|
+
nodes.forEach(function (node) {
|
|
112
|
+
var m = node.mission;
|
|
113
|
+
var color = STATUS_COLORS[m.status] || STATUS_COLORS.PENDING;
|
|
114
|
+
var label = STATUS_LABELS[m.status] || m.status;
|
|
115
|
+
|
|
116
|
+
// Node group
|
|
117
|
+
var g = svgEl('g', {
|
|
118
|
+
'data-mission': m.number,
|
|
119
|
+
style: 'cursor:pointer',
|
|
120
|
+
role: 'button',
|
|
121
|
+
tabindex: '0',
|
|
122
|
+
'aria-label': 'Mission ' + m.number + ': ' + escapeText(m.name) + ' — ' + label
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Circle
|
|
126
|
+
var circle = svgEl('circle', {
|
|
127
|
+
cx: node.x,
|
|
128
|
+
cy: node.y,
|
|
129
|
+
r: NODE_RADIUS,
|
|
130
|
+
fill: color,
|
|
131
|
+
opacity: '0.2',
|
|
132
|
+
stroke: color,
|
|
133
|
+
'stroke-width': '2'
|
|
134
|
+
});
|
|
135
|
+
g.appendChild(circle);
|
|
136
|
+
|
|
137
|
+
// Mission number
|
|
138
|
+
var text = svgEl('text', {
|
|
139
|
+
x: node.x,
|
|
140
|
+
y: node.y + 1,
|
|
141
|
+
'text-anchor': 'middle',
|
|
142
|
+
'dominant-baseline': 'central',
|
|
143
|
+
fill: color,
|
|
144
|
+
'font-size': '14',
|
|
145
|
+
'font-weight': '700'
|
|
146
|
+
});
|
|
147
|
+
text.textContent = m.number;
|
|
148
|
+
g.appendChild(text);
|
|
149
|
+
|
|
150
|
+
// Mission name label (below node)
|
|
151
|
+
var nameText = svgEl('text', {
|
|
152
|
+
x: node.x,
|
|
153
|
+
y: node.y + NODE_RADIUS + 14,
|
|
154
|
+
'text-anchor': 'middle',
|
|
155
|
+
fill: '#999',
|
|
156
|
+
'font-size': '9'
|
|
157
|
+
});
|
|
158
|
+
// Truncate long names
|
|
159
|
+
var displayName = m.name.length > 18 ? m.name.substring(0, 16) + '…' : m.name;
|
|
160
|
+
nameText.textContent = displayName;
|
|
161
|
+
g.appendChild(nameText);
|
|
162
|
+
|
|
163
|
+
// Status dot
|
|
164
|
+
var statusDot = svgEl('circle', {
|
|
165
|
+
cx: node.x + NODE_RADIUS - 4,
|
|
166
|
+
cy: node.y - NODE_RADIUS + 4,
|
|
167
|
+
r: '4',
|
|
168
|
+
fill: color
|
|
169
|
+
});
|
|
170
|
+
g.appendChild(statusDot);
|
|
171
|
+
|
|
172
|
+
// Focus indicator — highlight circle on keyboard focus
|
|
173
|
+
g.addEventListener('focus', function () { circle.setAttribute('stroke-width', '4'); });
|
|
174
|
+
g.addEventListener('blur', function () { circle.setAttribute('stroke-width', '2'); });
|
|
175
|
+
|
|
176
|
+
// Click handler — show details in the detail panel
|
|
177
|
+
g.addEventListener('click', function () { showDetail(m); });
|
|
178
|
+
g.addEventListener('keydown', function (e) {
|
|
179
|
+
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); showDetail(m); }
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
svg.appendChild(g);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
container.appendChild(svg);
|
|
186
|
+
|
|
187
|
+
// Legend
|
|
188
|
+
var legend = document.createElement('div');
|
|
189
|
+
legend.style.cssText = 'display:flex;gap:12px;margin-top:8px;font-size:10px;color:var(--text-dim);flex-wrap:wrap;';
|
|
190
|
+
Object.keys(STATUS_COLORS).forEach(function (status) {
|
|
191
|
+
var item = document.createElement('span');
|
|
192
|
+
item.innerHTML = '<span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:' +
|
|
193
|
+
STATUS_COLORS[status] + ';margin-right:4px;vertical-align:middle;"></span>' +
|
|
194
|
+
(STATUS_LABELS[status] || status);
|
|
195
|
+
legend.appendChild(item);
|
|
196
|
+
});
|
|
197
|
+
container.appendChild(legend);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ── Detail panel ──────────────────────────────
|
|
201
|
+
|
|
202
|
+
function showDetail(mission) {
|
|
203
|
+
var panel = document.getElementById('prophecy-detail');
|
|
204
|
+
if (!panel) return;
|
|
205
|
+
var color = STATUS_COLORS[mission.status] || STATUS_COLORS.PENDING;
|
|
206
|
+
var label = STATUS_LABELS[mission.status] || escapeText(mission.status);
|
|
207
|
+
panel.innerHTML =
|
|
208
|
+
'<div style="font-weight:700;color:' + color + ';">Mission ' + escapeText(String(mission.number)) + '</div>' +
|
|
209
|
+
'<div style="margin:4px 0;font-size:13px;">' + escapeText(mission.name) + '</div>' +
|
|
210
|
+
'<div style="font-size:11px;color:var(--text-dim);">Status: ' + label + '</div>';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ── Init ──────────────────────────────────────
|
|
214
|
+
|
|
215
|
+
// Expose render function for the main war-room.js to call
|
|
216
|
+
window.renderProphecyGraph = renderGraph;
|
|
217
|
+
})();
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>War Room — VoidForge</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
|
8
|
+
<link rel="stylesheet" href="styles.css">
|
|
9
|
+
<style>
|
|
10
|
+
body { min-height: 100vh; display: flex; flex-direction: column; background: var(--bg); color: var(--text); }
|
|
11
|
+
|
|
12
|
+
/* War Room Layout */
|
|
13
|
+
.war-room { display: grid; grid-template-columns: 1fr 280px; grid-template-rows: auto 1fr auto; height: 100vh; }
|
|
14
|
+
.war-room-header { grid-column: 1 / -1; padding: 12px 20px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
|
|
15
|
+
.war-room-title { font-size: 16px; font-weight: 700; color: var(--accent); }
|
|
16
|
+
.war-room-version { font-size: 12px; color: var(--text-dim); }
|
|
17
|
+
.war-room-nav { display: flex; gap: 8px; }
|
|
18
|
+
.war-room-nav a { color: var(--text-dim); text-decoration: none; font-size: 13px; padding: 4px 10px; border-radius: 4px; }
|
|
19
|
+
.war-room-nav a:hover { background: var(--bg-card); color: var(--text); }
|
|
20
|
+
|
|
21
|
+
/* Main Panel Area */
|
|
22
|
+
.main-panels { padding: 16px; overflow-y: auto; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-content: start; }
|
|
23
|
+
|
|
24
|
+
/* Sidebar */
|
|
25
|
+
.sidebar { border-left: 1px solid var(--border); padding: 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
|
|
26
|
+
|
|
27
|
+
/* Panel Card */
|
|
28
|
+
.panel { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px; }
|
|
29
|
+
.panel-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); margin-bottom: 8px; }
|
|
30
|
+
.panel-full { grid-column: 1 / -1; }
|
|
31
|
+
|
|
32
|
+
/* Campaign Timeline */
|
|
33
|
+
.timeline { display: flex; gap: 4px; flex-wrap: wrap; }
|
|
34
|
+
.timeline-item { width: 28px; height: 28px; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; }
|
|
35
|
+
.timeline-complete { background: #065f46; color: #34d399; }
|
|
36
|
+
.timeline-active { background: #713f12; color: #fbbf24; animation: pulse 2s infinite; }
|
|
37
|
+
.timeline-pending { background: var(--bg); color: var(--text-dim); border: 1px solid var(--border); }
|
|
38
|
+
.timeline-blocked { background: #7f1d1d; color: #fca5a5; }
|
|
39
|
+
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
|
|
40
|
+
|
|
41
|
+
/* Phase Pipeline */
|
|
42
|
+
.pipeline { display: flex; flex-direction: column; gap: 3px; }
|
|
43
|
+
.pipeline-phase { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 3px 0; }
|
|
44
|
+
.pipeline-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
|
45
|
+
.pipeline-dot.complete { background: #34d399; }
|
|
46
|
+
.pipeline-dot.active { background: #fbbf24; animation: pulse 2s infinite; }
|
|
47
|
+
.pipeline-dot.pending { background: var(--border); }
|
|
48
|
+
.pipeline-dot.skipped { background: var(--text-dim); opacity: 0.5; }
|
|
49
|
+
.pipeline-label { color: var(--text-dim); }
|
|
50
|
+
|
|
51
|
+
/* Finding Scoreboard */
|
|
52
|
+
.scoreboard { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
|
|
53
|
+
.score-item { text-align: center; padding: 8px 4px; border-radius: 4px; }
|
|
54
|
+
.score-critical { background: #7f1d1d; }
|
|
55
|
+
.score-high { background: #713f12; }
|
|
56
|
+
.score-medium { background: #1e3a5f; }
|
|
57
|
+
.score-low { background: #1a2e1a; }
|
|
58
|
+
.score-count { font-size: 20px; font-weight: 700; }
|
|
59
|
+
.score-label { font-size: 9px; text-transform: uppercase; color: var(--text-dim); margin-top: 2px; }
|
|
60
|
+
|
|
61
|
+
/* Context Gauge */
|
|
62
|
+
.gauge { position: relative; width: 80px; height: 80px; margin: 0 auto; }
|
|
63
|
+
.gauge svg { width: 80px; height: 80px; transform: rotate(-90deg); }
|
|
64
|
+
.gauge-track { fill: none; stroke: var(--border); stroke-width: 6; }
|
|
65
|
+
.gauge-fill { fill: none; stroke-width: 6; stroke-linecap: round; transition: stroke-dashoffset 0.5s, stroke 0.5s; }
|
|
66
|
+
.gauge-text { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; }
|
|
67
|
+
|
|
68
|
+
/* Agent Activity Ticker */
|
|
69
|
+
.ticker { grid-column: 1 / -1; border-top: 1px solid var(--border); padding: 6px 20px; font-size: 11px; color: var(--text-dim); overflow: hidden; white-space: nowrap; }
|
|
70
|
+
.ticker-item { display: inline; margin-right: 24px; }
|
|
71
|
+
.ticker-agent { color: var(--accent); font-weight: 600; }
|
|
72
|
+
|
|
73
|
+
/* Deploy Status */
|
|
74
|
+
.deploy-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
|
|
75
|
+
.deploy-dot { width: 8px; height: 8px; border-radius: 50%; }
|
|
76
|
+
.deploy-dot.live { background: #34d399; }
|
|
77
|
+
.deploy-dot.down { background: #ef4444; }
|
|
78
|
+
.deploy-dot.unknown { background: var(--border); }
|
|
79
|
+
|
|
80
|
+
/* Version Badge */
|
|
81
|
+
.version-badge { font-size: 13px; font-weight: 600; color: var(--accent); }
|
|
82
|
+
.branch-status { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
|
|
83
|
+
|
|
84
|
+
/* Focus management */
|
|
85
|
+
a:focus-visible, .panel:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
|
|
86
|
+
|
|
87
|
+
/* Responsive — stack on narrow viewports */
|
|
88
|
+
@media (max-width: 700px) {
|
|
89
|
+
.war-room { grid-template-columns: 1fr; }
|
|
90
|
+
.sidebar { border-left: none; border-top: 1px solid var(--border); }
|
|
91
|
+
.main-panels { grid-template-columns: 1fr; }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Reduced motion */
|
|
95
|
+
@media (prefers-reduced-motion: reduce) {
|
|
96
|
+
.timeline-active, .pipeline-dot.active { animation: none; }
|
|
97
|
+
}
|
|
98
|
+
</style>
|
|
99
|
+
</head>
|
|
100
|
+
<body>
|
|
101
|
+
<a href="#war-room-grid" class="skip-nav">Skip to main content</a>
|
|
102
|
+
<noscript><div class="noscript-msg">VoidForge requires JavaScript to run.</div></noscript>
|
|
103
|
+
<div class="war-room">
|
|
104
|
+
<!-- Header -->
|
|
105
|
+
<header class="war-room-header">
|
|
106
|
+
<div>
|
|
107
|
+
<div class="war-room-title">War Room</div>
|
|
108
|
+
<div class="war-room-version" id="version-display">VoidForge v—</div>
|
|
109
|
+
</div>
|
|
110
|
+
<nav class="war-room-nav" aria-label="War Room navigation">
|
|
111
|
+
<a href="lobby.html">Lobby</a>
|
|
112
|
+
<a href="war-room.html" aria-current="page" style="background:var(--bg-card);color:var(--text);">War Room</a>
|
|
113
|
+
</nav>
|
|
114
|
+
</header>
|
|
115
|
+
|
|
116
|
+
<!-- Main Panels -->
|
|
117
|
+
<main class="main-panels" id="war-room-grid">
|
|
118
|
+
<!-- Campaign Timeline -->
|
|
119
|
+
<div class="panel panel-full" role="region" aria-label="Campaign Timeline">
|
|
120
|
+
<h2 class="panel-title" id="title-timeline">Campaign Timeline</h2>
|
|
121
|
+
<div class="timeline" id="campaign-timeline" aria-labelledby="title-timeline">
|
|
122
|
+
<div class="timeline-item timeline-pending">—</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<!-- Phase Pipeline -->
|
|
127
|
+
<div class="panel" role="region" aria-label="Phase Pipeline">
|
|
128
|
+
<h2 class="panel-title" id="title-pipeline">Phase Pipeline</h2>
|
|
129
|
+
<div class="pipeline" id="phase-pipeline">
|
|
130
|
+
<div class="pipeline-phase"><span class="pipeline-dot pending"></span><span class="pipeline-label">No active build</span></div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<!-- Finding Scoreboard -->
|
|
135
|
+
<div class="panel" role="region" aria-label="Finding Scoreboard">
|
|
136
|
+
<h2 class="panel-title" id="title-findings">Findings</h2>
|
|
137
|
+
<div class="scoreboard" id="finding-scoreboard" aria-labelledby="title-findings" role="group">
|
|
138
|
+
<div class="score-item score-critical"><div class="score-count" id="score-critical">0</div><div class="score-label">Critical</div></div>
|
|
139
|
+
<div class="score-item score-high"><div class="score-count" id="score-high">0</div><div class="score-label">High</div></div>
|
|
140
|
+
<div class="score-item score-medium"><div class="score-count" id="score-medium">0</div><div class="score-label">Medium</div></div>
|
|
141
|
+
<div class="score-item score-low"><div class="score-count" id="score-low">0</div><div class="score-label">Low</div></div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<!-- Experiment Dashboard -->
|
|
146
|
+
<div class="panel" role="region" aria-label="Experiments">
|
|
147
|
+
<h2 class="panel-title" id="title-experiments">Experiments</h2>
|
|
148
|
+
<div id="experiment-dashboard" aria-labelledby="title-experiments" style="font-size:13px;color:var(--text-dim);">No experiments</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<!-- PRD Coverage -->
|
|
152
|
+
<div class="panel panel-full" role="region" aria-label="PRD Coverage">
|
|
153
|
+
<h2 class="panel-title" id="title-prd">PRD Coverage</h2>
|
|
154
|
+
<div id="prd-coverage" style="font-size:13px;color:var(--text-dim);">No campaign active</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<!-- Prophecy Graph -->
|
|
158
|
+
<div class="panel panel-full" role="region" aria-label="Prophecy Graph">
|
|
159
|
+
<h2 class="panel-title" id="title-prophecy">Prophecy Graph</h2>
|
|
160
|
+
<div id="prophecy-graph" style="min-height:100px;"></div>
|
|
161
|
+
<div id="prophecy-detail" style="font-size:12px;margin-top:6px;min-height:40px;color:var(--text-dim);"></div>
|
|
162
|
+
</div>
|
|
163
|
+
</main>
|
|
164
|
+
|
|
165
|
+
<!-- Sidebar -->
|
|
166
|
+
<aside class="sidebar">
|
|
167
|
+
<!-- Context Gauge -->
|
|
168
|
+
<div class="panel">
|
|
169
|
+
<h2 class="panel-title">Context Usage</h2>
|
|
170
|
+
<div class="gauge" id="context-gauge" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-label="Context usage">
|
|
171
|
+
<svg viewBox="0 0 36 36" role="img" aria-hidden="true">
|
|
172
|
+
<circle class="gauge-track" cx="18" cy="18" r="14" />
|
|
173
|
+
<circle class="gauge-fill" cx="18" cy="18" r="14"
|
|
174
|
+
stroke-dasharray="88" stroke-dashoffset="88"
|
|
175
|
+
id="gauge-fill" stroke="#34d399" />
|
|
176
|
+
</svg>
|
|
177
|
+
<div class="gauge-text" id="gauge-text" aria-live="polite">—%</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<!-- Version & Branch -->
|
|
182
|
+
<div class="panel">
|
|
183
|
+
<h2 class="panel-title">Version</h2>
|
|
184
|
+
<div class="version-badge" id="version-badge">—</div>
|
|
185
|
+
<div class="branch-status" id="branch-status">—</div>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<!-- Deploy Status -->
|
|
189
|
+
<div class="panel">
|
|
190
|
+
<h2 class="panel-title">Deploy</h2>
|
|
191
|
+
<div class="deploy-badge" id="deploy-status">
|
|
192
|
+
<span class="deploy-dot unknown"></span>
|
|
193
|
+
<span>No deploy data</span>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<!-- Test Suite -->
|
|
198
|
+
<div class="panel">
|
|
199
|
+
<h2 class="panel-title">Tests</h2>
|
|
200
|
+
<div id="test-status" style="font-size:13px;color:var(--text-dim);">No test data</div>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<!-- Cost -->
|
|
204
|
+
<div class="panel">
|
|
205
|
+
<h2 class="panel-title">Cost</h2>
|
|
206
|
+
<div id="cost-display" style="font-size:13px;color:var(--text-dim);">No cost data</div>
|
|
207
|
+
</div>
|
|
208
|
+
</aside>
|
|
209
|
+
|
|
210
|
+
<!-- Agent Activity Ticker -->
|
|
211
|
+
<footer class="ticker" id="agent-ticker" aria-live="polite" aria-label="Agent activity feed">
|
|
212
|
+
<span class="ticker-item"><span class="ticker-agent">Sisko</span> standing by...</span>
|
|
213
|
+
</footer>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<script src="war-room-prophecy.js"></script>
|
|
217
|
+
<script src="war-room.js"></script>
|
|
218
|
+
</body>
|
|
219
|
+
</html>
|