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,393 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
+
# ║ shipwright eventbus — Durable event bus for real-time inter-component ║
|
|
4
|
+
# ║ communication with publishing, subscribing, process monitoring, file ║
|
|
5
|
+
# ║ watching, event replay, and lifecycle management. ║
|
|
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
|
+
|
|
13
|
+
# ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
|
|
14
|
+
CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
|
|
15
|
+
PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
|
|
16
|
+
BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
|
|
17
|
+
GREEN='\033[38;2;74;222;128m' # success
|
|
18
|
+
YELLOW='\033[38;2;250;204;21m' # warning
|
|
19
|
+
RED='\033[38;2;248;113;113m' # error
|
|
20
|
+
DIM='\033[2m'
|
|
21
|
+
BOLD='\033[1m'
|
|
22
|
+
RESET='\033[0m'
|
|
23
|
+
|
|
24
|
+
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
25
|
+
# shellcheck source=lib/compat.sh
|
|
26
|
+
[[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
|
|
27
|
+
|
|
28
|
+
# ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
29
|
+
info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
|
|
30
|
+
success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
|
|
31
|
+
warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
|
|
32
|
+
error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
|
|
33
|
+
|
|
34
|
+
# ─── Configuration ──────────────────────────────────────────────────────────
|
|
35
|
+
EVENTBUS_FILE="${HOME}/.shipwright/eventbus.jsonl"
|
|
36
|
+
EVENT_TTL_DAYS=7 # Default TTL for events (seconds = 7 * 86400)
|
|
37
|
+
|
|
38
|
+
# ─── Initialize eventbus directory ──────────────────────────────────────────
|
|
39
|
+
ensure_eventbus_dir() {
|
|
40
|
+
local dir
|
|
41
|
+
dir="$(dirname "$EVENTBUS_FILE")"
|
|
42
|
+
[[ -d "$dir" ]] || mkdir -p "$dir"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# ─── Generate UUID (simple) ────────────────────────────────────────────────
|
|
46
|
+
generate_uuid() {
|
|
47
|
+
local uuid
|
|
48
|
+
uuid=$(od -x /dev/urandom | head -1 | awk '{OFS="-"; print $2$3, $4, $5, $6, $7$8$9}' | sed 's/-/-/g' | cut -c1-36)
|
|
49
|
+
echo "$uuid"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# ─── Publish command ────────────────────────────────────────────────────────
|
|
53
|
+
cmd_publish() {
|
|
54
|
+
local event_type="$1"
|
|
55
|
+
local source="${2:-unknown}"
|
|
56
|
+
local correlation_id="$3"
|
|
57
|
+
local payload_json="${4:-{}}"
|
|
58
|
+
|
|
59
|
+
if [[ -z "$event_type" ]]; then
|
|
60
|
+
error "publish requires event_type, source, [correlation_id], [payload_json]"
|
|
61
|
+
return 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
ensure_eventbus_dir
|
|
65
|
+
|
|
66
|
+
if [[ -z "$correlation_id" ]]; then
|
|
67
|
+
correlation_id="$(generate_uuid)"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
local timestamp
|
|
71
|
+
timestamp="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
72
|
+
|
|
73
|
+
# Build event JSON on single line
|
|
74
|
+
local event_json
|
|
75
|
+
event_json="{\"type\": \"$event_type\", \"source\": \"$source\", \"correlation_id\": \"$correlation_id\", \"timestamp\": \"$timestamp\", \"payload\": $payload_json}"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# Atomic write (append to JSONL file)
|
|
79
|
+
local tmp_file
|
|
80
|
+
tmp_file="$(mktemp)"
|
|
81
|
+
if [[ -f "$EVENTBUS_FILE" ]]; then
|
|
82
|
+
cat "$EVENTBUS_FILE" > "$tmp_file"
|
|
83
|
+
fi
|
|
84
|
+
echo "$event_json" >> "$tmp_file"
|
|
85
|
+
mv "$tmp_file" "$EVENTBUS_FILE"
|
|
86
|
+
|
|
87
|
+
success "Published event: $event_type (correlation_id: $correlation_id)"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# ─── Subscribe command ──────────────────────────────────────────────────────
|
|
91
|
+
cmd_subscribe() {
|
|
92
|
+
local event_type_filter="${1:-}"
|
|
93
|
+
local max_lines="${2:-}"
|
|
94
|
+
|
|
95
|
+
ensure_eventbus_dir
|
|
96
|
+
|
|
97
|
+
[[ ! -f "$EVENTBUS_FILE" ]] && {
|
|
98
|
+
warn "Event bus is empty or does not exist yet"
|
|
99
|
+
return 0
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
info "Subscribing to event bus (${event_type_filter:-(all types)})..."
|
|
103
|
+
echo ""
|
|
104
|
+
|
|
105
|
+
# Tail the file with optional grep filter
|
|
106
|
+
if [[ -n "$event_type_filter" ]]; then
|
|
107
|
+
tail -f "$EVENTBUS_FILE" | grep "\"type\": \"$event_type_filter\""
|
|
108
|
+
else
|
|
109
|
+
tail -f "$EVENTBUS_FILE"
|
|
110
|
+
fi
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# ─── Process reaper (SIGCHLD monitor) ──────────────────────────────────────
|
|
114
|
+
cmd_reaper() {
|
|
115
|
+
local pid_list=()
|
|
116
|
+
|
|
117
|
+
info "Starting process reaper. Press Ctrl+C to exit."
|
|
118
|
+
echo -e "${DIM}Monitoring child processes and emitting process.exited events...${RESET}"
|
|
119
|
+
echo ""
|
|
120
|
+
|
|
121
|
+
ensure_eventbus_dir
|
|
122
|
+
|
|
123
|
+
# Monitor child processes
|
|
124
|
+
while true; do
|
|
125
|
+
# Get list of all child processes
|
|
126
|
+
local pids
|
|
127
|
+
pids=$(jobs -p 2>/dev/null || echo "")
|
|
128
|
+
|
|
129
|
+
if [[ -n "$pids" ]]; then
|
|
130
|
+
while IFS= read -r pid; do
|
|
131
|
+
[[ -z "$pid" ]] && continue
|
|
132
|
+
|
|
133
|
+
# Check if process is still alive
|
|
134
|
+
if ! kill -0 "$pid" 2>/dev/null; then
|
|
135
|
+
# Process died — emit event
|
|
136
|
+
local payload="{\"pid\": $pid, \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
|
|
137
|
+
cmd_publish "process.exited" "reaper" "$(generate_uuid)" "$payload"
|
|
138
|
+
fi
|
|
139
|
+
done <<< "$pids"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
sleep 2
|
|
143
|
+
done
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# ─── File watcher (fswatch or inotifywait) ────────────────────────────────
|
|
147
|
+
cmd_watch() {
|
|
148
|
+
local watch_dir="$1"
|
|
149
|
+
[[ -z "$watch_dir" ]] && {
|
|
150
|
+
error "watch requires a directory path"
|
|
151
|
+
return 1
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
[[ ! -d "$watch_dir" ]] && {
|
|
155
|
+
error "Directory not found: $watch_dir"
|
|
156
|
+
return 1
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
ensure_eventbus_dir
|
|
160
|
+
|
|
161
|
+
info "Watching directory: $watch_dir"
|
|
162
|
+
echo -e "${DIM}Press Ctrl+C to stop...${RESET}"
|
|
163
|
+
echo ""
|
|
164
|
+
|
|
165
|
+
# Determine platform and use appropriate watcher
|
|
166
|
+
if command -v fswatch &>/dev/null; then
|
|
167
|
+
# macOS with fswatch
|
|
168
|
+
fswatch -r "$watch_dir" | while read -r file; do
|
|
169
|
+
local payload
|
|
170
|
+
payload="{\"file\": \"$file\", \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
|
|
171
|
+
cmd_publish "file.changed" "watcher" "$(generate_uuid)" "$payload"
|
|
172
|
+
done
|
|
173
|
+
elif command -v inotifywait &>/dev/null; then
|
|
174
|
+
# Linux with inotify-tools
|
|
175
|
+
inotifywait -m -r "$watch_dir" | while read -r dir action file; do
|
|
176
|
+
local filepath="${dir}${file}"
|
|
177
|
+
local payload
|
|
178
|
+
payload="{\"file\": \"$filepath\", \"action\": \"$action\", \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
|
|
179
|
+
cmd_publish "file.changed" "watcher" "$(generate_uuid)" "$payload"
|
|
180
|
+
done
|
|
181
|
+
else
|
|
182
|
+
error "Neither fswatch (macOS) nor inotifywait (Linux) is installed"
|
|
183
|
+
return 1
|
|
184
|
+
fi
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# ─── Event replay command ──────────────────────────────────────────────────
|
|
188
|
+
cmd_replay() {
|
|
189
|
+
local minutes="${1:-}"
|
|
190
|
+
[[ -z "$minutes" ]] && minutes=60
|
|
191
|
+
|
|
192
|
+
ensure_eventbus_dir
|
|
193
|
+
|
|
194
|
+
[[ ! -f "$EVENTBUS_FILE" ]] && {
|
|
195
|
+
warn "Event bus is empty or does not exist yet"
|
|
196
|
+
return 0
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
info "Replaying events from the last ${minutes} minutes..."
|
|
200
|
+
echo ""
|
|
201
|
+
|
|
202
|
+
# Calculate cutoff timestamp
|
|
203
|
+
local cutoff_epoch
|
|
204
|
+
cutoff_epoch=$(($(date +%s) - (minutes * 60)))
|
|
205
|
+
local cutoff_iso
|
|
206
|
+
cutoff_iso="$(date -u -j -f %s "$cutoff_epoch" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d @"$cutoff_epoch" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null)"
|
|
207
|
+
|
|
208
|
+
# Grep and display events after cutoff
|
|
209
|
+
grep "timestamp" "$EVENTBUS_FILE" | while read -r line; do
|
|
210
|
+
local ts
|
|
211
|
+
ts=$(echo "$line" | grep -o '"timestamp": "[^"]*"' | cut -d'"' -f4)
|
|
212
|
+
if [[ "$ts" > "$cutoff_iso" ]]; then
|
|
213
|
+
echo "$line"
|
|
214
|
+
fi
|
|
215
|
+
done
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# ─── Status command ────────────────────────────────────────────────────────
|
|
219
|
+
cmd_status() {
|
|
220
|
+
ensure_eventbus_dir
|
|
221
|
+
|
|
222
|
+
echo ""
|
|
223
|
+
echo -e "${CYAN}${BOLD}Event Bus Status${RESET}"
|
|
224
|
+
echo -e "${DIM}$(date '+%Y-%m-%d %H:%M:%S')${RESET}"
|
|
225
|
+
echo ""
|
|
226
|
+
|
|
227
|
+
if [[ ! -f "$EVENTBUS_FILE" ]]; then
|
|
228
|
+
echo -e " ${YELLOW}Event bus not yet initialized${RESET}"
|
|
229
|
+
echo ""
|
|
230
|
+
return 0
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
local total_events
|
|
234
|
+
total_events=$(wc -l < "$EVENTBUS_FILE" || echo 0)
|
|
235
|
+
|
|
236
|
+
local last_event_ts
|
|
237
|
+
last_event_ts=$(tail -1 "$EVENTBUS_FILE" | grep -o '"timestamp": "[^"]*"' | cut -d'"' -f4 || echo "never")
|
|
238
|
+
|
|
239
|
+
echo -e " ${CYAN}Event Bus:${RESET} $EVENTBUS_FILE"
|
|
240
|
+
echo -e " ${CYAN}Total Events:${RESET} ${BOLD}${total_events}${RESET}"
|
|
241
|
+
echo -e " ${CYAN}Last Event:${RESET} $last_event_ts"
|
|
242
|
+
echo ""
|
|
243
|
+
|
|
244
|
+
# Count events by type
|
|
245
|
+
if [[ $total_events -gt 0 ]]; then
|
|
246
|
+
echo -e " ${PURPLE}${BOLD}Events by Type${RESET}"
|
|
247
|
+
grep '"type"' "$EVENTBUS_FILE" | cut -d'"' -f4 | sort | uniq -c | sort -rn | while read -r count type; do
|
|
248
|
+
printf " ${DIM}%-40s${RESET} %3d events\n" "$type" "$count"
|
|
249
|
+
done
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
echo ""
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
# ─── Clean command (remove old events) ─────────────────────────────────────
|
|
256
|
+
cmd_clean() {
|
|
257
|
+
local ttl_days="${1:-$EVENT_TTL_DAYS}"
|
|
258
|
+
|
|
259
|
+
ensure_eventbus_dir
|
|
260
|
+
|
|
261
|
+
[[ ! -f "$EVENTBUS_FILE" ]] && {
|
|
262
|
+
success "Event bus is empty"
|
|
263
|
+
return 0
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
info "Cleaning events older than ${ttl_days} days..."
|
|
267
|
+
|
|
268
|
+
# Calculate cutoff timestamp
|
|
269
|
+
local cutoff_epoch
|
|
270
|
+
cutoff_epoch=$(($(date +%s) - (ttl_days * 86400)))
|
|
271
|
+
local cutoff_iso
|
|
272
|
+
cutoff_iso="$(date -u -j -f %s "$cutoff_epoch" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d @"$cutoff_epoch" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null)"
|
|
273
|
+
|
|
274
|
+
local old_count
|
|
275
|
+
old_count=$(grep -c "timestamp" "$EVENTBUS_FILE" 2>/dev/null || echo 0)
|
|
276
|
+
|
|
277
|
+
# Keep only recent events
|
|
278
|
+
local tmp_file
|
|
279
|
+
tmp_file="$(mktemp)"
|
|
280
|
+
grep "timestamp" "$EVENTBUS_FILE" | while read -r line; do
|
|
281
|
+
local ts
|
|
282
|
+
ts=$(echo "$line" | grep -o '"timestamp": "[^"]*"' | cut -d'"' -f4)
|
|
283
|
+
if [[ "$ts" > "$cutoff_iso" ]]; then
|
|
284
|
+
echo "$line" >> "$tmp_file"
|
|
285
|
+
fi
|
|
286
|
+
done
|
|
287
|
+
|
|
288
|
+
mv "$tmp_file" "$EVENTBUS_FILE"
|
|
289
|
+
|
|
290
|
+
local new_count
|
|
291
|
+
new_count=$(wc -l < "$EVENTBUS_FILE" || echo 0)
|
|
292
|
+
local removed=$((old_count - new_count))
|
|
293
|
+
|
|
294
|
+
success "Removed $removed old events. Remaining: $new_count"
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# ─── Help command ──────────────────────────────────────────────────────────
|
|
298
|
+
cmd_help() {
|
|
299
|
+
echo ""
|
|
300
|
+
echo -e "${CYAN}${BOLD}shipwright eventbus${RESET} — Durable event bus for real-time inter-component communication"
|
|
301
|
+
echo ""
|
|
302
|
+
echo -e "${BOLD}USAGE${RESET}"
|
|
303
|
+
echo -e " ${CYAN}shipwright eventbus${RESET} <subcommand> [options]"
|
|
304
|
+
echo ""
|
|
305
|
+
echo -e "${BOLD}SUBCOMMANDS${RESET}"
|
|
306
|
+
echo ""
|
|
307
|
+
echo -e " ${CYAN}publish${RESET} <type> <source> [correlation_id] [payload_json]"
|
|
308
|
+
echo -e " Publish a structured event to the event bus"
|
|
309
|
+
echo -e " ${DIM}shipwright eventbus publish stage.complete pipeline 123 '{\"stage\": \"build\"}'${RESET}"
|
|
310
|
+
echo ""
|
|
311
|
+
echo -e " ${CYAN}subscribe${RESET} [event_type]"
|
|
312
|
+
echo -e " Subscribe to events (tail with optional type filter)"
|
|
313
|
+
echo -e " ${DIM}shipwright eventbus subscribe${RESET} # All events"
|
|
314
|
+
echo -e " ${DIM}shipwright eventbus subscribe stage.complete${RESET} # Only stage events"
|
|
315
|
+
echo ""
|
|
316
|
+
echo -e " ${CYAN}reaper${RESET}"
|
|
317
|
+
echo -e " Monitor child processes and emit process.exited events"
|
|
318
|
+
echo -e " ${DIM}shipwright eventbus reaper${RESET}"
|
|
319
|
+
echo ""
|
|
320
|
+
echo -e " ${CYAN}watch${RESET} <directory>"
|
|
321
|
+
echo -e " Watch directory for file changes and emit file.changed events"
|
|
322
|
+
echo -e " ${DIM}shipwright eventbus watch /tmp/project${RESET}"
|
|
323
|
+
echo ""
|
|
324
|
+
echo -e " ${CYAN}replay${RESET} [minutes]"
|
|
325
|
+
echo -e " Replay events from the last N minutes (default: 60)"
|
|
326
|
+
echo -e " ${DIM}shipwright eventbus replay 30${RESET}"
|
|
327
|
+
echo ""
|
|
328
|
+
echo -e " ${CYAN}status${RESET}"
|
|
329
|
+
echo -e " Show event bus statistics and event counts by type"
|
|
330
|
+
echo -e " ${DIM}shipwright eventbus status${RESET}"
|
|
331
|
+
echo ""
|
|
332
|
+
echo -e " ${CYAN}clean${RESET} [ttl_days]"
|
|
333
|
+
echo -e " Remove events older than TTL (default: 7 days)"
|
|
334
|
+
echo -e " ${DIM}shipwright eventbus clean 3${RESET}"
|
|
335
|
+
echo ""
|
|
336
|
+
echo -e " ${CYAN}help${RESET}"
|
|
337
|
+
echo -e " Show this help message"
|
|
338
|
+
echo ""
|
|
339
|
+
echo -e "${BOLD}EVENT FORMAT${RESET}"
|
|
340
|
+
echo -e " Events are stored as JSONL with fields: type, source, correlation_id, timestamp, payload"
|
|
341
|
+
echo -e " ${DIM}Example:${RESET}"
|
|
342
|
+
echo -e " ${DIM}{\"type\": \"stage.complete\", \"source\": \"pipeline\", \"correlation_id\": \"123\", \"timestamp\": \"2025-02-14T12:34:56Z\", \"payload\": {...}}${RESET}"
|
|
343
|
+
echo ""
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
# ─── Main command router ───────────────────────────────────────────────────
|
|
347
|
+
main() {
|
|
348
|
+
local cmd="${1:-help}"
|
|
349
|
+
|
|
350
|
+
case "$cmd" in
|
|
351
|
+
publish)
|
|
352
|
+
shift
|
|
353
|
+
cmd_publish "$@"
|
|
354
|
+
;;
|
|
355
|
+
subscribe)
|
|
356
|
+
shift
|
|
357
|
+
cmd_subscribe "$@"
|
|
358
|
+
;;
|
|
359
|
+
reaper)
|
|
360
|
+
shift
|
|
361
|
+
cmd_reaper "$@"
|
|
362
|
+
;;
|
|
363
|
+
watch)
|
|
364
|
+
shift
|
|
365
|
+
cmd_watch "$@"
|
|
366
|
+
;;
|
|
367
|
+
replay)
|
|
368
|
+
shift
|
|
369
|
+
cmd_replay "$@"
|
|
370
|
+
;;
|
|
371
|
+
status)
|
|
372
|
+
shift
|
|
373
|
+
cmd_status "$@"
|
|
374
|
+
;;
|
|
375
|
+
clean)
|
|
376
|
+
shift
|
|
377
|
+
cmd_clean "$@"
|
|
378
|
+
;;
|
|
379
|
+
help|--help|-h)
|
|
380
|
+
cmd_help
|
|
381
|
+
;;
|
|
382
|
+
*)
|
|
383
|
+
error "Unknown subcommand: $cmd"
|
|
384
|
+
cmd_help
|
|
385
|
+
exit 1
|
|
386
|
+
;;
|
|
387
|
+
esac
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
# ─── Source guard ──────────────────────────────────────────────────────────
|
|
391
|
+
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
392
|
+
main "$@"
|
|
393
|
+
fi
|