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-recruit.sh
CHANGED
|
@@ -14,7 +14,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
14
14
|
RECRUIT_VERSION="3.0.0"
|
|
15
15
|
|
|
16
16
|
# ─── Dependency check ─────────────────────────────────────────────────────────
|
|
17
|
-
if ! command -v jq
|
|
17
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
18
18
|
echo "ERROR: sw-recruit.sh requires 'jq' (JSON processor). Install with:" >&2
|
|
19
19
|
echo " macOS: brew install jq" >&2
|
|
20
20
|
echo " Ubuntu: sudo apt install jq" >&2
|
|
@@ -45,16 +45,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
45
45
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
46
46
|
}
|
|
47
47
|
fi
|
|
48
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
49
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
50
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
51
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
52
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
53
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
54
|
-
DIM="${DIM:-\033[2m}"
|
|
55
|
-
BOLD="${BOLD:-\033[1m}"
|
|
56
|
-
RESET="${RESET:-\033[0m}"
|
|
57
|
-
|
|
58
48
|
# ─── File Locking for Concurrent Safety ────────────────────────────────────
|
|
59
49
|
# Usage: _recruit_locked_write <target_file> <tmp_file>
|
|
60
50
|
# Acquires flock, then moves tmp_file to target atomically.
|
|
@@ -65,7 +55,7 @@ _recruit_locked_write() {
|
|
|
65
55
|
local lock_file="${target}.lock"
|
|
66
56
|
|
|
67
57
|
(
|
|
68
|
-
if command -v flock
|
|
58
|
+
if command -v flock >/dev/null 2>&1; then
|
|
69
59
|
flock -w 5 200 2>/dev/null || true
|
|
70
60
|
fi
|
|
71
61
|
mv "$tmp_file" "$target"
|
|
@@ -90,7 +80,7 @@ POLICY_FILE="${SCRIPT_DIR}/../config/policy.json"
|
|
|
90
80
|
_recruit_policy() {
|
|
91
81
|
local key="$1"
|
|
92
82
|
local default="$2"
|
|
93
|
-
if [[ -f "$POLICY_FILE" ]] && command -v jq
|
|
83
|
+
if [[ -f "$POLICY_FILE" ]] && command -v jq >/dev/null 2>&1; then
|
|
94
84
|
local val
|
|
95
85
|
val=$(jq -r ".recruit.${key} // empty" "$POLICY_FILE" 2>/dev/null) || true
|
|
96
86
|
[[ -n "$val" ]] && echo "$val" || echo "$default"
|
|
@@ -133,7 +123,7 @@ fi
|
|
|
133
123
|
# Set SW_RECRUIT_NO_LLM=1 to disable LLM calls (e.g., in tests)
|
|
134
124
|
_recruit_has_claude() {
|
|
135
125
|
[[ "${SW_RECRUIT_NO_LLM:-}" == "1" ]] && return 1
|
|
136
|
-
command -v claude
|
|
126
|
+
command -v claude >/dev/null 2>&1
|
|
137
127
|
}
|
|
138
128
|
|
|
139
129
|
# Call Claude with a prompt, return text. Falls back gracefully.
|
|
@@ -144,7 +134,7 @@ _recruit_call_claude() {
|
|
|
144
134
|
# Honor the no-LLM flag everywhere (not just _recruit_has_claude)
|
|
145
135
|
[[ "${SW_RECRUIT_NO_LLM:-}" == "1" ]] && { echo ""; return; }
|
|
146
136
|
|
|
147
|
-
if [[ "$INTELLIGENCE_AVAILABLE" == "true" ]] && command -v _intelligence_call_claude
|
|
137
|
+
if [[ "$INTELLIGENCE_AVAILABLE" == "true" ]] && command -v _intelligence_call_claude >/dev/null 2>&1; then
|
|
148
138
|
_intelligence_call_claude "$prompt" 2>/dev/null || echo ""
|
|
149
139
|
return
|
|
150
140
|
fi
|
|
@@ -164,7 +154,7 @@ _recruit_call_claude() {
|
|
|
164
154
|
initialize_builtin_roles() {
|
|
165
155
|
ensure_recruit_dir
|
|
166
156
|
|
|
167
|
-
if jq -e '.architect' "$ROLES_DB"
|
|
157
|
+
if jq -e '.architect' "$ROLES_DB" >/dev/null 2>&1; then
|
|
168
158
|
return 0
|
|
169
159
|
fi
|
|
170
160
|
|
|
@@ -385,7 +375,7 @@ Return JSON only, no markdown fences."
|
|
|
385
375
|
local result
|
|
386
376
|
result=$(_recruit_call_claude "$prompt")
|
|
387
377
|
|
|
388
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e '.primary_role'
|
|
378
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e '.primary_role' >/dev/null 2>&1; then
|
|
389
379
|
echo "$result"
|
|
390
380
|
return 0
|
|
391
381
|
fi
|
|
@@ -483,7 +473,7 @@ Return JSON only."
|
|
|
483
473
|
local result
|
|
484
474
|
result=$(_recruit_call_claude "$prompt")
|
|
485
475
|
|
|
486
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e '.key'
|
|
476
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e '.key' >/dev/null 2>&1; then
|
|
487
477
|
role_key=$(echo "$result" | jq -r '.key')
|
|
488
478
|
role_title=$(echo "$result" | jq -r '.title')
|
|
489
479
|
role_desc=$(echo "$result" | jq -r '.description')
|
|
@@ -1042,7 +1032,7 @@ cmd_team() {
|
|
|
1042
1032
|
|
|
1043
1033
|
# Gather codebase context if in a git repo
|
|
1044
1034
|
local codebase_context=""
|
|
1045
|
-
if command -v git
|
|
1035
|
+
if command -v git >/dev/null 2>&1 && git rev-parse --git-dir >/dev/null 2>&1; then
|
|
1046
1036
|
local file_count lang_summary
|
|
1047
1037
|
file_count=$(git ls-files 2>/dev/null | wc -l | tr -d ' ')
|
|
1048
1038
|
lang_summary=$(git ls-files 2>/dev/null | grep -oE '\.[^.]+$' | sort | uniq -c | sort -rn | head -5 | tr '\n' ';' || echo "unknown")
|
|
@@ -1069,7 +1059,7 @@ Return JSON only."
|
|
|
1069
1059
|
local result
|
|
1070
1060
|
result=$(_recruit_call_claude "$prompt")
|
|
1071
1061
|
|
|
1072
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e '.team'
|
|
1062
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e '.team' >/dev/null 2>&1; then
|
|
1073
1063
|
while IFS= read -r role; do
|
|
1074
1064
|
[[ -z "$role" || "$role" == "null" ]] && continue
|
|
1075
1065
|
recommended_team+=("$role")
|
|
@@ -1439,7 +1429,7 @@ Return JSON only."
|
|
|
1439
1429
|
local result
|
|
1440
1430
|
result=$(_recruit_call_claude "$prompt")
|
|
1441
1431
|
|
|
1442
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e '.roles | length > 0'
|
|
1432
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e '.roles | length > 0' >/dev/null 2>&1; then
|
|
1443
1433
|
local new_count
|
|
1444
1434
|
new_count=$(echo "$result" | jq '.roles | length')
|
|
1445
1435
|
|
|
@@ -1596,7 +1586,7 @@ Return JSON only."
|
|
|
1596
1586
|
local result
|
|
1597
1587
|
result=$(_recruit_call_claude "$prompt")
|
|
1598
1588
|
|
|
1599
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e '.working_style'
|
|
1589
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e '.working_style' >/dev/null 2>&1; then
|
|
1600
1590
|
# Save the LLM-generated mind profile
|
|
1601
1591
|
local tmp_file
|
|
1602
1592
|
tmp_file=$(mktemp)
|
|
@@ -1700,7 +1690,7 @@ Return JSON only."
|
|
|
1700
1690
|
local result
|
|
1701
1691
|
result=$(_recruit_call_claude "$prompt")
|
|
1702
1692
|
|
|
1703
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e '.sub_tasks'
|
|
1693
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e '.sub_tasks' >/dev/null 2>&1; then
|
|
1704
1694
|
local restated_goal
|
|
1705
1695
|
restated_goal=$(echo "$result" | jq -r '.goal // ""')
|
|
1706
1696
|
[[ -n "$restated_goal" ]] && echo -e " ${DIM}Interpreted as: ${restated_goal}${RESET}"
|
|
@@ -1926,7 +1916,7 @@ cmd_match() {
|
|
|
1926
1916
|
local llm_result
|
|
1927
1917
|
llm_result=$(_recruit_llm_match "$task_description" "$available_roles")
|
|
1928
1918
|
|
|
1929
|
-
if [[ -n "$llm_result" ]] && echo "$llm_result" | jq -e '.primary_role'
|
|
1919
|
+
if [[ -n "$llm_result" ]] && echo "$llm_result" | jq -e '.primary_role' >/dev/null 2>&1; then
|
|
1930
1920
|
primary_role=$(echo "$llm_result" | jq -r '.primary_role')
|
|
1931
1921
|
secondary_roles=$(echo "$llm_result" | jq -r '.secondary_roles // [] | join(", ")')
|
|
1932
1922
|
confidence=$(echo "$llm_result" | jq -r '.confidence // 0.8')
|
|
@@ -1961,7 +1951,7 @@ cmd_match() {
|
|
|
1961
1951
|
fi
|
|
1962
1952
|
|
|
1963
1953
|
# Validate role exists
|
|
1964
|
-
if ! jq -e ".\"${primary_role}\"" "$ROLES_DB"
|
|
1954
|
+
if ! jq -e ".\"${primary_role}\"" "$ROLES_DB" >/dev/null 2>&1; then
|
|
1965
1955
|
primary_role="builder"
|
|
1966
1956
|
fi
|
|
1967
1957
|
|
package/scripts/sw-regression.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
|
|
|
@@ -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
|
format_duration() {
|
|
48
38
|
local secs="$1"
|
|
49
39
|
if [[ "$secs" -ge 3600 ]]; then
|
|
@@ -134,7 +124,7 @@ collect_script_metrics() {
|
|
|
134
124
|
# Check for syntax errors
|
|
135
125
|
while IFS= read -r script; do
|
|
136
126
|
if ! bash -n "$script" 2>/dev/null; then
|
|
137
|
-
((syntax_errors
|
|
127
|
+
syntax_errors=$((syntax_errors + 1))
|
|
138
128
|
fi
|
|
139
129
|
done < <(find "$REPO_DIR/scripts" -maxdepth 1 -name "*.sh" -type f 2>/dev/null)
|
|
140
130
|
|
|
@@ -291,14 +281,14 @@ cmd_check() {
|
|
|
291
281
|
# Metric should not decrease
|
|
292
282
|
if (( $(echo "$current_val_num < $baseline_val_num" | bc -l 2>/dev/null || echo "0") )); then
|
|
293
283
|
echo -e "${RED}✗ $name: $baseline_val_num → $current_val_num (${pct_diff}%)${RESET}"
|
|
294
|
-
((regressions
|
|
284
|
+
regressions=$((regressions + 1))
|
|
295
285
|
return 1
|
|
296
286
|
fi
|
|
297
287
|
elif [[ "$direction" == "increase" ]]; then
|
|
298
288
|
# Metric should not increase beyond threshold
|
|
299
289
|
if (( $(echo "$pct_diff > $threshold_val" | bc -l 2>/dev/null || echo "0") )); then
|
|
300
290
|
echo -e "${RED}✗ $name: $baseline_val_num → $current_val_num (+${pct_diff}%)${RESET}"
|
|
301
|
-
((regressions
|
|
291
|
+
regressions=$((regressions + 1))
|
|
302
292
|
return 1
|
|
303
293
|
fi
|
|
304
294
|
fi
|
|
@@ -306,10 +296,10 @@ cmd_check() {
|
|
|
306
296
|
# Improvement
|
|
307
297
|
if [[ "$direction" == "decrease" ]] && (( $(echo "$current_val_num > $baseline_val_num" | bc -l 2>/dev/null || echo "0") )); then
|
|
308
298
|
echo -e "${GREEN}✓ $name: $baseline_val_num → $current_val_num (improved)${RESET}"
|
|
309
|
-
((improvements
|
|
299
|
+
improvements=$((improvements + 1))
|
|
310
300
|
elif [[ "$direction" == "increase" ]] && (( $(echo "$current_val_num < $baseline_val_num" | bc -l 2>/dev/null || echo "0") )); then
|
|
311
301
|
echo -e "${GREEN}✓ $name: $baseline_val_num → $current_val_num (improved)${RESET}"
|
|
312
|
-
((improvements
|
|
302
|
+
improvements=$((improvements + 1))
|
|
313
303
|
fi
|
|
314
304
|
}
|
|
315
305
|
|
|
@@ -335,10 +325,10 @@ cmd_check() {
|
|
|
335
325
|
pass_rate_diff=$(awk "BEGIN { printf \"%.1f\", ($base_pass_rate - $curr_pass_rate) }")
|
|
336
326
|
if (( $(echo "$pass_rate_diff > $pass_rate_threshold" | bc -l 2>/dev/null || echo "0") )); then
|
|
337
327
|
echo -e "${RED}✗ Pass Rate: $base_pass_rate% → $curr_pass_rate% (drop: ${pass_rate_diff}%)${RESET}"
|
|
338
|
-
((regressions
|
|
328
|
+
regressions=$((regressions + 1))
|
|
339
329
|
elif (( $(echo "$curr_pass_rate > $base_pass_rate" | bc -l 2>/dev/null || echo "0") )); then
|
|
340
330
|
echo -e "${GREEN}✓ Pass Rate: $base_pass_rate% → $curr_pass_rate%${RESET}"
|
|
341
|
-
((improvements
|
|
331
|
+
improvements=$((improvements + 1))
|
|
342
332
|
else
|
|
343
333
|
echo -e "${DIM}= Pass Rate: $base_pass_rate% → $curr_pass_rate%${RESET}"
|
|
344
334
|
fi
|
|
@@ -373,10 +363,10 @@ cmd_check() {
|
|
|
373
363
|
curr_syntax_errors=$(echo "$current" | jq -r '.syntax_errors // 0')
|
|
374
364
|
if [[ "$curr_syntax_errors" -gt "$base_syntax_errors" ]]; then
|
|
375
365
|
echo -e "${RED}✗ Syntax Errors: $base_syntax_errors → $curr_syntax_errors${RESET}"
|
|
376
|
-
((regressions
|
|
366
|
+
regressions=$((regressions + 1))
|
|
377
367
|
elif [[ "$curr_syntax_errors" -lt "$base_syntax_errors" ]]; then
|
|
378
368
|
echo -e "${GREEN}✓ Syntax Errors: $base_syntax_errors → $curr_syntax_errors${RESET}"
|
|
379
|
-
((improvements
|
|
369
|
+
improvements=$((improvements + 1))
|
|
380
370
|
else
|
|
381
371
|
echo -e "${DIM}= Syntax Errors: $base_syntax_errors → $curr_syntax_errors${RESET}"
|
|
382
372
|
fi
|
|
@@ -510,7 +500,7 @@ cmd_history() {
|
|
|
510
500
|
|
|
511
501
|
local count=0
|
|
512
502
|
while IFS= read -r baseline_file; do
|
|
513
|
-
((count
|
|
503
|
+
count=$((count + 1))
|
|
514
504
|
if [[ "$count" -gt 10 ]]; then
|
|
515
505
|
break
|
|
516
506
|
fi
|
|
@@ -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
|
# ─── Structured Event Log ──────────────────────────────────────────────────
|
|
48
30
|
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
49
31
|
|
|
@@ -133,7 +115,9 @@ check_tests_passing() {
|
|
|
133
115
|
return 0
|
|
134
116
|
fi
|
|
135
117
|
|
|
136
|
-
|
|
118
|
+
local _test_log
|
|
119
|
+
_test_log=$(mktemp "${TMPDIR:-/tmp}/sw-test-output.XXXXXX")
|
|
120
|
+
if ! npm test 2>&1 | tee "$_test_log" | tail -20; then
|
|
137
121
|
error "Tests are not passing"
|
|
138
122
|
return 1
|
|
139
123
|
fi
|
|
@@ -171,7 +155,7 @@ check_coverage_threshold() {
|
|
|
171
155
|
check_no_open_blockers() {
|
|
172
156
|
info "Checking for open blockers..."
|
|
173
157
|
|
|
174
|
-
if ! command -v gh
|
|
158
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
175
159
|
warn "GitHub CLI not available — skipping blocker check"
|
|
176
160
|
return 0
|
|
177
161
|
fi
|
|
@@ -191,13 +175,20 @@ check_no_open_blockers() {
|
|
|
191
175
|
check_security_scan() {
|
|
192
176
|
info "Checking security scan status..."
|
|
193
177
|
|
|
194
|
-
if ! command -v gh
|
|
178
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
195
179
|
warn "GitHub CLI not available — skipping security check"
|
|
196
180
|
return 0
|
|
197
181
|
fi
|
|
198
182
|
|
|
183
|
+
local repo_nwo
|
|
184
|
+
repo_nwo=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null || echo "")
|
|
185
|
+
if [[ -z "$repo_nwo" ]]; then
|
|
186
|
+
warn "Could not determine repository — skipping security check"
|
|
187
|
+
return 0
|
|
188
|
+
fi
|
|
189
|
+
|
|
199
190
|
local vulns
|
|
200
|
-
vulns=$(gh api repos
|
|
191
|
+
vulns=$(gh api "repos/${repo_nwo}/dependabot/alerts" --jq 'length' 2>/dev/null || echo "0")
|
|
201
192
|
|
|
202
193
|
if [[ $vulns -gt 0 ]]; then
|
|
203
194
|
error "Found $vulns security vulnerabilities"
|
|
@@ -319,7 +310,7 @@ publish_release() {
|
|
|
319
310
|
fi
|
|
320
311
|
|
|
321
312
|
# Create GitHub release
|
|
322
|
-
if command -v gh
|
|
313
|
+
if command -v gh >/dev/null 2>&1; then
|
|
323
314
|
if gh release create "$next_version" --title "$next_version" --generate-notes; then
|
|
324
315
|
success "GitHub release created"
|
|
325
316
|
else
|
|
@@ -371,7 +362,7 @@ create_rc() {
|
|
|
371
362
|
fi
|
|
372
363
|
|
|
373
364
|
# Create GitHub pre-release
|
|
374
|
-
if command -v gh
|
|
365
|
+
if command -v gh >/dev/null 2>&1; then
|
|
375
366
|
if gh release create "$rc_version" --title "RC: $rc_version" --prerelease --generate-notes; then
|
|
376
367
|
success "GitHub pre-release created"
|
|
377
368
|
else
|
|
@@ -424,7 +415,7 @@ promote_rc() {
|
|
|
424
415
|
fi
|
|
425
416
|
|
|
426
417
|
# Create GitHub release (not pre-release)
|
|
427
|
-
if command -v gh
|
|
418
|
+
if command -v gh >/dev/null 2>&1; then
|
|
428
419
|
if gh release create "$stable_version" --title "$stable_version" --generate-notes; then
|
|
429
420
|
success "GitHub release created"
|
|
430
421
|
else
|
|
@@ -472,7 +463,7 @@ rollback_release() {
|
|
|
472
463
|
fi
|
|
473
464
|
|
|
474
465
|
# Delete GitHub release
|
|
475
|
-
if command -v gh
|
|
466
|
+
if command -v gh >/dev/null 2>&1; then
|
|
476
467
|
if gh release delete "$version" --yes 2>/dev/null; then
|
|
477
468
|
success "GitHub release deleted"
|
|
478
469
|
else
|
|
@@ -534,7 +525,7 @@ show_history() {
|
|
|
534
525
|
info "Release History"
|
|
535
526
|
echo ""
|
|
536
527
|
|
|
537
|
-
if ! command -v gh
|
|
528
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
538
529
|
error "GitHub CLI required for history"
|
|
539
530
|
return 1
|
|
540
531
|
fi
|
package/scripts/sw-release.sh
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
|
-
trap 'rm -f "${tmp_file:-}"' EXIT
|
|
8
|
+
trap 'rm -f "${tmp_file:-}" "${tmp_changelog:-}"' EXIT
|
|
9
9
|
|
|
10
|
-
VERSION="
|
|
10
|
+
VERSION="3.0.0"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
13
13
|
|
|
@@ -18,6 +18,7 @@ REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
18
18
|
# Canonical helpers (colors, output, events)
|
|
19
19
|
# shellcheck source=lib/helpers.sh
|
|
20
20
|
[[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
|
|
21
|
+
[[ -f "$SCRIPT_DIR/lib/config.sh" ]] && source "$SCRIPT_DIR/lib/config.sh"
|
|
21
22
|
# Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
|
|
22
23
|
[[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
|
|
23
24
|
[[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
|
|
@@ -35,16 +36,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
35
36
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
36
37
|
}
|
|
37
38
|
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
39
|
# ─── Parse flags ───────────────────────────────────────────────────────────
|
|
49
40
|
DRY_RUN=false
|
|
50
41
|
VERSION_TYPE=""
|
|
@@ -510,7 +501,8 @@ cmd_publish() {
|
|
|
510
501
|
info "Step 2/5: Generating changelog..."
|
|
511
502
|
local changelog
|
|
512
503
|
changelog="$(generate_changelog_md "$next_version" "$current_version" "HEAD")"
|
|
513
|
-
|
|
504
|
+
tmp_changelog="$(mktemp)"
|
|
505
|
+
echo "$changelog" > "$tmp_changelog"
|
|
514
506
|
success "Changelog generated"
|
|
515
507
|
echo ""
|
|
516
508
|
|
|
@@ -531,15 +523,15 @@ cmd_publish() {
|
|
|
531
523
|
|
|
532
524
|
# Step 5: Create GitHub release
|
|
533
525
|
info "Step 5/5: Creating GitHub release..."
|
|
534
|
-
if command -v gh
|
|
535
|
-
if gh release create "$next_version" --title "$next_version" --notes-file
|
|
526
|
+
if command -v gh >/dev/null 2>&1; then
|
|
527
|
+
if gh release create "$next_version" --title "$next_version" --notes-file "$tmp_changelog"; then
|
|
536
528
|
success "GitHub release created"
|
|
537
529
|
else
|
|
538
530
|
warn "Failed to create GitHub release (may already exist)"
|
|
539
531
|
fi
|
|
540
532
|
else
|
|
541
533
|
warn "gh CLI not installed — skipping GitHub release creation"
|
|
542
|
-
echo -e " Manual create: ${DIM}gh release create $next_version --title '$next_version' --notes-file
|
|
534
|
+
echo -e " Manual create: ${DIM}gh release create $next_version --title '$next_version' --notes-file <changelog_file>${RESET}"
|
|
543
535
|
fi
|
|
544
536
|
echo ""
|
|
545
537
|
|
package/scripts/sw-remote.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
|
|
|
@@ -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
|
# ─── Defaults ───────────────────────────────────────────────────────────────
|
|
48
38
|
MACHINES_FILE="$HOME/.shipwright/machines.json"
|
|
49
39
|
SSH_OPTS="-o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
|