shipwright-cli 2.4.0 → 3.1.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 +248 -94
- package/completions/shipwright.bash +68 -19
- package/completions/shipwright.fish +310 -42
- package/config/decision-tiers.json +55 -0
- package/config/defaults.json +111 -0
- package/config/event-schema.json +218 -0
- package/config/policy.json +21 -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 +7 -9
- 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 +127 -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 +63 -17
- package/scripts/lib/daemon-failure.sh +0 -0
- package/scripts/lib/daemon-health.sh +1 -1
- package/scripts/lib/daemon-patrol.sh +64 -17
- package/scripts/lib/daemon-poll.sh +54 -25
- package/scripts/lib/daemon-state.sh +125 -23
- package/scripts/lib/daemon-triage.sh +31 -9
- package/scripts/lib/decide-autonomy.sh +295 -0
- package/scripts/lib/decide-scoring.sh +228 -0
- package/scripts/lib/decide-signals.sh +462 -0
- package/scripts/lib/fleet-failover.sh +63 -0
- package/scripts/lib/helpers.sh +29 -6
- package/scripts/lib/pipeline-detection.sh +2 -2
- package/scripts/lib/pipeline-github.sh +9 -9
- package/scripts/lib/pipeline-intelligence.sh +105 -38
- package/scripts/lib/pipeline-quality-checks.sh +17 -16
- package/scripts/lib/pipeline-quality.sh +1 -1
- package/scripts/lib/pipeline-stages.sh +440 -59
- package/scripts/lib/pipeline-state.sh +54 -4
- package/scripts/lib/policy.sh +0 -0
- package/scripts/lib/test-helpers.sh +247 -0
- package/scripts/postinstall.mjs +78 -12
- package/scripts/signals/example-collector.sh +36 -0
- package/scripts/sw +17 -7
- 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 +17 -18
- package/scripts/sw-daemon.sh +76 -71
- package/scripts/sw-dashboard.sh +57 -17
- package/scripts/sw-db.sh +524 -26
- package/scripts/sw-decide.sh +685 -0
- 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 +138 -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 +368 -53
- 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 +905 -104
- package/scripts/sw-memory.sh +263 -20
- package/scripts/sw-mission-control.sh +2 -12
- package/scripts/sw-model-router.sh +73 -34
- package/scripts/sw-otel.sh +15 -23
- 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 +550 -122
- package/scripts/sw-pm.sh +2 -12
- package/scripts/sw-pr-lifecycle.sh +33 -28
- 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 +85 -14
- 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 +174 -41
- package/scripts/sw-security-audit.sh +12 -22
- package/scripts/sw-self-optimize.sh +239 -23
- package/scripts/sw-session.sh +5 -15
- 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 +29 -39
- 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 +73 -0
- package/templates/pipelines/tdd.json +72 -0
- package/scripts/sw-pipeline.sh.mock +0 -7
package/scripts/sw-pm.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.1.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -32,16 +32,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
32
32
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
33
33
|
}
|
|
34
34
|
fi
|
|
35
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
36
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
37
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
38
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
39
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
40
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
41
|
-
DIM="${DIM:-\033[2m}"
|
|
42
|
-
BOLD="${BOLD:-\033[1m}"
|
|
43
|
-
RESET="${RESET:-\033[0m}"
|
|
44
|
-
|
|
45
35
|
# ─── PM History Storage ──────────────────────────────────────────────────────
|
|
46
36
|
PM_HISTORY="${HOME}/.shipwright/pm-history.json"
|
|
47
37
|
|
|
@@ -224,7 +214,7 @@ recommend_team() {
|
|
|
224
214
|
if [[ -n "$issue_title" ]]; then
|
|
225
215
|
local recruit_result
|
|
226
216
|
recruit_result=$(bash "$SCRIPT_DIR/sw-recruit.sh" team --json "$issue_title" 2>/dev/null) || true
|
|
227
|
-
if [[ -n "$recruit_result" ]] && echo "$recruit_result" | jq -e '.team'
|
|
217
|
+
if [[ -n "$recruit_result" ]] && echo "$recruit_result" | jq -e '.team' >/dev/null 2>&1; then
|
|
228
218
|
local recruit_roles recruit_model recruit_agents recruit_cost
|
|
229
219
|
recruit_roles=$(echo "$recruit_result" | jq -r '.team | join(",")')
|
|
230
220
|
recruit_model=$(echo "$recruit_result" | jq -r '.model // "sonnet"')
|
|
@@ -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.1.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
|
# ─── Configuration Helpers ──────────────────────────────────────────────────
|
|
48
30
|
|
|
49
31
|
get_pr_config() {
|
|
@@ -67,7 +49,27 @@ get_pr_head_sha() {
|
|
|
67
49
|
get_pr_checks_status() {
|
|
68
50
|
local pr_number="$1"
|
|
69
51
|
# Returns: success, failure, pending, or unknown
|
|
70
|
-
gh pr checks
|
|
52
|
+
# gh pr checks requires --json flag to produce JSON output
|
|
53
|
+
local checks_json
|
|
54
|
+
checks_json=$(gh pr checks "$pr_number" --json name,state,conclusion 2>/dev/null || echo "[]")
|
|
55
|
+
|
|
56
|
+
# Handle empty or non-JSON response
|
|
57
|
+
if [[ -z "$checks_json" ]] || ! echo "$checks_json" | jq empty 2>/dev/null; then
|
|
58
|
+
echo "unknown"
|
|
59
|
+
return
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
local total failed pending
|
|
63
|
+
total=$(echo "$checks_json" | jq 'length' 2>/dev/null || echo "0")
|
|
64
|
+
[[ "$total" -eq 0 ]] && { echo "unknown"; return; }
|
|
65
|
+
|
|
66
|
+
failed=$(echo "$checks_json" | jq '[.[] | select(.conclusion == "FAILURE" or .conclusion == "failure")] | length' 2>/dev/null || echo "0")
|
|
67
|
+
[[ "$failed" -gt 0 ]] && { echo "failure"; return; }
|
|
68
|
+
|
|
69
|
+
pending=$(echo "$checks_json" | jq '[.[] | select(.state == "PENDING" or .state == "QUEUED" or .state == "IN_PROGRESS")] | length' 2>/dev/null || echo "0")
|
|
70
|
+
[[ "$pending" -gt 0 ]] && { echo "pending"; return; }
|
|
71
|
+
|
|
72
|
+
echo "success"
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
has_merge_conflicts() {
|
|
@@ -272,13 +274,16 @@ pr_review() {
|
|
|
272
274
|
# Evaluate quality criteria
|
|
273
275
|
local issues_found=0
|
|
274
276
|
local file_count
|
|
275
|
-
file_count=$(echo "$diff_output" | grep -c '^diff --git' ||
|
|
277
|
+
file_count=$(echo "$diff_output" | grep -c '^diff --git' || true)
|
|
278
|
+
file_count="${file_count:-0}"
|
|
276
279
|
|
|
277
280
|
local line_additions
|
|
278
|
-
line_additions=$(echo "$diff_output" | grep -c '^+' ||
|
|
281
|
+
line_additions=$(echo "$diff_output" | grep -c '^+' || true)
|
|
282
|
+
line_additions="${line_additions:-0}"
|
|
279
283
|
|
|
280
284
|
local line_deletions
|
|
281
|
-
line_deletions=$(echo "$diff_output" | grep -c '^-' ||
|
|
285
|
+
line_deletions=$(echo "$diff_output" | grep -c '^-' || true)
|
|
286
|
+
line_deletions="${line_deletions:-0}"
|
|
282
287
|
|
|
283
288
|
info "Diff analysis: ${file_count} files, +${line_additions}/-${line_deletions} lines"
|
|
284
289
|
|
|
@@ -287,25 +292,25 @@ pr_review() {
|
|
|
287
292
|
if echo "$diff_output" | grep -qE '(HACK|TODO|FIXME|XXX|BROKEN|DEBUG)'; then
|
|
288
293
|
warnings="${warnings}
|
|
289
294
|
- Found HACK/TODO/FIXME markers in code"
|
|
290
|
-
((issues_found
|
|
295
|
+
issues_found=$((issues_found + 1))
|
|
291
296
|
fi
|
|
292
297
|
|
|
293
298
|
if echo "$diff_output" | grep -qE 'console\.(log|warn|error)\('; then
|
|
294
299
|
warnings="${warnings}
|
|
295
300
|
- Found console.log statements (should use proper logging)"
|
|
296
|
-
((issues_found
|
|
301
|
+
issues_found=$((issues_found + 1))
|
|
297
302
|
fi
|
|
298
303
|
|
|
299
304
|
if [[ $line_additions -gt 500 ]]; then
|
|
300
305
|
warnings="${warnings}
|
|
301
306
|
- Large addition (${line_additions} lines) — consider splitting into smaller PRs"
|
|
302
|
-
((issues_found
|
|
307
|
+
issues_found=$((issues_found + 1))
|
|
303
308
|
fi
|
|
304
309
|
|
|
305
310
|
if [[ $file_count -gt 20 ]]; then
|
|
306
311
|
warnings="${warnings}
|
|
307
312
|
- Many files changed (${file_count}) — consider splitting"
|
|
308
|
-
((issues_found
|
|
313
|
+
issues_found=$((issues_found + 1))
|
|
309
314
|
fi
|
|
310
315
|
|
|
311
316
|
# Post review comment to PR
|
|
@@ -487,7 +492,7 @@ ${DIM}— Shipwright auto-lifecycle manager${RESET}"
|
|
|
487
492
|
gh pr comment "$pr_number" --body "$close_comment" 2>/dev/null || true
|
|
488
493
|
gh pr close "$pr_number" 2>/dev/null && {
|
|
489
494
|
success "Closed PR #${pr_number}"
|
|
490
|
-
((closed_count
|
|
495
|
+
closed_count=$((closed_count + 1))
|
|
491
496
|
emit_event "pr.closed_stale" "pr=${pr_number}" "age_days=${age_days}"
|
|
492
497
|
}
|
|
493
498
|
fi
|
package/scripts/sw-predictive.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.1.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
|
|
|
@@ -169,7 +159,7 @@ _predictive_record_anomaly() {
|
|
|
169
159
|
'{ts: $ts, ts_epoch: $epoch, stage: $stage, metric: $metric, severity: $severity, value: $value, baseline: $baseline, confirmed: null}')
|
|
170
160
|
echo "$record" >> "$tracking_file"
|
|
171
161
|
# Rotate anomaly tracking to prevent unbounded growth
|
|
172
|
-
type rotate_jsonl
|
|
162
|
+
type rotate_jsonl >/dev/null 2>&1 && rotate_jsonl "$tracking_file" 5000
|
|
173
163
|
}
|
|
174
164
|
|
|
175
165
|
# predictive_confirm_anomaly <stage> <metric_name> <was_real_failure>
|
|
@@ -308,7 +298,7 @@ _predictive_github_risk_factors() {
|
|
|
308
298
|
local issue_json="$1"
|
|
309
299
|
local risk_factors='{"security_risk": 0, "churn_risk": 0, "contributor_risk": 0, "recurrence_risk": 0}'
|
|
310
300
|
|
|
311
|
-
type _gh_detect_repo
|
|
301
|
+
type _gh_detect_repo >/dev/null 2>&1 || { echo "$risk_factors"; return 0; }
|
|
312
302
|
_gh_detect_repo 2>/dev/null || { echo "$risk_factors"; return 0; }
|
|
313
303
|
|
|
314
304
|
local owner="${GH_OWNER:-}" repo="${GH_REPO:-}"
|
|
@@ -316,7 +306,7 @@ _predictive_github_risk_factors() {
|
|
|
316
306
|
|
|
317
307
|
# Security risk: active alerts
|
|
318
308
|
local sec_risk=0
|
|
319
|
-
if type gh_security_alerts
|
|
309
|
+
if type gh_security_alerts >/dev/null 2>&1; then
|
|
320
310
|
local alert_count
|
|
321
311
|
alert_count=$(gh_security_alerts "$owner" "$repo" 2>/dev/null | jq 'length' 2>/dev/null || echo "0")
|
|
322
312
|
if [[ "${alert_count:-0}" -gt 10 ]]; then
|
|
@@ -330,7 +320,7 @@ _predictive_github_risk_factors() {
|
|
|
330
320
|
|
|
331
321
|
# Recurrence risk: similar past issues
|
|
332
322
|
local rec_risk=0
|
|
333
|
-
if type gh_similar_issues
|
|
323
|
+
if type gh_similar_issues >/dev/null 2>&1; then
|
|
334
324
|
local title
|
|
335
325
|
title=$(echo "$issue_json" | jq -r '.title // ""' 2>/dev/null | head -c 100)
|
|
336
326
|
if [[ -n "$title" ]]; then
|
|
@@ -346,7 +336,7 @@ _predictive_github_risk_factors() {
|
|
|
346
336
|
|
|
347
337
|
# Contributor risk: low contributor count = bus factor risk
|
|
348
338
|
local cont_risk=0
|
|
349
|
-
if type gh_contributors
|
|
339
|
+
if type gh_contributors >/dev/null 2>&1; then
|
|
350
340
|
local contributor_count
|
|
351
341
|
contributor_count=$(gh_contributors "$owner" "$repo" 2>/dev/null | jq 'length' 2>/dev/null || echo "0")
|
|
352
342
|
if [[ "${contributor_count:-0}" -lt 2 ]]; then
|
|
@@ -368,7 +358,7 @@ predict_pipeline_risk() {
|
|
|
368
358
|
local issue_json="${1:-"{}"}"
|
|
369
359
|
local repo_context="${2:-}"
|
|
370
360
|
|
|
371
|
-
if [[ "$INTELLIGENCE_AVAILABLE" == "true" ]] && command -v _intelligence_call_claude
|
|
361
|
+
if [[ "$INTELLIGENCE_AVAILABLE" == "true" ]] && command -v _intelligence_call_claude >/dev/null 2>&1; then
|
|
372
362
|
local prompt
|
|
373
363
|
prompt="Analyze this issue for pipeline risk. Return ONLY valid JSON.
|
|
374
364
|
|
|
@@ -381,7 +371,7 @@ Return JSON format:
|
|
|
381
371
|
local result
|
|
382
372
|
result=$(_intelligence_call_claude "$prompt" 2>/dev/null || echo "")
|
|
383
373
|
|
|
384
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e '.overall_risk'
|
|
374
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e '.overall_risk' >/dev/null 2>&1; then
|
|
385
375
|
# Validate range
|
|
386
376
|
local risk
|
|
387
377
|
risk=$(echo "$result" | jq '.overall_risk')
|
|
@@ -503,7 +493,7 @@ $(head -100 "$file_path" 2>/dev/null || true)
|
|
|
503
493
|
return 0
|
|
504
494
|
fi
|
|
505
495
|
|
|
506
|
-
if [[ "$INTELLIGENCE_AVAILABLE" != "true" ]] || ! command -v _intelligence_call_claude
|
|
496
|
+
if [[ "$INTELLIGENCE_AVAILABLE" != "true" ]] || ! command -v _intelligence_call_claude >/dev/null 2>&1; then
|
|
507
497
|
echo '[]'
|
|
508
498
|
return 0
|
|
509
499
|
fi
|
|
@@ -524,7 +514,7 @@ Only return findings with severity 'high' or 'critical'. Return [] if nothing si
|
|
|
524
514
|
local result
|
|
525
515
|
result=$(_intelligence_call_claude "$prompt" 2>/dev/null || echo "")
|
|
526
516
|
|
|
527
|
-
if [[ -n "$result" ]] && echo "$result" | jq -e 'type == "array"'
|
|
517
|
+
if [[ -n "$result" ]] && echo "$result" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
|
528
518
|
# Filter to only high/critical findings
|
|
529
519
|
local filtered
|
|
530
520
|
filtered=$(echo "$result" | jq '[.[] | select(.severity == "high" or .severity == "critical")]')
|
|
@@ -588,9 +578,13 @@ predict_detect_anomaly() {
|
|
|
588
578
|
return 0
|
|
589
579
|
fi
|
|
590
580
|
|
|
591
|
-
# Get per-metric thresholds (adaptive or default)
|
|
581
|
+
# Get per-metric thresholds (adaptive from intelligence/DB, or file-based, or default)
|
|
592
582
|
local metric_critical_mult metric_warning_mult
|
|
593
|
-
|
|
583
|
+
if [[ "$(type -t get_anomaly_threshold 2>/dev/null)" == "function" ]]; then
|
|
584
|
+
metric_critical_mult=$(get_anomaly_threshold)
|
|
585
|
+
else
|
|
586
|
+
metric_critical_mult=$(_predictive_get_anomaly_threshold "$metric_name")
|
|
587
|
+
fi
|
|
594
588
|
metric_warning_mult=$(_predictive_get_warning_multiplier "$metric_name")
|
|
595
589
|
|
|
596
590
|
# Calculate thresholds using awk for floating-point
|
package/scripts/sw-prep.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.1.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
|
# ─── Defaults ───────────────────────────────────────────────────────────────
|
|
52
42
|
FORCE=false
|
|
53
43
|
CHECK_ONLY=false
|
|
@@ -153,7 +143,7 @@ done
|
|
|
153
143
|
# ─── prep_init ──────────────────────────────────────────────────────────────
|
|
154
144
|
|
|
155
145
|
prep_init() {
|
|
156
|
-
if ! git rev-parse --is-inside-work-tree
|
|
146
|
+
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
157
147
|
error "Not inside a git repository"
|
|
158
148
|
exit 1
|
|
159
149
|
fi
|
|
@@ -591,7 +581,7 @@ prep_extract_patterns() {
|
|
|
591
581
|
# ─── Intelligence Check ──────────────────────────────────────────────────
|
|
592
582
|
|
|
593
583
|
intelligence_available() {
|
|
594
|
-
command -v claude
|
|
584
|
+
command -v claude >/dev/null 2>&1 || return 1
|
|
595
585
|
# Honor --with-claude flag
|
|
596
586
|
$WITH_CLAUDE && return 0
|
|
597
587
|
# Check daemon config for intelligence.enabled
|
|
@@ -1407,7 +1397,7 @@ prep_generate_manifest() {
|
|
|
1407
1397
|
HEREDOC
|
|
1408
1398
|
|
|
1409
1399
|
# Validate JSON
|
|
1410
|
-
if command -v jq
|
|
1400
|
+
if command -v jq >/dev/null 2>&1; then
|
|
1411
1401
|
if ! jq empty "$filepath" 2>/dev/null; then
|
|
1412
1402
|
warn "prep-manifest.json may have invalid JSON — check manually"
|
|
1413
1403
|
fi
|
|
@@ -1422,7 +1412,7 @@ HEREDOC
|
|
|
1422
1412
|
prep_with_claude() {
|
|
1423
1413
|
if ! $WITH_CLAUDE; then return; fi
|
|
1424
1414
|
|
|
1425
|
-
if ! command -v claude
|
|
1415
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
1426
1416
|
warn "claude CLI not found — skipping deep analysis"
|
|
1427
1417
|
return
|
|
1428
1418
|
fi
|
|
@@ -1471,7 +1461,7 @@ prep_validate() {
|
|
|
1471
1461
|
local issues=0
|
|
1472
1462
|
|
|
1473
1463
|
# Check JSON files
|
|
1474
|
-
if command -v jq
|
|
1464
|
+
if command -v jq >/dev/null 2>&1; then
|
|
1475
1465
|
for f in "$PROJECT_ROOT/.claude/settings.json" "$PROJECT_ROOT/.claude/prep-manifest.json"; do
|
|
1476
1466
|
if [[ -f "$f" ]] && ! jq empty "$f" 2>/dev/null; then
|
|
1477
1467
|
warn "Invalid JSON: ${f##"$PROJECT_ROOT"/}"
|
package/scripts/sw-ps.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Displays a table of agents running in claude-* tmux windows with ║
|
|
6
6
|
# ║ PID, status, idle time, and pane references. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="
|
|
8
|
+
VERSION="3.1.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
|
@@ -31,16 +31,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
31
31
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
32
32
|
}
|
|
33
33
|
fi
|
|
34
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
35
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
36
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
37
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
38
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
39
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
40
|
-
DIM="${DIM:-\033[2m}"
|
|
41
|
-
BOLD="${BOLD:-\033[1m}"
|
|
42
|
-
RESET="${RESET:-\033[0m}"
|
|
43
|
-
|
|
44
34
|
# ─── Format idle time ───────────────────────────────────────────────────────
|
|
45
35
|
format_idle() {
|
|
46
36
|
local seconds="$1"
|
|
@@ -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.1.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
|
# ─── Paths ──────────────────────────────────────────────────────────────────
|
|
48
38
|
PUB_DASH_DIR="${HOME}/.shipwright/public-dashboard"
|
|
49
39
|
SHARE_LINKS_FILE="${PUB_DASH_DIR}/share-links.json"
|
|
@@ -133,7 +123,7 @@ gather_pipeline_state() {
|
|
|
133
123
|
# ─── Generate Token ─────────────────────────────────────────────────────────
|
|
134
124
|
generate_token() {
|
|
135
125
|
# Create a read-only token (32 hex chars)
|
|
136
|
-
if command -v openssl
|
|
126
|
+
if command -v openssl >/dev/null 2>&1; then
|
|
137
127
|
openssl rand -hex 16
|
|
138
128
|
else
|
|
139
129
|
# Fallback to simple pseudo-random
|
package/scripts/sw-quality.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.1.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -33,15 +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
36
|
# Policy + quality thresholds (lib/pipeline-quality.sh sets QUALITY_* from config/policy.json)
|
|
46
37
|
[[ -f "$SCRIPT_DIR/lib/pipeline-quality.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-quality.sh"
|
|
47
38
|
|
|
@@ -102,7 +93,8 @@ validate_quality() {
|
|
|
102
93
|
local todos_pass=true
|
|
103
94
|
if [[ -d "$REPO_DIR/.git" ]]; then
|
|
104
95
|
local todo_count
|
|
105
|
-
todo_count=$(cd "$REPO_DIR" && git diff --cached 2>/dev/null | grep -cE '^\+.*(TODO|FIXME)' ||
|
|
96
|
+
todo_count=$(cd "$REPO_DIR" && git diff --cached 2>/dev/null | grep -cE '^\+.*(TODO|FIXME)' || true)
|
|
97
|
+
todo_count="${todo_count:-0}"
|
|
106
98
|
if [[ "$todo_count" -gt 0 ]]; then
|
|
107
99
|
todos_pass=false
|
|
108
100
|
all_pass=false
|
|
@@ -115,7 +107,8 @@ validate_quality() {
|
|
|
115
107
|
local secret_patterns="(password|secret|token|api[_-]?key|aws_access|private_key)"
|
|
116
108
|
if [[ -d "$REPO_DIR/.git" ]]; then
|
|
117
109
|
local secret_count
|
|
118
|
-
secret_count=$(cd "$REPO_DIR" && git diff --cached 2>/dev/null | grep -ciE "$secret_patterns" ||
|
|
110
|
+
secret_count=$(cd "$REPO_DIR" && git diff --cached 2>/dev/null | grep -ciE "$secret_patterns" || true)
|
|
111
|
+
secret_count="${secret_count:-0}"
|
|
119
112
|
if [[ "$secret_count" -gt 3 ]]; then
|
|
120
113
|
secrets_pass=false
|
|
121
114
|
all_pass=false
|
|
@@ -145,6 +138,62 @@ validate_quality() {
|
|
|
145
138
|
emit_event "quality.validate" "pass=$all_pass" "score=$score"
|
|
146
139
|
}
|
|
147
140
|
|
|
141
|
+
# ─── Semantic audit (Claude-powered, supplements grep) ───────────────────────
|
|
142
|
+
quality_semantic_audit() {
|
|
143
|
+
local target="${1:-$REPO_DIR}"
|
|
144
|
+
local audit_type="${2:-general}"
|
|
145
|
+
local results_file="${3:-}"
|
|
146
|
+
|
|
147
|
+
if ! command -v claude &>/dev/null; then
|
|
148
|
+
return 1
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
local code_sample=""
|
|
152
|
+
local changed_files
|
|
153
|
+
changed_files=$(cd "$REPO_DIR" 2>/dev/null && git diff --name-only HEAD~1 2>/dev/null) || true
|
|
154
|
+
[[ -z "$changed_files" ]] && changed_files=$(cd "$REPO_DIR" 2>/dev/null && git diff --cached --name-only 2>/dev/null) || true
|
|
155
|
+
[[ -z "$changed_files" ]] && changed_files=$(find "$target" -type f \( -name "*.sh" -o -name "*.ts" -o -name "*.js" \) 2>/dev/null | head -20)
|
|
156
|
+
|
|
157
|
+
local file_count=0
|
|
158
|
+
while IFS= read -r file; do
|
|
159
|
+
[[ -z "$file" ]] && continue
|
|
160
|
+
local full_path="$file"
|
|
161
|
+
[[ "$file" != /* ]] && full_path="$REPO_DIR/$file"
|
|
162
|
+
[[ ! -f "$full_path" ]] && continue
|
|
163
|
+
[[ "$file_count" -ge 10 ]] && break
|
|
164
|
+
local content
|
|
165
|
+
content=$(head -200 "$full_path" 2>/dev/null)
|
|
166
|
+
local display_path="$file"
|
|
167
|
+
[[ "$full_path" == "$REPO_DIR"* ]] && display_path="${full_path#$REPO_DIR/}"
|
|
168
|
+
code_sample+="
|
|
169
|
+
--- $display_path ---
|
|
170
|
+
$content
|
|
171
|
+
"
|
|
172
|
+
file_count=$((file_count + 1))
|
|
173
|
+
done <<< "$changed_files"
|
|
174
|
+
|
|
175
|
+
[[ -z "$code_sample" ]] && return 1
|
|
176
|
+
|
|
177
|
+
local prompt="You are a senior code reviewer performing a ${audit_type} audit. Analyze these files for real issues only - no style nits, no false positives. Return JSON array of findings:
|
|
178
|
+
[{\"severity\": \"critical|high|medium|low\", \"file\": \"path\", \"line\": N, \"category\": \"security|correctness|architecture|performance\", \"description\": \"specific issue\", \"suggestion\": \"how to fix\"}]
|
|
179
|
+
|
|
180
|
+
Only report REAL issues. Empty array [] if none found.
|
|
181
|
+
|
|
182
|
+
$code_sample"
|
|
183
|
+
|
|
184
|
+
local result
|
|
185
|
+
result=$(echo "$prompt" | timeout 60 claude -p 2>/dev/null) || return 1
|
|
186
|
+
|
|
187
|
+
local findings
|
|
188
|
+
findings=$(echo "$result" | grep -o '\[.*\]' | head -1) || findings="[]"
|
|
189
|
+
|
|
190
|
+
if [[ -n "$results_file" ]]; then
|
|
191
|
+
echo "$findings" > "$results_file"
|
|
192
|
+
else
|
|
193
|
+
echo "$findings"
|
|
194
|
+
fi
|
|
195
|
+
}
|
|
196
|
+
|
|
148
197
|
# ─── Audit subcommand ───────────────────────────────────────────────────────
|
|
149
198
|
audit_quality() {
|
|
150
199
|
info "Running adversarial quality audits..."
|
|
@@ -206,6 +255,26 @@ audit_quality() {
|
|
|
206
255
|
fi
|
|
207
256
|
fi
|
|
208
257
|
|
|
258
|
+
# Run semantic audit when Claude is available (supplements grep)
|
|
259
|
+
local semantic_results
|
|
260
|
+
if semantic_results=$(quality_semantic_audit "$REPO_DIR" "general" 2>/dev/null); then
|
|
261
|
+
local semantic_count
|
|
262
|
+
semantic_count=$(echo "$semantic_results" | jq 'length' 2>/dev/null || echo "0")
|
|
263
|
+
if [[ -n "$semantic_count" && "$semantic_count" -gt 0 ]]; then
|
|
264
|
+
info " Semantic audit found $semantic_count additional issue(s)"
|
|
265
|
+
while IFS=$'\t' read -r cat line; do
|
|
266
|
+
[[ -z "$line" ]] && continue
|
|
267
|
+
case "${cat:-correctness}" in
|
|
268
|
+
security) security_findings+=( "$line" ) ;;
|
|
269
|
+
correctness) correctness_findings+=( "$line" ) ;;
|
|
270
|
+
architecture) architecture_findings+=( "$line" ) ;;
|
|
271
|
+
performance) correctness_findings+=( "$line" ) ;;
|
|
272
|
+
*) correctness_findings+=( "$line" ) ;;
|
|
273
|
+
esac
|
|
274
|
+
done < <(echo "$semantic_results" | jq -r '.[] | "\(.category)\t[\(.severity)] \(.file):\(.line // "?") - \(.description)"' 2>/dev/null)
|
|
275
|
+
fi
|
|
276
|
+
fi
|
|
277
|
+
|
|
209
278
|
# Compile audit results
|
|
210
279
|
local security_score=100
|
|
211
280
|
[[ ${#security_findings[@]} -gt 0 ]] && security_score=$((100 - ${#security_findings[@]} * 25))
|
|
@@ -255,7 +324,8 @@ completion_detection() {
|
|
|
255
324
|
# Check diminishing returns: < 10 lines changed in last 3 iterations
|
|
256
325
|
local recent_changes=0
|
|
257
326
|
if [[ -f "$ARTIFACTS_DIR/progress.md" ]]; then
|
|
258
|
-
recent_changes=$(grep -c "^### Iteration" "$ARTIFACTS_DIR/progress.md" ||
|
|
327
|
+
recent_changes=$(grep -c "^### Iteration" "$ARTIFACTS_DIR/progress.md" || true)
|
|
328
|
+
recent_changes="${recent_changes:-0}"
|
|
259
329
|
fi
|
|
260
330
|
|
|
261
331
|
# Check if tests went from failing to passing
|
|
@@ -272,7 +342,8 @@ completion_detection() {
|
|
|
272
342
|
local subtasks_done=true
|
|
273
343
|
if [[ -f ".claude/goal.md" ]]; then
|
|
274
344
|
local unchecked_count
|
|
275
|
-
unchecked_count=$(grep -c "^- \[ \]" ".claude/goal.md" 2>/dev/null ||
|
|
345
|
+
unchecked_count=$(grep -c "^- \[ \]" ".claude/goal.md" 2>/dev/null || true)
|
|
346
|
+
unchecked_count="${unchecked_count:-0}"
|
|
276
347
|
if [[ "$unchecked_count" -gt 0 ]]; then
|
|
277
348
|
subtasks_done=false
|
|
278
349
|
fi
|
package/scripts/sw-reaper.sh
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# ║ shipwright reaper --watch Continuous loop (default: 5s) ║
|
|
12
12
|
# ║ shipwright reaper --dry-run Preview what would be reaped ║
|
|
13
13
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
14
|
-
VERSION="
|
|
14
|
+
VERSION="3.1.0"
|
|
15
15
|
set -euo pipefail
|
|
16
16
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
17
17
|
|
|
@@ -37,16 +37,6 @@ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
|
37
37
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
38
38
|
}
|
|
39
39
|
fi
|
|
40
|
-
CYAN="${CYAN:-\033[38;2;0;212;255m}"
|
|
41
|
-
PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
|
|
42
|
-
BLUE="${BLUE:-\033[38;2;0;102;255m}"
|
|
43
|
-
GREEN="${GREEN:-\033[38;2;74;222;128m}"
|
|
44
|
-
YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
|
|
45
|
-
RED="${RED:-\033[38;2;248;113;113m}"
|
|
46
|
-
DIM="${DIM:-\033[2m}"
|
|
47
|
-
BOLD="${BOLD:-\033[1m}"
|
|
48
|
-
RESET="${RESET:-\033[0m}"
|
|
49
|
-
|
|
50
40
|
# ─── Defaults ──────────────────────────────────────────────────────────────
|
|
51
41
|
WATCH=false
|
|
52
42
|
DRY_RUN=false
|