shipwright-cli 1.7.1 → 1.9.0
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/.claude/agents/code-reviewer.md +90 -0
- package/.claude/agents/devops-engineer.md +142 -0
- package/.claude/agents/pipeline-agent.md +80 -0
- package/.claude/agents/shell-script-specialist.md +150 -0
- package/.claude/agents/test-specialist.md +196 -0
- package/.claude/hooks/post-tool-use.sh +38 -0
- package/.claude/hooks/pre-tool-use.sh +25 -0
- package/.claude/hooks/session-started.sh +37 -0
- package/README.md +212 -814
- package/claude-code/CLAUDE.md.shipwright +54 -0
- package/claude-code/hooks/notify-idle.sh +2 -2
- package/claude-code/hooks/session-start.sh +24 -0
- package/claude-code/hooks/task-completed.sh +6 -2
- package/claude-code/settings.json.template +12 -0
- package/dashboard/public/app.js +4422 -0
- package/dashboard/public/index.html +816 -0
- package/dashboard/public/styles.css +4755 -0
- package/dashboard/server.ts +4315 -0
- package/docs/KNOWN-ISSUES.md +18 -10
- package/docs/TIPS.md +38 -26
- package/docs/patterns/README.md +33 -23
- package/package.json +9 -5
- package/scripts/adapters/iterm2-adapter.sh +1 -1
- package/scripts/adapters/tmux-adapter.sh +52 -23
- package/scripts/adapters/wezterm-adapter.sh +26 -14
- package/scripts/lib/compat.sh +200 -0
- package/scripts/lib/helpers.sh +72 -0
- package/scripts/postinstall.mjs +72 -13
- package/scripts/{cct → sw} +109 -21
- package/scripts/sw-adversarial.sh +274 -0
- package/scripts/sw-architecture-enforcer.sh +330 -0
- package/scripts/sw-checkpoint.sh +390 -0
- package/scripts/{cct-cleanup.sh → sw-cleanup.sh} +3 -1
- package/scripts/sw-connect.sh +619 -0
- package/scripts/{cct-cost.sh → sw-cost.sh} +368 -34
- package/scripts/{cct-daemon.sh → sw-daemon.sh} +2217 -204
- package/scripts/sw-dashboard.sh +477 -0
- package/scripts/sw-developer-simulation.sh +252 -0
- package/scripts/sw-docs.sh +635 -0
- package/scripts/sw-doctor.sh +907 -0
- package/scripts/{cct-fix.sh → sw-fix.sh} +10 -6
- package/scripts/{cct-fleet.sh → sw-fleet.sh} +498 -22
- package/scripts/sw-github-checks.sh +521 -0
- package/scripts/sw-github-deploy.sh +533 -0
- package/scripts/sw-github-graphql.sh +972 -0
- package/scripts/sw-heartbeat.sh +293 -0
- package/scripts/{cct-init.sh → sw-init.sh} +144 -11
- package/scripts/sw-intelligence.sh +1196 -0
- package/scripts/sw-jira.sh +643 -0
- package/scripts/sw-launchd.sh +364 -0
- package/scripts/sw-linear.sh +648 -0
- package/scripts/{cct-logs.sh → sw-logs.sh} +72 -2
- package/scripts/{cct-loop.sh → sw-loop.sh} +534 -44
- package/scripts/{cct-memory.sh → sw-memory.sh} +321 -38
- package/scripts/sw-patrol-meta.sh +417 -0
- package/scripts/sw-pipeline-composer.sh +455 -0
- package/scripts/{cct-pipeline.sh → sw-pipeline.sh} +2319 -178
- package/scripts/sw-predictive.sh +820 -0
- package/scripts/{cct-prep.sh → sw-prep.sh} +339 -49
- package/scripts/{cct-ps.sh → sw-ps.sh} +6 -4
- package/scripts/{cct-reaper.sh → sw-reaper.sh} +6 -4
- package/scripts/sw-remote.sh +687 -0
- package/scripts/sw-self-optimize.sh +947 -0
- package/scripts/sw-session.sh +519 -0
- package/scripts/sw-setup.sh +234 -0
- package/scripts/sw-status.sh +605 -0
- package/scripts/{cct-templates.sh → sw-templates.sh} +9 -4
- package/scripts/sw-tmux.sh +591 -0
- package/scripts/sw-tracker-jira.sh +277 -0
- package/scripts/sw-tracker-linear.sh +292 -0
- package/scripts/sw-tracker.sh +409 -0
- package/scripts/{cct-upgrade.sh → sw-upgrade.sh} +103 -46
- package/scripts/{cct-worktree.sh → sw-worktree.sh} +3 -0
- package/templates/pipelines/autonomous.json +27 -5
- package/templates/pipelines/full.json +12 -0
- package/templates/pipelines/standard.json +12 -0
- package/tmux/{claude-teams-overlay.conf → shipwright-overlay.conf} +27 -9
- package/tmux/templates/accessibility.json +34 -0
- package/tmux/templates/api-design.json +35 -0
- package/tmux/templates/architecture.json +1 -0
- package/tmux/templates/bug-fix.json +9 -0
- package/tmux/templates/code-review.json +1 -0
- package/tmux/templates/compliance.json +36 -0
- package/tmux/templates/data-pipeline.json +36 -0
- package/tmux/templates/debt-paydown.json +34 -0
- package/tmux/templates/devops.json +1 -0
- package/tmux/templates/documentation.json +1 -0
- package/tmux/templates/exploration.json +1 -0
- package/tmux/templates/feature-dev.json +1 -0
- package/tmux/templates/full-stack.json +8 -0
- package/tmux/templates/i18n.json +34 -0
- package/tmux/templates/incident-response.json +36 -0
- package/tmux/templates/migration.json +1 -0
- package/tmux/templates/observability.json +35 -0
- package/tmux/templates/onboarding.json +33 -0
- package/tmux/templates/performance.json +35 -0
- package/tmux/templates/refactor.json +1 -0
- package/tmux/templates/release.json +35 -0
- package/tmux/templates/security-audit.json +8 -0
- package/tmux/templates/spike.json +34 -0
- package/tmux/templates/testing.json +1 -0
- package/tmux/tmux.conf +98 -9
- package/scripts/cct-doctor.sh +0 -414
- package/scripts/cct-session.sh +0 -284
- package/scripts/cct-status.sh +0 -169
|
@@ -0,0 +1,816 @@
|
|
|
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>Fleet Command — Shipwright</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link
|
|
10
|
+
href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500;700&family=Plus+Jakarta+Sans:wght@300;400;500;600;700&display=swap"
|
|
11
|
+
rel="stylesheet"
|
|
12
|
+
/>
|
|
13
|
+
<link rel="stylesheet" href="styles.css" />
|
|
14
|
+
<link
|
|
15
|
+
rel="icon"
|
|
16
|
+
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text y='28' font-size='28'>⚓</text></svg>"
|
|
17
|
+
/>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<!-- Header -->
|
|
21
|
+
<header class="header" id="header">
|
|
22
|
+
<div class="header-left">
|
|
23
|
+
<svg
|
|
24
|
+
class="header-icon"
|
|
25
|
+
viewBox="0 0 28 28"
|
|
26
|
+
width="28"
|
|
27
|
+
height="28"
|
|
28
|
+
fill="none"
|
|
29
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
30
|
+
>
|
|
31
|
+
<defs>
|
|
32
|
+
<linearGradient
|
|
33
|
+
id="ship-grad"
|
|
34
|
+
x1="0"
|
|
35
|
+
y1="0"
|
|
36
|
+
x2="28"
|
|
37
|
+
y2="28"
|
|
38
|
+
gradientUnits="userSpaceOnUse"
|
|
39
|
+
>
|
|
40
|
+
<stop offset="0%" stop-color="#00d4ff" />
|
|
41
|
+
<stop offset="50%" stop-color="#0066ff" />
|
|
42
|
+
<stop offset="100%" stop-color="#7c3aed" />
|
|
43
|
+
</linearGradient>
|
|
44
|
+
</defs>
|
|
45
|
+
<path
|
|
46
|
+
d="M14 2L4 22h4l2-4h8l2 4h4L14 2zm0 6l3.5 8h-7L14 8z"
|
|
47
|
+
fill="url(#ship-grad)"
|
|
48
|
+
/>
|
|
49
|
+
<path
|
|
50
|
+
d="M2 24c2-2 5-2 7 0s5 2 7 0 5-2 7 0"
|
|
51
|
+
stroke="url(#ship-grad)"
|
|
52
|
+
stroke-width="1.5"
|
|
53
|
+
fill="none"
|
|
54
|
+
stroke-linecap="round"
|
|
55
|
+
/>
|
|
56
|
+
</svg>
|
|
57
|
+
<span class="header-title">Fleet Command</span>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="header-center" id="connection">
|
|
60
|
+
<span class="connection-dot offline" id="connection-dot"></span>
|
|
61
|
+
<span class="connection-text" id="connection-text">OFFLINE</span>
|
|
62
|
+
<span class="cost-ticker" id="cost-ticker"></span>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="header-right">
|
|
65
|
+
<button
|
|
66
|
+
class="emergency-brake-btn"
|
|
67
|
+
id="emergency-brake"
|
|
68
|
+
style="display: none"
|
|
69
|
+
title="Emergency Brake — Pause All"
|
|
70
|
+
>
|
|
71
|
+
<svg
|
|
72
|
+
viewBox="0 0 24 24"
|
|
73
|
+
width="18"
|
|
74
|
+
height="18"
|
|
75
|
+
fill="none"
|
|
76
|
+
stroke="currentColor"
|
|
77
|
+
stroke-width="2"
|
|
78
|
+
>
|
|
79
|
+
<circle cx="12" cy="12" r="10" />
|
|
80
|
+
<rect x="8" y="8" width="8" height="8" rx="1" fill="currentColor" />
|
|
81
|
+
</svg>
|
|
82
|
+
</button>
|
|
83
|
+
<div class="user-menu" id="user-menu">
|
|
84
|
+
<button class="user-avatar" id="user-avatar" aria-label="User menu">
|
|
85
|
+
<span class="avatar-initials" id="avatar-initials">?</span>
|
|
86
|
+
</button>
|
|
87
|
+
<div class="user-dropdown" id="user-dropdown">
|
|
88
|
+
<div class="dropdown-username" id="dropdown-username">—</div>
|
|
89
|
+
<a class="dropdown-link" href="/auth/logout">Sign out</a>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</header>
|
|
94
|
+
|
|
95
|
+
<!-- Tab Navigation -->
|
|
96
|
+
<nav class="tab-bar" id="tab-bar">
|
|
97
|
+
<div class="tab-bar-inner">
|
|
98
|
+
<button class="tab-btn active" data-tab="overview">Overview</button>
|
|
99
|
+
<button class="tab-btn" data-tab="agents">Agents</button>
|
|
100
|
+
<button class="tab-btn" data-tab="pipelines">Pipelines</button>
|
|
101
|
+
<button class="tab-btn" data-tab="timeline">Timeline</button>
|
|
102
|
+
<button class="tab-btn" data-tab="activity">Activity</button>
|
|
103
|
+
<button class="tab-btn" data-tab="metrics">Metrics</button>
|
|
104
|
+
<button class="tab-btn" data-tab="machines">Machines</button>
|
|
105
|
+
<button class="tab-btn" data-tab="insights">Insights</button>
|
|
106
|
+
<button class="tab-btn" data-tab="team">Team</button>
|
|
107
|
+
<div class="tab-indicator" id="tab-indicator"></div>
|
|
108
|
+
</div>
|
|
109
|
+
</nav>
|
|
110
|
+
|
|
111
|
+
<!-- Alert Banner -->
|
|
112
|
+
<div class="alert-banner" id="alert-banner" style="display: none">
|
|
113
|
+
<div class="alert-banner-inner">
|
|
114
|
+
<span class="alert-icon" id="alert-icon"></span>
|
|
115
|
+
<span class="alert-message" id="alert-message"></span>
|
|
116
|
+
<div class="alert-actions" id="alert-actions"></div>
|
|
117
|
+
<button class="alert-dismiss" id="alert-dismiss" aria-label="Dismiss">
|
|
118
|
+
×
|
|
119
|
+
</button>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- Main Content -->
|
|
124
|
+
<main class="main" id="main-content">
|
|
125
|
+
<!-- ═══ OVERVIEW TAB ═══ -->
|
|
126
|
+
<div class="tab-panel active" id="panel-overview">
|
|
127
|
+
<!-- Stats Row -->
|
|
128
|
+
<section class="stats-row" id="stats-row">
|
|
129
|
+
<div class="stat-card">
|
|
130
|
+
<span class="stat-label">STATUS</span>
|
|
131
|
+
<div class="stat-value-row">
|
|
132
|
+
<span class="pulse-dot offline" id="status-dot"></span>
|
|
133
|
+
<span class="stat-value" id="stat-status">OFFLINE</span>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="stat-card">
|
|
137
|
+
<span class="stat-label">ACTIVE</span>
|
|
138
|
+
<div class="stat-value gradient-text" id="stat-active">0 / 0</div>
|
|
139
|
+
<div class="stat-bar-track">
|
|
140
|
+
<div class="stat-bar-fill" id="stat-active-bar"></div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
<div class="stat-card">
|
|
144
|
+
<span class="stat-label">QUEUE</span>
|
|
145
|
+
<div class="stat-value" id="stat-queue">0</div>
|
|
146
|
+
<div class="stat-subtitle" id="stat-queue-sub">issues waiting</div>
|
|
147
|
+
</div>
|
|
148
|
+
<div class="stat-card">
|
|
149
|
+
<span class="stat-label">COMPLETED</span>
|
|
150
|
+
<div class="stat-value gradient-text" id="stat-completed">0</div>
|
|
151
|
+
<div class="stat-subtitle" id="stat-failed-sub">0 failed</div>
|
|
152
|
+
</div>
|
|
153
|
+
</section>
|
|
154
|
+
|
|
155
|
+
<!-- Daemon Control Bar -->
|
|
156
|
+
<div class="daemon-control-bar" id="daemon-control-bar">
|
|
157
|
+
<div class="daemon-control-status">
|
|
158
|
+
<span class="daemon-status-badge" id="daemon-status-badge"
|
|
159
|
+
>Unknown</span
|
|
160
|
+
>
|
|
161
|
+
<span class="daemon-status-label">Daemon</span>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="daemon-control-actions">
|
|
164
|
+
<button
|
|
165
|
+
class="btn btn-sm btn-start"
|
|
166
|
+
id="daemon-btn-start"
|
|
167
|
+
onclick="daemonControl('start')"
|
|
168
|
+
title="Start daemon"
|
|
169
|
+
>
|
|
170
|
+
Start
|
|
171
|
+
</button>
|
|
172
|
+
<button
|
|
173
|
+
class="btn btn-sm btn-stop"
|
|
174
|
+
id="daemon-btn-stop"
|
|
175
|
+
onclick="daemonControl('stop')"
|
|
176
|
+
title="Stop daemon"
|
|
177
|
+
>
|
|
178
|
+
Stop
|
|
179
|
+
</button>
|
|
180
|
+
<button
|
|
181
|
+
class="btn btn-sm btn-pause"
|
|
182
|
+
id="daemon-btn-pause"
|
|
183
|
+
onclick="daemonControl('pause')"
|
|
184
|
+
title="Pause/Resume daemon"
|
|
185
|
+
>
|
|
186
|
+
Pause
|
|
187
|
+
</button>
|
|
188
|
+
<button
|
|
189
|
+
class="btn btn-sm btn-patrol"
|
|
190
|
+
id="daemon-btn-patrol"
|
|
191
|
+
onclick="daemonControl('patrol')"
|
|
192
|
+
title="Run patrol now"
|
|
193
|
+
>
|
|
194
|
+
Run Patrol
|
|
195
|
+
</button>
|
|
196
|
+
</div>
|
|
197
|
+
<div class="daemon-control-info" id="daemon-control-info">
|
|
198
|
+
<span class="daemon-info-item"
|
|
199
|
+
><strong>Workers:</strong>
|
|
200
|
+
<span id="daemon-info-workers">-</span></span
|
|
201
|
+
>
|
|
202
|
+
<span class="daemon-info-item"
|
|
203
|
+
><strong>Poll:</strong>
|
|
204
|
+
<span id="daemon-info-poll">-</span>s</span
|
|
205
|
+
>
|
|
206
|
+
<span class="daemon-info-item"
|
|
207
|
+
><strong>Patrol:</strong>
|
|
208
|
+
<span id="daemon-info-patrol">-</span>s</span
|
|
209
|
+
>
|
|
210
|
+
<span class="daemon-info-item"
|
|
211
|
+
><strong>Budget:</strong> $<span id="daemon-info-budget"
|
|
212
|
+
>-</span
|
|
213
|
+
></span
|
|
214
|
+
>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<!-- Active Pipelines -->
|
|
219
|
+
<section class="section">
|
|
220
|
+
<h2 class="section-label">ACTIVE PIPELINES</h2>
|
|
221
|
+
<div id="active-pipelines">
|
|
222
|
+
<div class="empty-state">
|
|
223
|
+
<svg
|
|
224
|
+
class="empty-icon"
|
|
225
|
+
viewBox="0 0 24 24"
|
|
226
|
+
width="32"
|
|
227
|
+
height="32"
|
|
228
|
+
fill="none"
|
|
229
|
+
stroke="currentColor"
|
|
230
|
+
stroke-width="1.5"
|
|
231
|
+
>
|
|
232
|
+
<path d="M12 6v6l4 2M12 2a10 10 0 100 20 10 10 0 000-20z" />
|
|
233
|
+
</svg>
|
|
234
|
+
<p>No active pipelines</p>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</section>
|
|
238
|
+
|
|
239
|
+
<!-- Queue Section -->
|
|
240
|
+
<section class="section">
|
|
241
|
+
<h2 class="section-label">AWAITING DEPLOYMENT</h2>
|
|
242
|
+
<div id="queue-list">
|
|
243
|
+
<div class="empty-state"><p>Queue clear</p></div>
|
|
244
|
+
</div>
|
|
245
|
+
</section>
|
|
246
|
+
|
|
247
|
+
<!-- Two-column layout: Activity + Resources -->
|
|
248
|
+
<div class="bottom-grid">
|
|
249
|
+
<!-- Activity Feed (compact, recent 10) -->
|
|
250
|
+
<section class="section">
|
|
251
|
+
<h2 class="section-label">ACTIVITY</h2>
|
|
252
|
+
<div class="activity-feed" id="activity-feed">
|
|
253
|
+
<div class="empty-state"><p>Awaiting events...</p></div>
|
|
254
|
+
</div>
|
|
255
|
+
</section>
|
|
256
|
+
|
|
257
|
+
<!-- Resource Scaling -->
|
|
258
|
+
<section class="section">
|
|
259
|
+
<h2 class="section-label">RESOURCE SCALING</h2>
|
|
260
|
+
<div class="resources-panel" id="resources-panel">
|
|
261
|
+
<div class="resource-row">
|
|
262
|
+
<span class="resource-label">CPU</span>
|
|
263
|
+
<div class="resource-bar-track">
|
|
264
|
+
<div class="resource-bar-fill" id="res-cpu-bar"></div>
|
|
265
|
+
</div>
|
|
266
|
+
<span class="resource-info" id="res-cpu-info">—</span>
|
|
267
|
+
</div>
|
|
268
|
+
<div class="resource-row">
|
|
269
|
+
<span class="resource-label">MEM</span>
|
|
270
|
+
<div class="resource-bar-track">
|
|
271
|
+
<div class="resource-bar-fill" id="res-mem-bar"></div>
|
|
272
|
+
</div>
|
|
273
|
+
<span class="resource-info" id="res-mem-info">—</span>
|
|
274
|
+
</div>
|
|
275
|
+
<div class="resource-row">
|
|
276
|
+
<span class="resource-label">BUDGET</span>
|
|
277
|
+
<div class="resource-bar-track">
|
|
278
|
+
<div class="resource-bar-fill" id="res-budget-bar"></div>
|
|
279
|
+
</div>
|
|
280
|
+
<span class="resource-info" id="res-budget-info">—</span>
|
|
281
|
+
</div>
|
|
282
|
+
<div class="resource-constraint" id="resource-constraint">
|
|
283
|
+
<span class="constraint-badge nominal">NOMINAL</span>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</section>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<!-- Machines (only shown if registered) -->
|
|
290
|
+
<section class="section" id="machines-section" style="display: none">
|
|
291
|
+
<h2 class="section-label">MACHINES</h2>
|
|
292
|
+
<div class="machines-grid" id="machines-grid"></div>
|
|
293
|
+
</section>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<!-- ═══ AGENTS TAB ═══ -->
|
|
297
|
+
<div class="tab-panel" id="panel-agents">
|
|
298
|
+
<div class="agents-grid" id="agents-grid">
|
|
299
|
+
<div class="empty-state"><p>No active agents</p></div>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<!-- ═══ PIPELINES TAB ═══ -->
|
|
304
|
+
<div class="tab-panel" id="panel-pipelines">
|
|
305
|
+
<!-- Filter bar -->
|
|
306
|
+
<div class="filter-bar" id="pipeline-filters">
|
|
307
|
+
<button class="filter-chip active" data-filter="all">All</button>
|
|
308
|
+
<button class="filter-chip" data-filter="active">Active</button>
|
|
309
|
+
<button class="filter-chip" data-filter="completed">Completed</button>
|
|
310
|
+
<button class="filter-chip" data-filter="failed">Failed</button>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<div class="bulk-actions" id="bulk-actions" style="display: none">
|
|
314
|
+
<span class="bulk-count" id="bulk-count">0 selected</span>
|
|
315
|
+
<button class="bulk-btn" id="bulk-pause">Pause Selected</button>
|
|
316
|
+
<button class="bulk-btn" id="bulk-resume">Resume Selected</button>
|
|
317
|
+
<button class="bulk-btn bulk-btn-danger" id="bulk-abort">
|
|
318
|
+
Abort Selected
|
|
319
|
+
</button>
|
|
320
|
+
</div>
|
|
321
|
+
|
|
322
|
+
<!-- Pipeline table -->
|
|
323
|
+
<div class="pipeline-table-wrap">
|
|
324
|
+
<table class="pipeline-table" id="pipeline-table">
|
|
325
|
+
<thead>
|
|
326
|
+
<tr>
|
|
327
|
+
<th>
|
|
328
|
+
<input
|
|
329
|
+
type="checkbox"
|
|
330
|
+
id="pipeline-select-all"
|
|
331
|
+
class="pipeline-checkbox"
|
|
332
|
+
/>
|
|
333
|
+
</th>
|
|
334
|
+
<th>Issue</th>
|
|
335
|
+
<th>Title</th>
|
|
336
|
+
<th>Status</th>
|
|
337
|
+
<th>Stage</th>
|
|
338
|
+
<th>Duration</th>
|
|
339
|
+
<th>Branch</th>
|
|
340
|
+
</tr>
|
|
341
|
+
</thead>
|
|
342
|
+
<tbody id="pipeline-table-body">
|
|
343
|
+
<tr>
|
|
344
|
+
<td colspan="7" class="empty-state"><p>No pipeline data</p></td>
|
|
345
|
+
</tr>
|
|
346
|
+
</tbody>
|
|
347
|
+
</table>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<!-- Pipeline detail panel (hidden until row click) -->
|
|
351
|
+
<div class="pipeline-detail-panel" id="pipeline-detail-panel">
|
|
352
|
+
<div class="detail-panel-header">
|
|
353
|
+
<h3 class="detail-panel-title" id="detail-panel-title">
|
|
354
|
+
Pipeline Detail
|
|
355
|
+
</h3>
|
|
356
|
+
<button
|
|
357
|
+
class="detail-panel-close"
|
|
358
|
+
id="detail-panel-close"
|
|
359
|
+
aria-label="Close detail panel"
|
|
360
|
+
>
|
|
361
|
+
×
|
|
362
|
+
</button>
|
|
363
|
+
</div>
|
|
364
|
+
<div class="detail-panel-body" id="detail-panel-body">
|
|
365
|
+
<!-- Populated dynamically -->
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
</div>
|
|
369
|
+
|
|
370
|
+
<!-- ═══ TIMELINE TAB ═══ -->
|
|
371
|
+
<div class="tab-panel" id="panel-timeline">
|
|
372
|
+
<div class="timeline-controls">
|
|
373
|
+
<select class="timeline-range-select" id="timeline-range">
|
|
374
|
+
<option value="6">Last 6 hours</option>
|
|
375
|
+
<option value="24" selected>Last 24 hours</option>
|
|
376
|
+
<option value="72">Last 3 days</option>
|
|
377
|
+
<option value="168">Last 7 days</option>
|
|
378
|
+
</select>
|
|
379
|
+
</div>
|
|
380
|
+
<div class="gantt-chart" id="gantt-chart">
|
|
381
|
+
<div class="empty-state"><p>No timeline data</p></div>
|
|
382
|
+
</div>
|
|
383
|
+
</div>
|
|
384
|
+
|
|
385
|
+
<!-- ═══ ACTIVITY TAB ═══ -->
|
|
386
|
+
<div class="tab-panel" id="panel-activity">
|
|
387
|
+
<!-- Filter chips -->
|
|
388
|
+
<div class="filter-bar" id="activity-filters">
|
|
389
|
+
<button class="filter-chip active" data-filter="all">All</button>
|
|
390
|
+
<button class="filter-chip" data-filter="spawn">Spawn</button>
|
|
391
|
+
<button class="filter-chip" data-filter="stage">Stage</button>
|
|
392
|
+
<button class="filter-chip" data-filter="completed">Complete</button>
|
|
393
|
+
<button class="filter-chip" data-filter="failed">Failed</button>
|
|
394
|
+
<button class="filter-chip" data-filter="scale">Scale</button>
|
|
395
|
+
<button class="filter-chip" data-filter="poll">Poll</button>
|
|
396
|
+
<div class="filter-issue-input">
|
|
397
|
+
<input
|
|
398
|
+
type="text"
|
|
399
|
+
id="activity-issue-filter"
|
|
400
|
+
placeholder="Filter by issue #"
|
|
401
|
+
class="issue-filter-input"
|
|
402
|
+
/>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
|
|
406
|
+
<!-- Activity timeline -->
|
|
407
|
+
<div class="activity-timeline" id="activity-timeline">
|
|
408
|
+
<div class="empty-state"><p>Loading activity...</p></div>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
<!-- Load more button -->
|
|
412
|
+
<div
|
|
413
|
+
class="load-more-wrap"
|
|
414
|
+
id="activity-load-more"
|
|
415
|
+
style="display: none"
|
|
416
|
+
>
|
|
417
|
+
<button class="load-more-btn" id="load-more-btn">Load more</button>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
|
|
421
|
+
<!-- ═══ METRICS TAB ═══ -->
|
|
422
|
+
<div class="tab-panel" id="panel-metrics">
|
|
423
|
+
<div class="metrics-grid" id="metrics-grid">
|
|
424
|
+
<!-- Top row: big numbers -->
|
|
425
|
+
<div class="metrics-top-row">
|
|
426
|
+
<div class="metric-card metric-card-lg">
|
|
427
|
+
<span class="metric-label">SUCCESS RATE</span>
|
|
428
|
+
<div id="metric-donut-wrap" class="donut-wrap">
|
|
429
|
+
<div class="donut" id="metric-donut" style="--pct: 0%">
|
|
430
|
+
<span class="donut-value" id="metric-success-rate">—</span>
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
433
|
+
</div>
|
|
434
|
+
<div class="metric-card metric-card-lg">
|
|
435
|
+
<span class="metric-label">AVG DURATION</span>
|
|
436
|
+
<div class="metric-big-value" id="metric-avg-duration">—</div>
|
|
437
|
+
<span class="metric-sub">per pipeline</span>
|
|
438
|
+
</div>
|
|
439
|
+
<div class="metric-card metric-card-lg">
|
|
440
|
+
<span class="metric-label">THROUGHPUT</span>
|
|
441
|
+
<div class="metric-big-value" id="metric-throughput">—</div>
|
|
442
|
+
<span class="metric-sub">issues / hour</span>
|
|
443
|
+
</div>
|
|
444
|
+
<div class="metric-card metric-card-lg">
|
|
445
|
+
<span class="metric-label">TOTAL</span>
|
|
446
|
+
<div
|
|
447
|
+
class="metric-big-value gradient-text"
|
|
448
|
+
id="metric-total-completed"
|
|
449
|
+
>
|
|
450
|
+
—
|
|
451
|
+
</div>
|
|
452
|
+
<span class="metric-sub" id="metric-total-failed">0 failed</span>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
<!-- Stage duration breakdown -->
|
|
457
|
+
<div class="metric-card metric-card-wide">
|
|
458
|
+
<span class="metric-label">STAGE DURATION BREAKDOWN</span>
|
|
459
|
+
<div class="stage-breakdown" id="stage-breakdown">
|
|
460
|
+
<div class="empty-state"><p>No data</p></div>
|
|
461
|
+
</div>
|
|
462
|
+
</div>
|
|
463
|
+
|
|
464
|
+
<!-- Daily activity chart -->
|
|
465
|
+
<div class="metric-card metric-card-wide">
|
|
466
|
+
<span class="metric-label">DAILY ACTIVITY</span>
|
|
467
|
+
<div class="daily-chart-wrap" id="daily-chart">
|
|
468
|
+
<div class="empty-state"><p>No data</p></div>
|
|
469
|
+
</div>
|
|
470
|
+
</div>
|
|
471
|
+
|
|
472
|
+
<!-- DORA Grades -->
|
|
473
|
+
<div
|
|
474
|
+
class="metric-card metric-card-wide"
|
|
475
|
+
id="dora-grades-container"
|
|
476
|
+
style="display: none"
|
|
477
|
+
>
|
|
478
|
+
<span class="metric-label">DORA GRADES</span>
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
|
|
483
|
+
<!-- ═══ MACHINES TAB ═══ -->
|
|
484
|
+
<div class="tab-panel" id="panel-machines">
|
|
485
|
+
<!-- Summary row -->
|
|
486
|
+
<div class="machines-summary" id="machines-summary"></div>
|
|
487
|
+
|
|
488
|
+
<!-- Action bar -->
|
|
489
|
+
<div class="machines-actions">
|
|
490
|
+
<button class="btn-primary" id="btn-add-machine">
|
|
491
|
+
+ Add Machine
|
|
492
|
+
</button>
|
|
493
|
+
<button class="btn-secondary" id="btn-join-link">
|
|
494
|
+
Generate Join Link
|
|
495
|
+
</button>
|
|
496
|
+
</div>
|
|
497
|
+
|
|
498
|
+
<!-- Machine cards grid -->
|
|
499
|
+
<div class="machines-grid" id="machines-tab-grid">
|
|
500
|
+
<div class="empty-state"><p>No machines registered</p></div>
|
|
501
|
+
</div>
|
|
502
|
+
|
|
503
|
+
<!-- Active join tokens -->
|
|
504
|
+
<section class="section" id="join-tokens-section" style="display: none">
|
|
505
|
+
<h2 class="section-label">ACTIVE JOIN LINKS</h2>
|
|
506
|
+
<div id="join-tokens-list"></div>
|
|
507
|
+
</section>
|
|
508
|
+
</div>
|
|
509
|
+
|
|
510
|
+
<!-- ═══ INSIGHTS TAB ═══ -->
|
|
511
|
+
<div class="tab-panel" id="panel-insights">
|
|
512
|
+
<div class="insights-grid">
|
|
513
|
+
<!-- Failure Patterns -->
|
|
514
|
+
<section class="section">
|
|
515
|
+
<h2 class="section-label">FAILURE PATTERNS</h2>
|
|
516
|
+
<div id="failure-patterns">
|
|
517
|
+
<div class="empty-state"><p>Loading patterns...</p></div>
|
|
518
|
+
</div>
|
|
519
|
+
</section>
|
|
520
|
+
|
|
521
|
+
<!-- Patrol Findings -->
|
|
522
|
+
<section class="section">
|
|
523
|
+
<h2 class="section-label">PATROL FINDINGS</h2>
|
|
524
|
+
<div id="patrol-findings">
|
|
525
|
+
<div class="empty-state"><p>No patrol data</p></div>
|
|
526
|
+
</div>
|
|
527
|
+
</section>
|
|
528
|
+
|
|
529
|
+
<!-- Decision Log -->
|
|
530
|
+
<section class="section">
|
|
531
|
+
<h2 class="section-label">DECISION LOG</h2>
|
|
532
|
+
<div id="decision-log">
|
|
533
|
+
<div class="empty-state"><p>No decisions recorded</p></div>
|
|
534
|
+
</div>
|
|
535
|
+
</section>
|
|
536
|
+
|
|
537
|
+
<!-- Failure Heatmap -->
|
|
538
|
+
<section class="section">
|
|
539
|
+
<h2 class="section-label">FAILURE HEATMAP</h2>
|
|
540
|
+
<div id="failure-heatmap">
|
|
541
|
+
<div class="empty-state"><p>No data</p></div>
|
|
542
|
+
</div>
|
|
543
|
+
</section>
|
|
544
|
+
</div>
|
|
545
|
+
</div>
|
|
546
|
+
|
|
547
|
+
<!-- ═══ TEAM TAB ═══ -->
|
|
548
|
+
<div class="tab-panel" id="panel-team">
|
|
549
|
+
<!-- Team Stats Bar -->
|
|
550
|
+
<section class="team-stats-bar" id="team-stats-bar">
|
|
551
|
+
<div class="team-stat">
|
|
552
|
+
<span class="team-stat-label">DEVELOPERS ONLINE</span>
|
|
553
|
+
<div class="team-stat-value gradient-text" id="team-stat-online">
|
|
554
|
+
0
|
|
555
|
+
</div>
|
|
556
|
+
</div>
|
|
557
|
+
<div class="team-stat">
|
|
558
|
+
<span class="team-stat-label">ACTIVE PIPELINES</span>
|
|
559
|
+
<div class="team-stat-value" id="team-stat-pipelines">0</div>
|
|
560
|
+
</div>
|
|
561
|
+
<div class="team-stat">
|
|
562
|
+
<span class="team-stat-label">TOTAL QUEUED</span>
|
|
563
|
+
<div class="team-stat-value" id="team-stat-queued">0</div>
|
|
564
|
+
</div>
|
|
565
|
+
</section>
|
|
566
|
+
|
|
567
|
+
<!-- Developer Cards -->
|
|
568
|
+
<section class="section-header">
|
|
569
|
+
<h2 class="section-label">CONNECTED DEVELOPERS</h2>
|
|
570
|
+
</section>
|
|
571
|
+
<div class="team-grid" id="team-grid">
|
|
572
|
+
<div class="empty-state">
|
|
573
|
+
No developers connected. Run
|
|
574
|
+
<code>shipwright connect start</code> to join.
|
|
575
|
+
</div>
|
|
576
|
+
</div>
|
|
577
|
+
|
|
578
|
+
<!-- Team Activity Feed -->
|
|
579
|
+
<section class="section-header" style="margin-top: 2rem">
|
|
580
|
+
<h2 class="section-label">TEAM ACTIVITY</h2>
|
|
581
|
+
</section>
|
|
582
|
+
<div class="team-activity" id="team-activity">
|
|
583
|
+
<div class="empty-state">No team activity yet.</div>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
</main>
|
|
587
|
+
|
|
588
|
+
<!-- Footer -->
|
|
589
|
+
<footer class="footer">
|
|
590
|
+
<span>Shipwright Fleet Command v1.7.1</span>
|
|
591
|
+
<span>Dashboard refreshes via WebSocket</span>
|
|
592
|
+
</footer>
|
|
593
|
+
|
|
594
|
+
<!-- Intervention Modal -->
|
|
595
|
+
<div class="modal-overlay" id="intervention-modal" style="display: none">
|
|
596
|
+
<div class="modal-card">
|
|
597
|
+
<div class="modal-header">
|
|
598
|
+
<h3 class="modal-title" id="modal-title">Send Message</h3>
|
|
599
|
+
<button class="modal-close" id="modal-close">×</button>
|
|
600
|
+
</div>
|
|
601
|
+
<div class="modal-body">
|
|
602
|
+
<textarea
|
|
603
|
+
class="modal-textarea"
|
|
604
|
+
id="modal-message"
|
|
605
|
+
placeholder="Type a message for the agent..."
|
|
606
|
+
rows="4"
|
|
607
|
+
></textarea>
|
|
608
|
+
</div>
|
|
609
|
+
<div class="modal-footer">
|
|
610
|
+
<button class="modal-btn modal-btn-cancel" id="modal-cancel">
|
|
611
|
+
Cancel
|
|
612
|
+
</button>
|
|
613
|
+
<button class="modal-btn modal-btn-send" id="modal-send">Send</button>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
|
|
618
|
+
<!-- Emergency Brake Modal -->
|
|
619
|
+
<div class="modal-overlay" id="emergency-modal" style="display: none">
|
|
620
|
+
<div class="modal-card">
|
|
621
|
+
<div class="modal-header">
|
|
622
|
+
<h3 class="modal-title">Emergency Brake</h3>
|
|
623
|
+
<button class="modal-close" id="emergency-modal-close">
|
|
624
|
+
×
|
|
625
|
+
</button>
|
|
626
|
+
</div>
|
|
627
|
+
<div class="modal-body">
|
|
628
|
+
<p class="emergency-warning">
|
|
629
|
+
This will pause
|
|
630
|
+
<strong id="emergency-active-count">0</strong> active pipelines and
|
|
631
|
+
<strong id="emergency-queue-count">0</strong> queued items.
|
|
632
|
+
</p>
|
|
633
|
+
</div>
|
|
634
|
+
<div class="modal-footer">
|
|
635
|
+
<button class="modal-btn modal-btn-cancel" id="emergency-cancel">
|
|
636
|
+
Cancel
|
|
637
|
+
</button>
|
|
638
|
+
<button class="modal-btn modal-btn-danger" id="emergency-confirm">
|
|
639
|
+
Pause Everything
|
|
640
|
+
</button>
|
|
641
|
+
</div>
|
|
642
|
+
</div>
|
|
643
|
+
</div>
|
|
644
|
+
|
|
645
|
+
<!-- Add Machine Modal -->
|
|
646
|
+
<div class="modal-overlay" id="add-machine-modal" style="display: none">
|
|
647
|
+
<div class="modal-card modal-wide">
|
|
648
|
+
<div class="modal-header">
|
|
649
|
+
<h3 class="modal-title">Register Machine</h3>
|
|
650
|
+
<button class="modal-close" id="machine-modal-close">×</button>
|
|
651
|
+
</div>
|
|
652
|
+
<div class="modal-body">
|
|
653
|
+
<div class="form-row">
|
|
654
|
+
<div class="form-group">
|
|
655
|
+
<label class="form-label" for="machine-name">Name</label>
|
|
656
|
+
<input
|
|
657
|
+
type="text"
|
|
658
|
+
id="machine-name"
|
|
659
|
+
class="form-input"
|
|
660
|
+
placeholder="e.g. build-server-1"
|
|
661
|
+
/>
|
|
662
|
+
</div>
|
|
663
|
+
<div class="form-group">
|
|
664
|
+
<label class="form-label" for="machine-host">Host</label>
|
|
665
|
+
<input
|
|
666
|
+
type="text"
|
|
667
|
+
id="machine-host"
|
|
668
|
+
class="form-input"
|
|
669
|
+
placeholder="e.g. 10.0.1.5 or localhost"
|
|
670
|
+
/>
|
|
671
|
+
</div>
|
|
672
|
+
</div>
|
|
673
|
+
<div class="form-row">
|
|
674
|
+
<div class="form-group">
|
|
675
|
+
<label class="form-label" for="machine-ssh-user">SSH User</label>
|
|
676
|
+
<input
|
|
677
|
+
type="text"
|
|
678
|
+
id="machine-ssh-user"
|
|
679
|
+
class="form-input"
|
|
680
|
+
placeholder="optional"
|
|
681
|
+
/>
|
|
682
|
+
</div>
|
|
683
|
+
<div class="form-group">
|
|
684
|
+
<label class="form-label" for="machine-path"
|
|
685
|
+
>Shipwright Path</label
|
|
686
|
+
>
|
|
687
|
+
<input
|
|
688
|
+
type="text"
|
|
689
|
+
id="machine-path"
|
|
690
|
+
class="form-input"
|
|
691
|
+
placeholder="/opt/shipwright"
|
|
692
|
+
/>
|
|
693
|
+
</div>
|
|
694
|
+
</div>
|
|
695
|
+
<div class="form-row">
|
|
696
|
+
<div class="form-group">
|
|
697
|
+
<label class="form-label" for="machine-workers"
|
|
698
|
+
>Max Workers</label
|
|
699
|
+
>
|
|
700
|
+
<input
|
|
701
|
+
type="number"
|
|
702
|
+
id="machine-workers"
|
|
703
|
+
class="form-input"
|
|
704
|
+
value="4"
|
|
705
|
+
min="1"
|
|
706
|
+
max="64"
|
|
707
|
+
/>
|
|
708
|
+
</div>
|
|
709
|
+
<div class="form-group">
|
|
710
|
+
<label class="form-label" for="machine-role">Role</label>
|
|
711
|
+
<select id="machine-role" class="form-input">
|
|
712
|
+
<option value="worker">Worker</option>
|
|
713
|
+
<option value="primary">Primary</option>
|
|
714
|
+
</select>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
<div
|
|
718
|
+
id="machine-modal-error"
|
|
719
|
+
class="form-error"
|
|
720
|
+
style="display: none"
|
|
721
|
+
></div>
|
|
722
|
+
</div>
|
|
723
|
+
<div class="modal-footer">
|
|
724
|
+
<button class="modal-btn modal-btn-cancel" id="machine-modal-cancel">
|
|
725
|
+
Cancel
|
|
726
|
+
</button>
|
|
727
|
+
<button class="modal-btn modal-btn-send" id="machine-modal-submit">
|
|
728
|
+
Register
|
|
729
|
+
</button>
|
|
730
|
+
</div>
|
|
731
|
+
</div>
|
|
732
|
+
</div>
|
|
733
|
+
|
|
734
|
+
<!-- Join Link Modal -->
|
|
735
|
+
<div class="modal-overlay" id="join-link-modal" style="display: none">
|
|
736
|
+
<div class="modal-card">
|
|
737
|
+
<div class="modal-header">
|
|
738
|
+
<h3 class="modal-title">Generate Join Link</h3>
|
|
739
|
+
<button class="modal-close" id="join-modal-close">×</button>
|
|
740
|
+
</div>
|
|
741
|
+
<div class="modal-body">
|
|
742
|
+
<div class="form-group">
|
|
743
|
+
<label class="form-label" for="join-label">Label (optional)</label>
|
|
744
|
+
<input
|
|
745
|
+
type="text"
|
|
746
|
+
id="join-label"
|
|
747
|
+
class="form-input"
|
|
748
|
+
placeholder="e.g. Seth's laptop"
|
|
749
|
+
/>
|
|
750
|
+
</div>
|
|
751
|
+
<div class="form-group">
|
|
752
|
+
<label class="form-label" for="join-workers">Max Workers</label>
|
|
753
|
+
<input
|
|
754
|
+
type="number"
|
|
755
|
+
id="join-workers"
|
|
756
|
+
class="form-input"
|
|
757
|
+
value="4"
|
|
758
|
+
min="1"
|
|
759
|
+
max="64"
|
|
760
|
+
/>
|
|
761
|
+
</div>
|
|
762
|
+
<div id="join-command-display" style="display: none">
|
|
763
|
+
<label class="form-label">Run this command on the machine:</label>
|
|
764
|
+
<div class="join-command">
|
|
765
|
+
<code id="join-command-text"></code>
|
|
766
|
+
<button
|
|
767
|
+
class="join-copy-btn"
|
|
768
|
+
id="join-copy-btn"
|
|
769
|
+
title="Copy to clipboard"
|
|
770
|
+
>
|
|
771
|
+
Copy
|
|
772
|
+
</button>
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
</div>
|
|
776
|
+
<div class="modal-footer">
|
|
777
|
+
<button class="modal-btn modal-btn-cancel" id="join-modal-cancel">
|
|
778
|
+
Cancel
|
|
779
|
+
</button>
|
|
780
|
+
<button class="modal-btn modal-btn-send" id="join-modal-generate">
|
|
781
|
+
Generate
|
|
782
|
+
</button>
|
|
783
|
+
</div>
|
|
784
|
+
</div>
|
|
785
|
+
</div>
|
|
786
|
+
|
|
787
|
+
<!-- Remove Machine Modal -->
|
|
788
|
+
<div class="modal-overlay" id="remove-machine-modal" style="display: none">
|
|
789
|
+
<div class="modal-card">
|
|
790
|
+
<div class="modal-header">
|
|
791
|
+
<h3 class="modal-title">Remove Machine</h3>
|
|
792
|
+
<button class="modal-close" id="remove-modal-close">×</button>
|
|
793
|
+
</div>
|
|
794
|
+
<div class="modal-body">
|
|
795
|
+
<p class="emergency-warning">
|
|
796
|
+
Remove <strong id="remove-machine-name"></strong> from the fleet?
|
|
797
|
+
</p>
|
|
798
|
+
<label class="form-checkbox-label">
|
|
799
|
+
<input type="checkbox" id="remove-stop-daemon" />
|
|
800
|
+
Also stop daemon on this machine
|
|
801
|
+
</label>
|
|
802
|
+
</div>
|
|
803
|
+
<div class="modal-footer">
|
|
804
|
+
<button class="modal-btn modal-btn-cancel" id="remove-modal-cancel">
|
|
805
|
+
Cancel
|
|
806
|
+
</button>
|
|
807
|
+
<button class="modal-btn modal-btn-danger" id="remove-modal-confirm">
|
|
808
|
+
Remove
|
|
809
|
+
</button>
|
|
810
|
+
</div>
|
|
811
|
+
</div>
|
|
812
|
+
</div>
|
|
813
|
+
|
|
814
|
+
<script src="app.js"></script>
|
|
815
|
+
</body>
|
|
816
|
+
</html>
|