shipwright-cli 2.4.0 → 3.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 +16 -11
- package/completions/_shipwright +1 -1
- package/completions/shipwright.bash +3 -8
- package/completions/shipwright.fish +1 -1
- package/config/defaults.json +111 -0
- package/config/event-schema.json +81 -0
- package/config/policy.json +13 -18
- package/dashboard/coverage/coverage-summary.json +14 -0
- package/dashboard/public/index.html +1 -1
- package/dashboard/server.ts +306 -17
- package/dashboard/src/components/charts/bar.test.ts +79 -0
- package/dashboard/src/components/charts/donut.test.ts +68 -0
- package/dashboard/src/components/charts/pipeline-rail.test.ts +117 -0
- package/dashboard/src/components/charts/sparkline.test.ts +125 -0
- package/dashboard/src/core/api.test.ts +309 -0
- package/dashboard/src/core/helpers.test.ts +301 -0
- package/dashboard/src/core/router.test.ts +307 -0
- package/dashboard/src/core/router.ts +7 -0
- package/dashboard/src/core/sse.test.ts +144 -0
- package/dashboard/src/views/metrics.test.ts +186 -0
- package/dashboard/src/views/overview.test.ts +173 -0
- package/dashboard/src/views/pipelines.test.ts +183 -0
- package/dashboard/src/views/team.test.ts +253 -0
- package/dashboard/vitest.config.ts +14 -5
- package/docs/TIPS.md +1 -1
- package/docs/patterns/README.md +1 -1
- package/package.json +5 -7
- package/scripts/adapters/docker-deploy.sh +1 -1
- package/scripts/adapters/tmux-adapter.sh +11 -1
- package/scripts/adapters/wezterm-adapter.sh +1 -1
- package/scripts/check-version-consistency.sh +1 -1
- package/scripts/lib/architecture.sh +126 -0
- package/scripts/lib/bootstrap.sh +75 -0
- package/scripts/lib/compat.sh +89 -6
- package/scripts/lib/config.sh +91 -0
- package/scripts/lib/daemon-adaptive.sh +3 -3
- package/scripts/lib/daemon-dispatch.sh +39 -16
- package/scripts/lib/daemon-health.sh +1 -1
- package/scripts/lib/daemon-patrol.sh +24 -12
- package/scripts/lib/daemon-poll.sh +37 -25
- package/scripts/lib/daemon-state.sh +115 -23
- package/scripts/lib/daemon-triage.sh +30 -8
- package/scripts/lib/fleet-failover.sh +63 -0
- package/scripts/lib/helpers.sh +30 -6
- package/scripts/lib/pipeline-detection.sh +2 -2
- package/scripts/lib/pipeline-github.sh +9 -9
- package/scripts/lib/pipeline-intelligence.sh +85 -35
- package/scripts/lib/pipeline-quality-checks.sh +16 -16
- package/scripts/lib/pipeline-quality.sh +1 -1
- package/scripts/lib/pipeline-stages.sh +242 -28
- package/scripts/lib/pipeline-state.sh +40 -4
- package/scripts/lib/test-helpers.sh +247 -0
- package/scripts/postinstall.mjs +3 -11
- package/scripts/sw +10 -4
- package/scripts/sw-activity.sh +1 -11
- package/scripts/sw-adaptive.sh +109 -85
- package/scripts/sw-adversarial.sh +4 -14
- package/scripts/sw-architecture-enforcer.sh +1 -11
- package/scripts/sw-auth.sh +8 -17
- package/scripts/sw-autonomous.sh +111 -49
- package/scripts/sw-changelog.sh +1 -11
- package/scripts/sw-checkpoint.sh +144 -20
- package/scripts/sw-ci.sh +2 -12
- package/scripts/sw-cleanup.sh +13 -17
- package/scripts/sw-code-review.sh +16 -36
- package/scripts/sw-connect.sh +5 -12
- package/scripts/sw-context.sh +9 -26
- package/scripts/sw-cost.sh +6 -16
- package/scripts/sw-daemon.sh +75 -70
- package/scripts/sw-dashboard.sh +57 -17
- package/scripts/sw-db.sh +506 -15
- package/scripts/sw-decompose.sh +1 -11
- package/scripts/sw-deps.sh +15 -25
- package/scripts/sw-developer-simulation.sh +1 -11
- package/scripts/sw-discovery.sh +112 -30
- package/scripts/sw-doc-fleet.sh +7 -17
- package/scripts/sw-docs-agent.sh +6 -16
- package/scripts/sw-docs.sh +4 -12
- package/scripts/sw-doctor.sh +134 -43
- package/scripts/sw-dora.sh +11 -19
- package/scripts/sw-durable.sh +35 -52
- package/scripts/sw-e2e-orchestrator.sh +11 -27
- package/scripts/sw-eventbus.sh +115 -115
- package/scripts/sw-evidence.sh +114 -30
- package/scripts/sw-feedback.sh +3 -13
- package/scripts/sw-fix.sh +2 -20
- package/scripts/sw-fleet-discover.sh +1 -11
- package/scripts/sw-fleet-viz.sh +10 -18
- package/scripts/sw-fleet.sh +13 -17
- package/scripts/sw-github-app.sh +6 -16
- package/scripts/sw-github-checks.sh +1 -11
- package/scripts/sw-github-deploy.sh +1 -11
- package/scripts/sw-github-graphql.sh +2 -12
- package/scripts/sw-guild.sh +1 -11
- package/scripts/sw-heartbeat.sh +49 -12
- package/scripts/sw-hygiene.sh +45 -43
- package/scripts/sw-incident.sh +48 -74
- package/scripts/sw-init.sh +35 -37
- package/scripts/sw-instrument.sh +1 -11
- package/scripts/sw-intelligence.sh +362 -51
- package/scripts/sw-jira.sh +5 -14
- package/scripts/sw-launchd.sh +2 -12
- package/scripts/sw-linear.sh +8 -17
- package/scripts/sw-logs.sh +4 -12
- package/scripts/sw-loop.sh +641 -90
- package/scripts/sw-memory.sh +243 -17
- package/scripts/sw-mission-control.sh +2 -12
- package/scripts/sw-model-router.sh +73 -34
- package/scripts/sw-otel.sh +11 -21
- package/scripts/sw-oversight.sh +1 -11
- package/scripts/sw-patrol-meta.sh +5 -11
- package/scripts/sw-pipeline-composer.sh +7 -17
- package/scripts/sw-pipeline-vitals.sh +1 -11
- package/scripts/sw-pipeline.sh +478 -122
- package/scripts/sw-pm.sh +2 -12
- package/scripts/sw-pr-lifecycle.sh +27 -25
- package/scripts/sw-predictive.sh +16 -22
- package/scripts/sw-prep.sh +6 -16
- package/scripts/sw-ps.sh +1 -11
- package/scripts/sw-public-dashboard.sh +2 -12
- package/scripts/sw-quality.sh +77 -10
- package/scripts/sw-reaper.sh +1 -11
- package/scripts/sw-recruit.sh +15 -25
- package/scripts/sw-regression.sh +11 -21
- package/scripts/sw-release-manager.sh +19 -28
- package/scripts/sw-release.sh +8 -16
- package/scripts/sw-remote.sh +1 -11
- package/scripts/sw-replay.sh +48 -44
- package/scripts/sw-retro.sh +70 -92
- package/scripts/sw-review-rerun.sh +1 -1
- package/scripts/sw-scale.sh +109 -32
- package/scripts/sw-security-audit.sh +12 -22
- package/scripts/sw-self-optimize.sh +239 -23
- package/scripts/sw-session.sh +3 -13
- package/scripts/sw-setup.sh +8 -18
- package/scripts/sw-standup.sh +5 -15
- package/scripts/sw-status.sh +32 -23
- package/scripts/sw-strategic.sh +129 -13
- package/scripts/sw-stream.sh +1 -11
- package/scripts/sw-swarm.sh +76 -36
- package/scripts/sw-team-stages.sh +10 -20
- package/scripts/sw-templates.sh +4 -14
- package/scripts/sw-testgen.sh +3 -13
- package/scripts/sw-tmux-pipeline.sh +1 -19
- package/scripts/sw-tmux-role-color.sh +0 -10
- package/scripts/sw-tmux-status.sh +3 -11
- package/scripts/sw-tmux.sh +2 -20
- package/scripts/sw-trace.sh +1 -19
- package/scripts/sw-tracker-github.sh +0 -10
- package/scripts/sw-tracker-jira.sh +1 -11
- package/scripts/sw-tracker-linear.sh +1 -11
- package/scripts/sw-tracker.sh +7 -24
- package/scripts/sw-triage.sh +24 -34
- package/scripts/sw-upgrade.sh +5 -23
- package/scripts/sw-ux.sh +1 -19
- package/scripts/sw-webhook.sh +18 -32
- package/scripts/sw-widgets.sh +3 -21
- package/scripts/sw-worktree.sh +11 -27
- package/scripts/update-homebrew-sha.sh +67 -0
- package/templates/pipelines/tdd.json +72 -0
- package/scripts/sw-pipeline.sh.mock +0 -7
package/scripts/sw-swarm.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="
|
|
9
|
+
VERSION="3.0.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -33,16 +33,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
33
33
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
34
34
|
}
|
|
35
35
|
fi
|
|
36
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
37
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
38
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
39
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
40
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
41
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
42
|
-
DIM="${DIM:-\033[2m}"
|
|
43
|
-
BOLD="${BOLD:-\033[1m}"
|
|
44
|
-
RESET="${RESET:-\033[0m}"
|
|
45
|
-
|
|
46
36
|
# ─── Constants ──────────────────────────────────────────────────────────────
|
|
47
37
|
SWARM_DIR="${HOME}/.shipwright/swarm"
|
|
48
38
|
REGISTRY_FILE="${SWARM_DIR}/registry.json"
|
|
@@ -197,12 +187,12 @@ cmd_spawn() {
|
|
|
197
187
|
mv "$tmp_file" "$REGISTRY_FILE" || { rm -f "$tmp_file"; error "Failed to update registry"; return 1; }
|
|
198
188
|
record_metric "$agent_id" "spawn" "1" "$agent_type"
|
|
199
189
|
|
|
200
|
-
# Create real tmux session for the agent (
|
|
201
|
-
if command -v tmux
|
|
190
|
+
# Create real tmux session for the agent (run actual daemon)
|
|
191
|
+
if command -v tmux >/dev/null 2>&1; then
|
|
202
192
|
local session_name="swarm-${agent_id}"
|
|
203
193
|
if ! tmux has-session -t "$session_name" 2>/dev/null; then
|
|
204
194
|
tmux new-session -d -s "$session_name" -c "$REPO_DIR" \
|
|
205
|
-
"
|
|
195
|
+
"SW_AGENT_ROLE=builder bash scripts/sw-daemon.sh start --role builder 2>&1 | tee /tmp/sw-swarm-${agent_id}.log" 2>/dev/null && \
|
|
206
196
|
info "Tmux session created: $session_name" || warn "Tmux session creation failed (agent still in registry)"
|
|
207
197
|
fi
|
|
208
198
|
fi
|
|
@@ -250,7 +240,7 @@ cmd_retire() {
|
|
|
250
240
|
|
|
251
241
|
# Kill real tmux session if present
|
|
252
242
|
local session_name="swarm-${agent_id}"
|
|
253
|
-
if command -v tmux
|
|
243
|
+
if command -v tmux >/dev/null 2>&1 && tmux has-session -t "$session_name" 2>/dev/null; then
|
|
254
244
|
tmux kill-session -t "$session_name" 2>/dev/null && info "Tmux session killed: $session_name" || warn "Tmux kill failed for $session_name"
|
|
255
245
|
fi
|
|
256
246
|
|
|
@@ -342,37 +332,87 @@ cmd_health() {
|
|
|
342
332
|
fi
|
|
343
333
|
}
|
|
344
334
|
|
|
335
|
+
# ─── Swarm spawn helper (for cmd_scale) ───────────────────────────────────
|
|
336
|
+
swarm_spawn_agent() {
|
|
337
|
+
local role="${1:-builder}"
|
|
338
|
+
local count="${2:-1}"
|
|
339
|
+
local i
|
|
340
|
+
for i in $(seq 1 "$count"); do
|
|
341
|
+
cmd_spawn "standard" 2>/dev/null || true
|
|
342
|
+
done
|
|
343
|
+
}
|
|
344
|
+
|
|
345
345
|
# ─── Auto-scale logic ────────────────────────────────────────────────────
|
|
346
346
|
cmd_scale() {
|
|
347
|
+
local target="${1:-auto}"
|
|
348
|
+
|
|
347
349
|
ensure_dirs
|
|
348
350
|
init_registry
|
|
349
351
|
init_config
|
|
350
352
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
+
if [[ "$target" == "auto" ]]; then
|
|
354
|
+
# Auto-scale based on queue depth
|
|
355
|
+
local queue_depth=0
|
|
356
|
+
local state_file="$HOME/.shipwright/daemon-state.json"
|
|
357
|
+
if [[ -f "$state_file" ]]; then
|
|
358
|
+
queue_depth=$(jq '.queued | length' "$state_file" 2>/dev/null || echo "0")
|
|
359
|
+
fi
|
|
353
360
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return 0
|
|
357
|
-
fi
|
|
361
|
+
local current_agents
|
|
362
|
+
current_agents=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -cE '^shipwright-sw-agent|^swarm-' || echo "0")
|
|
358
363
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
364
|
+
local target_agents=1
|
|
365
|
+
if [[ "$queue_depth" -gt 5 ]]; then
|
|
366
|
+
target_agents=3
|
|
367
|
+
elif [[ "$queue_depth" -gt 2 ]]; then
|
|
368
|
+
target_agents=2
|
|
369
|
+
fi
|
|
363
370
|
|
|
364
|
-
|
|
365
|
-
|
|
371
|
+
if [[ "$current_agents" -lt "$target_agents" ]]; then
|
|
372
|
+
local to_spawn=$((target_agents - current_agents))
|
|
373
|
+
echo "Queue depth: $queue_depth, scaling up by $to_spawn"
|
|
374
|
+
swarm_spawn_agent "builder" "$to_spawn"
|
|
375
|
+
elif [[ "$current_agents" -gt "$target_agents" && "$current_agents" -gt 1 ]]; then
|
|
376
|
+
local to_retire=$((current_agents - target_agents))
|
|
377
|
+
echo "Queue depth: $queue_depth, scaling down by $to_retire"
|
|
378
|
+
# Retire oldest agents from registry (tmux sessions are managed by scale down)
|
|
379
|
+
local registry_count
|
|
380
|
+
registry_count=$(jq -r '.agents | length' "$REGISTRY_FILE" 2>/dev/null || echo "0")
|
|
381
|
+
local retired=0
|
|
382
|
+
if [[ "$registry_count" -gt 0 ]] && [[ "$to_retire" -gt 0 ]]; then
|
|
383
|
+
local agent_id
|
|
384
|
+
agent_id=$(jq -r '.agents[0].id // empty' "$REGISTRY_FILE" 2>/dev/null)
|
|
385
|
+
if [[ -n "$agent_id" ]]; then
|
|
386
|
+
cmd_retire "$agent_id" 2>/dev/null && retired=1 || true
|
|
387
|
+
fi
|
|
388
|
+
fi
|
|
389
|
+
else
|
|
390
|
+
echo "Queue depth: $queue_depth, agents: $current_agents (optimal)"
|
|
391
|
+
fi
|
|
392
|
+
else
|
|
393
|
+
# Scale to specific count - show current state
|
|
394
|
+
local auto_scale_enabled
|
|
395
|
+
auto_scale_enabled=$(jq -r '.auto_scaling_enabled' "$CONFIG_FILE")
|
|
366
396
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
397
|
+
if [[ "$auto_scale_enabled" != "true" ]]; then
|
|
398
|
+
warn "Auto-scaling is disabled"
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
local min_agents max_agents target_util
|
|
402
|
+
min_agents=$(jq -r '.min_agents // 1' "$CONFIG_FILE")
|
|
403
|
+
max_agents=$(jq -r '.max_agents // 8' "$CONFIG_FILE")
|
|
404
|
+
target_util=$(jq -r '.target_utilization // 0.75' "$CONFIG_FILE")
|
|
405
|
+
|
|
406
|
+
local active_count
|
|
407
|
+
active_count=$(jq -r '.active_count // 0' "$REGISTRY_FILE")
|
|
408
|
+
|
|
409
|
+
info "Auto-Scaling Analysis"
|
|
410
|
+
echo ""
|
|
411
|
+
echo -e " Current agents: ${CYAN}${active_count}/${max_agents}${RESET}"
|
|
412
|
+
echo -e " Min agents: ${CYAN}${min_agents}${RESET}"
|
|
413
|
+
echo -e " Target utilization: ${CYAN}${target_util}${RESET}"
|
|
414
|
+
echo ""
|
|
415
|
+
fi
|
|
376
416
|
}
|
|
377
417
|
|
|
378
418
|
# ─── Performance leaderboard ──────────────────────────────────────────────
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="
|
|
9
|
+
VERSION="3.0.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -34,16 +34,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
34
34
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
35
35
|
}
|
|
36
36
|
fi
|
|
37
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
38
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
39
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
40
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
41
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
42
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
43
|
-
DIM="${DIM:-\033[2m}"
|
|
44
|
-
BOLD="${BOLD:-\033[1m}"
|
|
45
|
-
RESET="${RESET:-\033[0m}"
|
|
46
|
-
|
|
47
37
|
# ─── Structured Event Log ──────────────────────────────────────────────────
|
|
48
38
|
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
49
39
|
|
|
@@ -182,7 +172,7 @@ cmd_delegate() {
|
|
|
182
172
|
result: null
|
|
183
173
|
}')
|
|
184
174
|
tasks=$(echo "$tasks" | jq ". += [$task_json]")
|
|
185
|
-
((file_count
|
|
175
|
+
file_count=$((file_count + 1))
|
|
186
176
|
done < <(echo "$changed_files")
|
|
187
177
|
|
|
188
178
|
# Output delegation result
|
|
@@ -216,7 +206,7 @@ cmd_status() {
|
|
|
216
206
|
for team_file in "$TEAM_STATE_DIR"/*.json; do
|
|
217
207
|
[[ -f "$team_file" ]] || continue
|
|
218
208
|
local ts
|
|
219
|
-
ts=$(
|
|
209
|
+
ts=$(file_mtime "$team_file")
|
|
220
210
|
local name
|
|
221
211
|
name=$(basename "$team_file" .json)
|
|
222
212
|
local status
|
|
@@ -255,7 +245,7 @@ cmd_status() {
|
|
|
255
245
|
local spec_status
|
|
256
246
|
spec_status=$(echo "$team_json" | jq -r ".specialist_status[$spec_idx] // \"pending\"" 2>/dev/null || echo "pending")
|
|
257
247
|
printf " ${DIM}%-3d${RESET} %-20s %-15s\n" "$((spec_idx + 1))" "$spec" "$spec_status"
|
|
258
|
-
((spec_idx
|
|
248
|
+
spec_idx=$((spec_idx + 1))
|
|
259
249
|
done < <(echo "$specs")
|
|
260
250
|
echo ""
|
|
261
251
|
}
|
|
@@ -292,11 +282,11 @@ cmd_vote() {
|
|
|
292
282
|
local verdict
|
|
293
283
|
verdict=$(echo "$team_json" | jq -r ".verdicts[\"$spec\"]? // \"neutral\"" 2>/dev/null || echo "neutral")
|
|
294
284
|
case "$verdict" in
|
|
295
|
-
approve) ((approve_count
|
|
296
|
-
reject) ((reject_count
|
|
297
|
-
*) ((neutral_count
|
|
285
|
+
approve) approve_count=$((approve_count + 1)) ;;
|
|
286
|
+
reject) reject_count=$((reject_count + 1)) ;;
|
|
287
|
+
*) neutral_count=$((neutral_count + 1)) ;;
|
|
298
288
|
esac
|
|
299
|
-
((total
|
|
289
|
+
total=$((total + 1))
|
|
300
290
|
done < <(echo "$specs")
|
|
301
291
|
|
|
302
292
|
# Consensus: majority vote with leader tiebreak
|
|
@@ -370,9 +360,9 @@ cmd_aggregate() {
|
|
|
370
360
|
|
|
371
361
|
if [[ -n "$result" ]]; then
|
|
372
362
|
if echo "$result" | jq -e '.success' >/dev/null 2>&1; then
|
|
373
|
-
((success_count
|
|
363
|
+
success_count=$((success_count + 1))
|
|
374
364
|
else
|
|
375
|
-
((failure_count
|
|
365
|
+
failure_count=$((failure_count + 1))
|
|
376
366
|
fi
|
|
377
367
|
results=$(echo "$results" | jq ". += [$result]")
|
|
378
368
|
fi
|
package/scripts/sw-templates.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Templates define reusable agent team configurations (roles, layout, ║
|
|
6
6
|
# ║ focus areas) that shipwright session --template can use to scaffold teams. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="
|
|
8
|
+
VERSION="3.0.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
|
@@ -35,16 +35,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
35
35
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
36
36
|
}
|
|
37
37
|
fi
|
|
38
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
39
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
40
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
41
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
42
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
43
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
44
|
-
DIM="${DIM:-\033[2m}"
|
|
45
|
-
BOLD="${BOLD:-\033[1m}"
|
|
46
|
-
RESET="${RESET:-\033[0m}"
|
|
47
|
-
|
|
48
38
|
# ─── Template Discovery ─────────────────────────────────────────────────────
|
|
49
39
|
REPO_TEMPLATES_DIR="$(cd "$SCRIPT_DIR/../tmux/templates" 2>/dev/null && pwd)" || REPO_TEMPLATES_DIR=""
|
|
50
40
|
USER_TEMPLATES_DIR="${HOME}/.shipwright/templates"
|
|
@@ -79,7 +69,7 @@ find_template() {
|
|
|
79
69
|
# Extract a top-level string field from JSON
|
|
80
70
|
json_field() {
|
|
81
71
|
local file="$1" field="$2"
|
|
82
|
-
if command -v jq
|
|
72
|
+
if command -v jq >/dev/null 2>&1; then
|
|
83
73
|
jq -r ".${field} // \"\"" "$file" 2>/dev/null
|
|
84
74
|
else
|
|
85
75
|
grep -o "\"${field}\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$file" | head -1 | sed 's/.*: *"//;s/"$//'
|
|
@@ -89,7 +79,7 @@ json_field() {
|
|
|
89
79
|
# Extract agent count from JSON
|
|
90
80
|
json_agent_count() {
|
|
91
81
|
local file="$1"
|
|
92
|
-
if command -v jq
|
|
82
|
+
if command -v jq >/dev/null 2>&1; then
|
|
93
83
|
jq -r '.agents // [] | length' "$file" 2>/dev/null
|
|
94
84
|
else
|
|
95
85
|
grep -c '"name"' "$file" 2>/dev/null || echo "0"
|
|
@@ -99,7 +89,7 @@ json_agent_count() {
|
|
|
99
89
|
# Print agent details from a template
|
|
100
90
|
print_agents() {
|
|
101
91
|
local file="$1"
|
|
102
|
-
if command -v jq
|
|
92
|
+
if command -v jq >/dev/null 2>&1; then
|
|
103
93
|
jq -r '.agents // [] | .[] | "\(.name // "?")|\(.role // "")|\(.focus // "")"' "$file" 2>/dev/null
|
|
104
94
|
else
|
|
105
95
|
# Best-effort grep fallback for simple cases
|
package/scripts/sw-testgen.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="
|
|
9
|
+
VERSION="3.0.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Handle subcommands ───────────────────────────────────────────────────────
|
|
@@ -38,16 +38,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
38
38
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
39
39
|
}
|
|
40
40
|
fi
|
|
41
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
42
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
43
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
44
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
45
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
46
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
47
|
-
DIM="${DIM:-\033[2m}"
|
|
48
|
-
BOLD="${BOLD:-\033[1m}"
|
|
49
|
-
RESET="${RESET:-\033[0m}"
|
|
50
|
-
|
|
51
41
|
# ─── Configuration ───────────────────────────────────────────────────────────
|
|
52
42
|
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
53
43
|
SCRIPTS_DIR="$PROJECT_ROOT/scripts"
|
|
@@ -210,7 +200,7 @@ EOF
|
|
|
210
200
|
# Generate test template; use Claude for real assertions when available
|
|
211
201
|
local test_template_file="$TESTGEN_DIR/generated-tests.sh"
|
|
212
202
|
local use_claude="false"
|
|
213
|
-
command -v claude
|
|
203
|
+
command -v claude >/dev/null 2>&1 && use_claude="true"
|
|
214
204
|
[[ "${TESTGEN_USE_CLAUDE:-true}" == "false" ]] && use_claude="false"
|
|
215
205
|
|
|
216
206
|
{
|
|
@@ -468,7 +458,7 @@ detect_regressions() {
|
|
|
468
458
|
[[ "$(basename "$test_file")" == "sw-testgen-test.sh" ]] && continue
|
|
469
459
|
|
|
470
460
|
local result
|
|
471
|
-
if bash "$test_file"
|
|
461
|
+
if bash "$test_file" >/dev/null 2>&1; then
|
|
472
462
|
result="PASS"
|
|
473
463
|
else
|
|
474
464
|
result="FAIL"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="
|
|
9
|
+
VERSION="3.0.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -26,24 +26,6 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
|
|
|
26
26
|
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
27
27
|
now_epoch() { date +%s; }
|
|
28
28
|
fi
|
|
29
|
-
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
30
|
-
emit_event() {
|
|
31
|
-
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
32
|
-
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
33
|
-
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
34
|
-
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
35
|
-
}
|
|
36
|
-
fi
|
|
37
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
38
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
39
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
40
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
41
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
42
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
43
|
-
DIM="${DIM:-\033[2m}"
|
|
44
|
-
BOLD="${BOLD:-\033[1m}"
|
|
45
|
-
RESET="${RESET:-\033[0m}"
|
|
46
|
-
|
|
47
29
|
# Get daemon session name
|
|
48
30
|
get_daemon_session() {
|
|
49
31
|
echo "sw-daemon"
|
|
@@ -39,16 +39,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
39
39
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
40
40
|
}
|
|
41
41
|
fi
|
|
42
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
43
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
44
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
45
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
46
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
47
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
48
|
-
DIM="${DIM:-\033[2m}"
|
|
49
|
-
BOLD="${BOLD:-\033[1m}"
|
|
50
|
-
RESET="${RESET:-\033[0m}"
|
|
51
|
-
|
|
52
42
|
# Get the active pane's title
|
|
53
43
|
PANE_TITLE="$(tmux display-message -p '#{pane_title}' 2>/dev/null || echo "")"
|
|
54
44
|
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
|
|
11
11
|
SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
|
12
|
+
# shellcheck source=lib/compat.sh
|
|
13
|
+
[[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
|
|
12
14
|
# Canonical helpers (colors, output, events)
|
|
13
15
|
# shellcheck source=lib/helpers.sh
|
|
14
16
|
[[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
|
|
@@ -29,16 +31,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
29
31
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
30
32
|
}
|
|
31
33
|
fi
|
|
32
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
33
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
34
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
35
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
36
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
37
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
38
|
-
DIM="${DIM:-\033[2m}"
|
|
39
|
-
BOLD="${BOLD:-\033[1m}"
|
|
40
|
-
RESET="${RESET:-\033[0m}"
|
|
41
|
-
|
|
42
34
|
# ─── Stage colors (match Shipwright brand palette) ────────────────────────
|
|
43
35
|
# Each pipeline stage gets a distinct color for instant visual recognition
|
|
44
36
|
stage_color() {
|
|
@@ -128,7 +120,7 @@ agent_widget() {
|
|
|
128
120
|
# Heartbeat is alive if updated within last 60 seconds
|
|
129
121
|
local mtime
|
|
130
122
|
if [[ "$(uname)" == "Darwin" ]]; then
|
|
131
|
-
mtime="$(
|
|
123
|
+
mtime="$(file_mtime "$hb")"
|
|
132
124
|
else
|
|
133
125
|
mtime="$(stat -c %Y "$hb" 2>/dev/null || echo 0)"
|
|
134
126
|
fi
|
package/scripts/sw-tmux.sh
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# ║ shipwright tmux fix — Auto-fix common issues ║
|
|
12
12
|
# ║ shipwright tmux reload — Reload tmux config ║
|
|
13
13
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
14
|
-
VERSION="
|
|
14
|
+
VERSION="3.0.0"
|
|
15
15
|
set -euo pipefail
|
|
16
16
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
17
17
|
|
|
@@ -34,24 +34,6 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
|
|
|
34
34
|
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
35
35
|
now_epoch() { date +%s; }
|
|
36
36
|
fi
|
|
37
|
-
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
38
|
-
emit_event() {
|
|
39
|
-
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
40
|
-
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
41
|
-
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
42
|
-
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
43
|
-
}
|
|
44
|
-
fi
|
|
45
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
46
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
47
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
48
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
49
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
50
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
51
|
-
DIM="${DIM:-\033[2m}"
|
|
52
|
-
BOLD="${BOLD:-\033[1m}"
|
|
53
|
-
RESET="${RESET:-\033[0m}"
|
|
54
|
-
|
|
55
37
|
PASS=0
|
|
56
38
|
WARN=0
|
|
57
39
|
FAIL=0
|
|
@@ -73,7 +55,7 @@ tmux_doctor() {
|
|
|
73
55
|
|
|
74
56
|
# ─── 1. tmux installed + version ─────────────────────────────────────
|
|
75
57
|
echo -e "${BOLD}1. tmux Version${RESET}"
|
|
76
|
-
if ! command -v tmux
|
|
58
|
+
if ! command -v tmux >/dev/null 2>&1; then
|
|
77
59
|
check_fail "tmux not installed"
|
|
78
60
|
echo -e " ${DIM}brew install tmux (macOS)${RESET}"
|
|
79
61
|
echo -e " ${DIM}sudo apt install tmux (Ubuntu/Debian)${RESET}"
|
package/scripts/sw-trace.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="
|
|
9
|
+
VERSION="3.0.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -26,24 +26,6 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
|
|
|
26
26
|
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
27
27
|
now_epoch() { date +%s; }
|
|
28
28
|
fi
|
|
29
|
-
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
30
|
-
emit_event() {
|
|
31
|
-
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
32
|
-
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
33
|
-
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
34
|
-
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
35
|
-
}
|
|
36
|
-
fi
|
|
37
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
38
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
39
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
40
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
41
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
42
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
43
|
-
DIM="${DIM:-\033[2m}"
|
|
44
|
-
BOLD="${BOLD:-\033[1m}"
|
|
45
|
-
RESET="${RESET:-\033[0m}"
|
|
46
|
-
|
|
47
29
|
# ─── Data Paths ─────────────────────────────────────────────────────────────
|
|
48
30
|
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
49
31
|
SHIPWRIGHT_DIR="${REPO_DIR}/.claude/pipeline-artifacts"
|
|
@@ -28,16 +28,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
28
28
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
29
29
|
}
|
|
30
30
|
fi
|
|
31
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
32
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
33
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
34
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
35
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
36
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
37
|
-
DIM="${DIM:-\033[2m}"
|
|
38
|
-
BOLD="${BOLD:-\033[1m}"
|
|
39
|
-
RESET="${RESET:-\033[0m}"
|
|
40
|
-
|
|
41
31
|
# ─── Discovery & CRUD Interface ────────────────────────────────────────────
|
|
42
32
|
# All functions output normalized JSON (or plain text where specified).
|
|
43
33
|
# Input: normalized arguments (label, state, issue_id, etc.)
|
|
@@ -28,16 +28,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
28
28
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
29
29
|
}
|
|
30
30
|
fi
|
|
31
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
32
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
33
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
34
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
35
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
36
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
37
|
-
DIM="${DIM:-\033[2m}"
|
|
38
|
-
BOLD="${BOLD:-\033[1m}"
|
|
39
|
-
RESET="${RESET:-\033[0m}"
|
|
40
|
-
|
|
41
31
|
# ─── Status Auto-Discovery ────────────────────────────────────────────────
|
|
42
32
|
# Queries Jira API for project statuses and caches the transition name mapping.
|
|
43
33
|
# Only fills in JIRA_TRANSITION_* values that are empty (config/env takes priority).
|
|
@@ -158,7 +148,7 @@ jira_api() {
|
|
|
158
148
|
local auth
|
|
159
149
|
auth=$(printf '%s:%s' "$JIRA_EMAIL" "$JIRA_API_TOKEN" | base64)
|
|
160
150
|
|
|
161
|
-
local args=(-sf -X "$method" \
|
|
151
|
+
local args=(-sf --connect-timeout 10 --max-time 30 -X "$method" \
|
|
162
152
|
-H "Authorization: Basic $auth" \
|
|
163
153
|
-H "Content-Type: application/json")
|
|
164
154
|
|
|
@@ -28,16 +28,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
28
28
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
29
29
|
}
|
|
30
30
|
fi
|
|
31
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
32
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
33
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
34
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
35
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
36
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
37
|
-
DIM="${DIM:-\033[2m}"
|
|
38
|
-
BOLD="${BOLD:-\033[1m}"
|
|
39
|
-
RESET="${RESET:-\033[0m}"
|
|
40
|
-
|
|
41
31
|
# ─── Status Auto-Discovery ────────────────────────────────────────────────
|
|
42
32
|
# Queries Linear API for workflow states and caches the mapping.
|
|
43
33
|
# Only fills in STATUS_* values that are empty (config/env takes priority).
|
|
@@ -175,7 +165,7 @@ linear_graphql() {
|
|
|
175
165
|
payload=$(jq -n --arg q "$query" --argjson v "$variables" '{query: $q, variables: $v}')
|
|
176
166
|
|
|
177
167
|
local response
|
|
178
|
-
response=$(curl -sf -X POST "$LINEAR_API" \
|
|
168
|
+
response=$(curl -sf --connect-timeout 10 --max-time 30 -X POST "$LINEAR_API" \
|
|
179
169
|
-H "Authorization: $LINEAR_API_KEY" \
|
|
180
170
|
-H "Content-Type: application/json" \
|
|
181
171
|
-d "$payload" 2>&1) || {
|