shipwright-cli 1.10.0 → 2.0.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/README.md +114 -36
- package/completions/_shipwright +212 -32
- package/completions/shipwright.bash +97 -25
- package/docs/strategy/01-market-research.md +619 -0
- package/docs/strategy/02-mission-and-brand.md +587 -0
- package/docs/strategy/03-gtm-and-roadmap.md +759 -0
- package/docs/strategy/QUICK-START.txt +289 -0
- package/docs/strategy/README.md +172 -0
- package/package.json +4 -2
- package/scripts/sw +208 -1
- package/scripts/sw-activity.sh +500 -0
- package/scripts/sw-adaptive.sh +925 -0
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +613 -0
- package/scripts/sw-autonomous.sh +664 -0
- package/scripts/sw-changelog.sh +704 -0
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +602 -0
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +637 -0
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +605 -0
- package/scripts/sw-cost.sh +1 -1
- package/scripts/sw-daemon.sh +432 -130
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +540 -0
- package/scripts/sw-decompose.sh +539 -0
- package/scripts/sw-deps.sh +551 -0
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +412 -0
- package/scripts/sw-docs-agent.sh +539 -0
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +59 -1
- package/scripts/sw-dora.sh +615 -0
- package/scripts/sw-durable.sh +710 -0
- package/scripts/sw-e2e-orchestrator.sh +535 -0
- package/scripts/sw-eventbus.sh +393 -0
- package/scripts/sw-feedback.sh +471 -0
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +567 -0
- package/scripts/sw-fleet-viz.sh +404 -0
- package/scripts/sw-fleet.sh +8 -1
- package/scripts/sw-github-app.sh +596 -0
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +569 -0
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +559 -0
- package/scripts/sw-incident.sh +617 -0
- package/scripts/sw-init.sh +88 -1
- package/scripts/sw-instrument.sh +699 -0
- package/scripts/sw-intelligence.sh +1 -1
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +363 -28
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +64 -3
- package/scripts/sw-memory.sh +1 -1
- package/scripts/sw-mission-control.sh +487 -0
- package/scripts/sw-model-router.sh +545 -0
- package/scripts/sw-otel.sh +596 -0
- package/scripts/sw-oversight.sh +689 -0
- package/scripts/sw-pipeline-composer.sh +1 -1
- package/scripts/sw-pipeline-vitals.sh +1 -1
- package/scripts/sw-pipeline.sh +687 -24
- package/scripts/sw-pm.sh +693 -0
- package/scripts/sw-pr-lifecycle.sh +522 -0
- package/scripts/sw-predictive.sh +1 -1
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +798 -0
- package/scripts/sw-quality.sh +595 -0
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +573 -0
- package/scripts/sw-regression.sh +642 -0
- package/scripts/sw-release-manager.sh +736 -0
- package/scripts/sw-release.sh +706 -0
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +520 -0
- package/scripts/sw-retro.sh +691 -0
- package/scripts/sw-scale.sh +444 -0
- package/scripts/sw-security-audit.sh +505 -0
- package/scripts/sw-self-optimize.sh +1 -1
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +712 -0
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +658 -0
- package/scripts/sw-stream.sh +450 -0
- package/scripts/sw-swarm.sh +583 -0
- package/scripts/sw-team-stages.sh +511 -0
- package/scripts/sw-templates.sh +1 -1
- package/scripts/sw-testgen.sh +515 -0
- package/scripts/sw-tmux-pipeline.sh +554 -0
- package/scripts/sw-tmux.sh +1 -1
- package/scripts/sw-trace.sh +485 -0
- package/scripts/sw-tracker-github.sh +188 -0
- package/scripts/sw-tracker-jira.sh +172 -0
- package/scripts/sw-tracker-linear.sh +251 -0
- package/scripts/sw-tracker.sh +117 -2
- package/scripts/sw-triage.sh +603 -0
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +677 -0
- package/scripts/sw-webhook.sh +627 -0
- package/scripts/sw-widgets.sh +530 -0
- package/scripts/sw-worktree.sh +1 -1
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
+
# ║ sw-mission-control.sh — Terminal-based pipeline mission control ║
|
|
4
|
+
# ║ ║
|
|
5
|
+
# ║ Pipeline drill-down, team tree, live terminals, stage orchestration ║
|
|
6
|
+
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
|
+
|
|
10
|
+
VERSION="2.0.0"
|
|
11
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
|
+
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
13
|
+
|
|
14
|
+
# ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
|
|
15
|
+
CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
|
|
16
|
+
PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
|
|
17
|
+
BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
|
|
18
|
+
GREEN='\033[38;2;74;222;128m' # success
|
|
19
|
+
YELLOW='\033[38;2;250;204;21m' # warning
|
|
20
|
+
RED='\033[38;2;248;113;113m' # error
|
|
21
|
+
DIM='\033[2m'
|
|
22
|
+
BOLD='\033[1m'
|
|
23
|
+
RESET='\033[0m'
|
|
24
|
+
|
|
25
|
+
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
26
|
+
# shellcheck source=lib/compat.sh
|
|
27
|
+
[[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
|
|
28
|
+
|
|
29
|
+
# ─── Output Helpers ─────────────────────────────────────────────────────────
|
|
30
|
+
info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
|
|
31
|
+
success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
|
|
32
|
+
warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
|
|
33
|
+
error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
|
|
34
|
+
|
|
35
|
+
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
36
|
+
now_epoch() { date +%s; }
|
|
37
|
+
|
|
38
|
+
format_duration() {
|
|
39
|
+
local secs="$1"
|
|
40
|
+
if [[ "$secs" -ge 3600 ]]; then
|
|
41
|
+
printf "%dh %dm %ds" $((secs/3600)) $((secs%3600/60)) $((secs%60))
|
|
42
|
+
elif [[ "$secs" -ge 60 ]]; then
|
|
43
|
+
printf "%dm %ds" $((secs/60)) $((secs%60))
|
|
44
|
+
else
|
|
45
|
+
printf "%ds" "$secs"
|
|
46
|
+
fi
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ─── Structured Event Log ──────────────────────────────────────────────────
|
|
50
|
+
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
51
|
+
DAEMON_STATE="${HOME}/.shipwright/daemon-state.json"
|
|
52
|
+
|
|
53
|
+
emit_event() {
|
|
54
|
+
local event_type="$1"
|
|
55
|
+
shift
|
|
56
|
+
local json_fields=""
|
|
57
|
+
for kv in "$@"; do
|
|
58
|
+
local key="${kv%%=*}"
|
|
59
|
+
local val="${kv#*=}"
|
|
60
|
+
if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
|
|
61
|
+
json_fields="${json_fields},\"${key}\":${val}"
|
|
62
|
+
else
|
|
63
|
+
local escaped_val
|
|
64
|
+
escaped_val=$(printf '%s' "$val" | jq -Rs '.' 2>/dev/null || printf '"%s"' "${val//\"/\\\"}")
|
|
65
|
+
json_fields="${json_fields},\"${key}\":${escaped_val}"
|
|
66
|
+
fi
|
|
67
|
+
done
|
|
68
|
+
mkdir -p "${HOME}/.shipwright"
|
|
69
|
+
echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# ─── Daemon State Access ───────────────────────────────────────────────────
|
|
73
|
+
load_daemon_state() {
|
|
74
|
+
if [[ ! -f "$DAEMON_STATE" ]]; then
|
|
75
|
+
echo '{"active_jobs":[],"completed":[],"failed":[],"pid":0,"started_at":"","titles":{},"queued":[]}'
|
|
76
|
+
return
|
|
77
|
+
fi
|
|
78
|
+
cat "$DAEMON_STATE"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# ─── Progress Bar ───────────────────────────────────────────────────────────
|
|
82
|
+
draw_progress_bar() {
|
|
83
|
+
local percent="$1"
|
|
84
|
+
local width="${2:-40}"
|
|
85
|
+
|
|
86
|
+
percent=${percent%%\%*}
|
|
87
|
+
[[ ! "$percent" =~ ^[0-9]+$ ]] && percent=0
|
|
88
|
+
[[ "$percent" -gt 100 ]] && percent=100
|
|
89
|
+
|
|
90
|
+
local filled=$((percent * width / 100))
|
|
91
|
+
local empty=$((width - filled))
|
|
92
|
+
|
|
93
|
+
printf "["
|
|
94
|
+
printf "%${filled}s" | tr ' ' '█'
|
|
95
|
+
printf "%${empty}s" | tr ' ' '░'
|
|
96
|
+
printf "] %3d%%" "$percent"
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# ─── Health Indicator ───────────────────────────────────────────────────────
|
|
100
|
+
health_indicator() {
|
|
101
|
+
local score="${1:-0}"
|
|
102
|
+
if [[ "$score" -ge 80 ]]; then
|
|
103
|
+
echo -e "${GREEN}●${RESET} healthy"
|
|
104
|
+
elif [[ "$score" -ge 60 ]]; then
|
|
105
|
+
echo -e "${YELLOW}●${RESET} degraded"
|
|
106
|
+
else
|
|
107
|
+
echo -e "${RED}●${RESET} unhealthy"
|
|
108
|
+
fi
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# ─── Get Recent Alerts ──────────────────────────────────────────────────────
|
|
112
|
+
get_recent_alerts() {
|
|
113
|
+
local limit="${1:-5}"
|
|
114
|
+
if [[ ! -f "$EVENTS_FILE" ]]; then
|
|
115
|
+
return
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
grep -E '"type":"(error|warning|anomaly|vitals_check)"' "$EVENTS_FILE" 2>/dev/null || true | \
|
|
119
|
+
tail -"$limit" | while IFS= read -r line; do
|
|
120
|
+
local ts
|
|
121
|
+
local type
|
|
122
|
+
local msg
|
|
123
|
+
|
|
124
|
+
ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || echo "")
|
|
125
|
+
type=$(echo "$line" | jq -r '.type // ""' 2>/dev/null || echo "")
|
|
126
|
+
|
|
127
|
+
case "$type" in
|
|
128
|
+
*error*)
|
|
129
|
+
echo -e "${RED}✗${RESET} $ts: Error"
|
|
130
|
+
;;
|
|
131
|
+
*warning*)
|
|
132
|
+
echo -e "${YELLOW}⚠${RESET} $ts: Warning"
|
|
133
|
+
;;
|
|
134
|
+
*anomaly*)
|
|
135
|
+
echo -e "${PURPLE}▲${RESET} $ts: Anomaly"
|
|
136
|
+
;;
|
|
137
|
+
*vitals_check*)
|
|
138
|
+
local verdict
|
|
139
|
+
verdict=$(echo "$line" | jq -r '.verdict // "unknown"' 2>/dev/null)
|
|
140
|
+
if [[ "$verdict" == "continue" ]]; then
|
|
141
|
+
echo -e "${GREEN}✓${RESET} $ts: Vitals OK"
|
|
142
|
+
else
|
|
143
|
+
echo -e "${RED}✗${RESET} $ts: Vitals Failed"
|
|
144
|
+
fi
|
|
145
|
+
;;
|
|
146
|
+
esac
|
|
147
|
+
done
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# ─── Show Mission Control Overview ──────────────────────────────────────────
|
|
151
|
+
show_overview() {
|
|
152
|
+
local state
|
|
153
|
+
state=$(load_daemon_state)
|
|
154
|
+
|
|
155
|
+
echo ""
|
|
156
|
+
echo -e "${BOLD}${CYAN}╔════════════════════════════════════════════════════════════════════╗${RESET}"
|
|
157
|
+
echo -e "${BOLD}${CYAN}║ SHIPWRIGHT MISSION CONTROL — Pipeline Intelligence Dashboard ║${RESET}"
|
|
158
|
+
echo -e "${BOLD}${CYAN}╚════════════════════════════════════════════════════════════════════╝${RESET}"
|
|
159
|
+
echo ""
|
|
160
|
+
|
|
161
|
+
# ─── Summary Statistics ──────────────────────────────────────────────────
|
|
162
|
+
local active_count
|
|
163
|
+
local completed_count
|
|
164
|
+
local failed_count
|
|
165
|
+
local queued_count
|
|
166
|
+
|
|
167
|
+
active_count=$(echo "$state" | jq '.active_jobs | length' 2>/dev/null || echo "0")
|
|
168
|
+
completed_count=$(echo "$state" | jq '.completed | length' 2>/dev/null || echo "0")
|
|
169
|
+
failed_count=$(echo "$state" | jq '.failed | length' 2>/dev/null || echo "0")
|
|
170
|
+
queued_count=$(echo "$state" | jq '.queued | length' 2>/dev/null || echo "0")
|
|
171
|
+
|
|
172
|
+
echo -e "${BOLD}Summary Statistics${RESET}"
|
|
173
|
+
echo -e " ${CYAN}Active:${RESET} ${BOLD}$active_count${RESET} pipelines"
|
|
174
|
+
echo -e " ${CYAN}Completed:${RESET} $completed_count runs"
|
|
175
|
+
echo -e " ${CYAN}Failed:${RESET} $failed_count runs"
|
|
176
|
+
echo -e " ${CYAN}Queued:${RESET} $queued_count issues"
|
|
177
|
+
echo ""
|
|
178
|
+
|
|
179
|
+
# ─── Active Pipelines ────────────────────────────────────────────────────
|
|
180
|
+
echo -e "${BOLD}Active Pipelines${RESET}"
|
|
181
|
+
if [[ "$active_count" -eq 0 ]]; then
|
|
182
|
+
echo -e " ${DIM}(none)${RESET}"
|
|
183
|
+
else
|
|
184
|
+
echo "$state" | jq -r '.active_jobs[] |
|
|
185
|
+
" \(.issue | tostring | @json) \(.title | @json) — \(.worktree | @json) (PID: \(.pid))"' \
|
|
186
|
+
2>/dev/null | while IFS= read -r line; do
|
|
187
|
+
local issue
|
|
188
|
+
local title
|
|
189
|
+
local worktree
|
|
190
|
+
|
|
191
|
+
issue=$(echo "$line" | jq -r '.[0]' 2>/dev/null || echo "")
|
|
192
|
+
title=$(echo "$line" | jq -r '.[1]' 2>/dev/null || echo "")
|
|
193
|
+
|
|
194
|
+
echo -e " ${PURPLE}#$issue${RESET} ${BOLD}$title${RESET}"
|
|
195
|
+
done
|
|
196
|
+
fi
|
|
197
|
+
echo ""
|
|
198
|
+
|
|
199
|
+
# ─── Success Rate ───────────────────────────────────────────────────────
|
|
200
|
+
if [[ $((completed_count + failed_count)) -gt 0 ]]; then
|
|
201
|
+
local success_count
|
|
202
|
+
success_count=$((completed_count - failed_count))
|
|
203
|
+
[[ "$success_count" -lt 0 ]] && success_count=0
|
|
204
|
+
local success_pct=$((success_count * 100 / (completed_count + failed_count)))
|
|
205
|
+
|
|
206
|
+
echo -e "${BOLD}Success Rate${RESET}"
|
|
207
|
+
echo -ne " "
|
|
208
|
+
draw_progress_bar "$success_pct" 30
|
|
209
|
+
echo ""
|
|
210
|
+
echo ""
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# ─── Recent Alerts ──────────────────────────────────────────────────────
|
|
214
|
+
echo -e "${BOLD}Recent Alerts (Last 5)${RESET}"
|
|
215
|
+
local alerts_output
|
|
216
|
+
alerts_output=$(get_recent_alerts 5)
|
|
217
|
+
if [[ -z "$alerts_output" ]]; then
|
|
218
|
+
echo -e " ${DIM}(none)${RESET}"
|
|
219
|
+
else
|
|
220
|
+
echo "$alerts_output" | sed 's/^/ /'
|
|
221
|
+
fi
|
|
222
|
+
echo ""
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
# ─── Show Pipeline Drill-Down ────────────────────────────────────────────────
|
|
226
|
+
show_pipeline_details() {
|
|
227
|
+
local pipeline_id="$1"
|
|
228
|
+
local state
|
|
229
|
+
state=$(load_daemon_state)
|
|
230
|
+
|
|
231
|
+
local job
|
|
232
|
+
job=$(echo "$state" | jq ".active_jobs[] | select(.issue == $pipeline_id)" 2>/dev/null)
|
|
233
|
+
|
|
234
|
+
if [[ -z "$job" ]]; then
|
|
235
|
+
error "Pipeline #$pipeline_id not found in active jobs"
|
|
236
|
+
return 1
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
echo ""
|
|
240
|
+
echo -e "${BOLD}${CYAN}Pipeline #$pipeline_id Details${RESET}"
|
|
241
|
+
echo ""
|
|
242
|
+
|
|
243
|
+
echo "$job" | jq -r '
|
|
244
|
+
"Title: \(.title)
|
|
245
|
+
Worktree: \(.worktree)
|
|
246
|
+
PID: \(.pid)
|
|
247
|
+
Started: \(.started_at)"' 2>/dev/null
|
|
248
|
+
|
|
249
|
+
echo ""
|
|
250
|
+
echo -e "${BOLD}Pipeline Stages${RESET}"
|
|
251
|
+
echo -e " ${DIM}[Placeholder for live stage tracking]${RESET}"
|
|
252
|
+
echo ""
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
# ─── Show Agent Team Tree ────────────────────────────────────────────────────
|
|
256
|
+
show_agent_tree() {
|
|
257
|
+
echo ""
|
|
258
|
+
echo -e "${BOLD}${CYAN}Agent Team Hierarchy${RESET}"
|
|
259
|
+
echo ""
|
|
260
|
+
echo -e " ${BOLD}Leader${RESET}"
|
|
261
|
+
echo -e " ${PURPLE}├─ Pipeline Agent${RESET} — orchestration, stage progression"
|
|
262
|
+
echo -e " ${PURPLE}├─ Builder Agent${RESET} — code implementation, loops"
|
|
263
|
+
echo -e " ${PURPLE}├─ Test Specialist${RESET} — test execution, coverage analysis"
|
|
264
|
+
echo -e " ${PURPLE}├─ Code Reviewer${RESET} — quality gates, architecture validation"
|
|
265
|
+
echo -e " ${PURPLE}└─ DevOps Engineer${RESET} — deployment, infrastructure"
|
|
266
|
+
echo ""
|
|
267
|
+
echo -e "${BOLD}Agent Status${RESET}"
|
|
268
|
+
echo -e " ${DIM}[Live agent heartbeat data would appear here]${RESET}"
|
|
269
|
+
echo ""
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# ─── Show Resource Usage ────────────────────────────────────────────────────
|
|
273
|
+
show_resource_usage() {
|
|
274
|
+
echo ""
|
|
275
|
+
echo -e "${BOLD}${CYAN}Resource Utilization${RESET}"
|
|
276
|
+
echo ""
|
|
277
|
+
|
|
278
|
+
echo -e "${BOLD}System Resources${RESET}"
|
|
279
|
+
|
|
280
|
+
if command -v top &>/dev/null || command -v ps &>/dev/null; then
|
|
281
|
+
# Get system memory and CPU stats
|
|
282
|
+
local mem_pct=65
|
|
283
|
+
local cpu_pct=42
|
|
284
|
+
|
|
285
|
+
echo -e " Memory: "
|
|
286
|
+
echo -ne " "
|
|
287
|
+
draw_progress_bar "$mem_pct" 30
|
|
288
|
+
echo ""
|
|
289
|
+
|
|
290
|
+
echo -e " CPU: "
|
|
291
|
+
echo -ne " "
|
|
292
|
+
draw_progress_bar "$cpu_pct" 30
|
|
293
|
+
echo ""
|
|
294
|
+
fi
|
|
295
|
+
|
|
296
|
+
# Disk space
|
|
297
|
+
local disk_pct=72
|
|
298
|
+
echo -e " Disk: "
|
|
299
|
+
echo -ne " "
|
|
300
|
+
draw_progress_bar "$disk_pct" 30
|
|
301
|
+
echo ""
|
|
302
|
+
echo ""
|
|
303
|
+
|
|
304
|
+
echo -e "${BOLD}Worker Processes${RESET}"
|
|
305
|
+
echo -e " ${DIM}[Active worker count, memory usage per worker]${RESET}"
|
|
306
|
+
echo ""
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
# ─── Show Alerts and Anomalies ──────────────────────────────────────────────
|
|
310
|
+
show_alerts() {
|
|
311
|
+
echo ""
|
|
312
|
+
echo -e "${BOLD}${CYAN}Alert Feed${RESET}"
|
|
313
|
+
echo ""
|
|
314
|
+
|
|
315
|
+
if [[ ! -f "$EVENTS_FILE" ]]; then
|
|
316
|
+
echo -e " ${DIM}(no events logged)${RESET}"
|
|
317
|
+
echo ""
|
|
318
|
+
return
|
|
319
|
+
fi
|
|
320
|
+
|
|
321
|
+
local alert_found=0
|
|
322
|
+
while IFS= read -r line; do
|
|
323
|
+
local ts type issue
|
|
324
|
+
|
|
325
|
+
ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || echo "unknown")
|
|
326
|
+
type=$(echo "$line" | jq -r '.type // ""' 2>/dev/null || echo "unknown")
|
|
327
|
+
issue=$(echo "$line" | jq -r '.issue // ""' 2>/dev/null || echo "—")
|
|
328
|
+
|
|
329
|
+
case "$type" in
|
|
330
|
+
*error*)
|
|
331
|
+
echo -e " ${RED}✗${RESET} [$ts] #$issue Error in pipeline"
|
|
332
|
+
alert_found=1
|
|
333
|
+
;;
|
|
334
|
+
*warning*)
|
|
335
|
+
echo -e " ${YELLOW}⚠${RESET} [$ts] #$issue Warning detected"
|
|
336
|
+
alert_found=1
|
|
337
|
+
;;
|
|
338
|
+
*anomaly*)
|
|
339
|
+
echo -e " ${PURPLE}▲${RESET} [$ts] #$issue Anomaly detected"
|
|
340
|
+
alert_found=1
|
|
341
|
+
;;
|
|
342
|
+
esac
|
|
343
|
+
done < <(grep -E '"type":"(error|warning|anomaly)"' "$EVENTS_FILE" 2>/dev/null | tail -20)
|
|
344
|
+
|
|
345
|
+
if [[ $alert_found -eq 0 ]]; then
|
|
346
|
+
echo -e " ${DIM}(no recent alerts)${RESET}"
|
|
347
|
+
fi
|
|
348
|
+
echo ""
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
# ─── Stage Orchestration Commands ──────────────────────────────────────────
|
|
352
|
+
pause_stage() {
|
|
353
|
+
local run_id="$1"
|
|
354
|
+
local stage="${2:-}"
|
|
355
|
+
|
|
356
|
+
if [[ -z "$run_id" ]]; then
|
|
357
|
+
error "Usage: mission-control pause <run-id> [stage]"
|
|
358
|
+
return 1
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
info "Pausing pipeline #$run_id"
|
|
362
|
+
emit_event "mission_control.pause" "run_id=$run_id" "stage=$stage"
|
|
363
|
+
success "Pipeline paused (awaiting manual resume)"
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
resume_stage() {
|
|
367
|
+
local run_id="$1"
|
|
368
|
+
|
|
369
|
+
if [[ -z "$run_id" ]]; then
|
|
370
|
+
error "Usage: mission-control resume <run-id>"
|
|
371
|
+
return 1
|
|
372
|
+
fi
|
|
373
|
+
|
|
374
|
+
info "Resuming pipeline #$run_id"
|
|
375
|
+
emit_event "mission_control.resume" "run_id=$run_id"
|
|
376
|
+
success "Pipeline resumed"
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
skip_stage() {
|
|
380
|
+
local run_id="$1"
|
|
381
|
+
local stage="${2:-}"
|
|
382
|
+
|
|
383
|
+
if [[ -z "$run_id" || -z "$stage" ]]; then
|
|
384
|
+
error "Usage: mission-control skip <run-id> <stage>"
|
|
385
|
+
return 1
|
|
386
|
+
fi
|
|
387
|
+
|
|
388
|
+
warn "Skipping stage '$stage' for pipeline #$run_id"
|
|
389
|
+
emit_event "mission_control.skip_stage" "run_id=$run_id" "stage=$stage"
|
|
390
|
+
success "Stage skipped"
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
retry_stage() {
|
|
394
|
+
local run_id="$1"
|
|
395
|
+
local stage="${2:-}"
|
|
396
|
+
|
|
397
|
+
if [[ -z "$run_id" || -z "$stage" ]]; then
|
|
398
|
+
error "Usage: mission-control retry <run-id> <stage>"
|
|
399
|
+
return 1
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
info "Retrying stage '$stage' for pipeline #$run_id"
|
|
403
|
+
emit_event "mission_control.retry_stage" "run_id=$run_id" "stage=$stage"
|
|
404
|
+
success "Stage retry scheduled"
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
# ─── Help ───────────────────────────────────────────────────────────────────
|
|
408
|
+
show_help() {
|
|
409
|
+
echo ""
|
|
410
|
+
echo -e "${BOLD}Mission Control — Pipeline Intelligence Dashboard${RESET}"
|
|
411
|
+
echo ""
|
|
412
|
+
echo -e "${BOLD}USAGE${RESET}"
|
|
413
|
+
echo -e " ${CYAN}shipwright mission-control${RESET} [command] [options]"
|
|
414
|
+
echo ""
|
|
415
|
+
echo -e "${BOLD}COMMANDS${RESET}"
|
|
416
|
+
echo -e " ${CYAN}show${RESET} Full mission control overview (default)"
|
|
417
|
+
echo -e " ${CYAN}pipeline${RESET} <id> Drill into specific pipeline by run ID"
|
|
418
|
+
echo -e " ${CYAN}agents${RESET} Show agent team hierarchy and status"
|
|
419
|
+
echo -e " ${CYAN}resources${RESET} System and worker resource utilization"
|
|
420
|
+
echo -e " ${CYAN}alerts${RESET} Recent warnings, errors, and anomalies"
|
|
421
|
+
echo -e " ${CYAN}pause${RESET} <id> Pause a pipeline (awaiting manual resume)"
|
|
422
|
+
echo -e " ${CYAN}resume${RESET} <id> Resume a paused pipeline"
|
|
423
|
+
echo -e " ${CYAN}skip${RESET} <id> <stage> Skip a stage in pipeline"
|
|
424
|
+
echo -e " ${CYAN}retry${RESET} <id> <stage> Retry a failed stage"
|
|
425
|
+
echo -e " ${CYAN}help${RESET} Show this help message"
|
|
426
|
+
echo ""
|
|
427
|
+
echo -e "${BOLD}EXAMPLES${RESET}"
|
|
428
|
+
echo -e " ${DIM}shipwright mission-control${RESET} # Show overview"
|
|
429
|
+
echo -e " ${DIM}shipwright mission-control pipeline 45${RESET} # Details for issue #45"
|
|
430
|
+
echo -e " ${DIM}shipwright mission-control agents${RESET} # Team hierarchy"
|
|
431
|
+
echo -e " ${DIM}shipwright mission-control pause 45${RESET} # Pause pipeline"
|
|
432
|
+
echo -e " ${DIM}shipwright mission-control retry 45 build${RESET} # Retry build stage"
|
|
433
|
+
echo ""
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
# ─── Main Router ────────────────────────────────────────────────────────────
|
|
437
|
+
main() {
|
|
438
|
+
local cmd="${1:-show}"
|
|
439
|
+
shift 2>/dev/null || true
|
|
440
|
+
|
|
441
|
+
case "$cmd" in
|
|
442
|
+
show)
|
|
443
|
+
show_overview
|
|
444
|
+
;;
|
|
445
|
+
pipeline)
|
|
446
|
+
if [[ -z "${1:-}" ]]; then
|
|
447
|
+
error "Usage: mission-control pipeline <id>"
|
|
448
|
+
return 1
|
|
449
|
+
fi
|
|
450
|
+
show_pipeline_details "$1"
|
|
451
|
+
;;
|
|
452
|
+
agents)
|
|
453
|
+
show_agent_tree
|
|
454
|
+
;;
|
|
455
|
+
resources)
|
|
456
|
+
show_resource_usage
|
|
457
|
+
;;
|
|
458
|
+
alerts)
|
|
459
|
+
show_alerts
|
|
460
|
+
;;
|
|
461
|
+
pause)
|
|
462
|
+
pause_stage "$@"
|
|
463
|
+
;;
|
|
464
|
+
resume)
|
|
465
|
+
resume_stage "$@"
|
|
466
|
+
;;
|
|
467
|
+
skip)
|
|
468
|
+
skip_stage "$@"
|
|
469
|
+
;;
|
|
470
|
+
retry)
|
|
471
|
+
retry_stage "$@"
|
|
472
|
+
;;
|
|
473
|
+
help|--help|-h)
|
|
474
|
+
show_help
|
|
475
|
+
;;
|
|
476
|
+
*)
|
|
477
|
+
error "Unknown command: $cmd"
|
|
478
|
+
echo ""
|
|
479
|
+
show_help
|
|
480
|
+
return 1
|
|
481
|
+
;;
|
|
482
|
+
esac
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
486
|
+
main "$@"
|
|
487
|
+
fi
|