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-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.0.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.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
|
# ─── 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() {
|
|
@@ -287,25 +289,25 @@ pr_review() {
|
|
|
287
289
|
if echo "$diff_output" | grep -qE '(HACK|TODO|FIXME|XXX|BROKEN|DEBUG)'; then
|
|
288
290
|
warnings="${warnings}
|
|
289
291
|
- Found HACK/TODO/FIXME markers in code"
|
|
290
|
-
((issues_found
|
|
292
|
+
issues_found=$((issues_found + 1))
|
|
291
293
|
fi
|
|
292
294
|
|
|
293
295
|
if echo "$diff_output" | grep -qE 'console\.(log|warn|error)\('; then
|
|
294
296
|
warnings="${warnings}
|
|
295
297
|
- Found console.log statements (should use proper logging)"
|
|
296
|
-
((issues_found
|
|
298
|
+
issues_found=$((issues_found + 1))
|
|
297
299
|
fi
|
|
298
300
|
|
|
299
301
|
if [[ $line_additions -gt 500 ]]; then
|
|
300
302
|
warnings="${warnings}
|
|
301
303
|
- Large addition (${line_additions} lines) — consider splitting into smaller PRs"
|
|
302
|
-
((issues_found
|
|
304
|
+
issues_found=$((issues_found + 1))
|
|
303
305
|
fi
|
|
304
306
|
|
|
305
307
|
if [[ $file_count -gt 20 ]]; then
|
|
306
308
|
warnings="${warnings}
|
|
307
309
|
- Many files changed (${file_count}) — consider splitting"
|
|
308
|
-
((issues_found
|
|
310
|
+
issues_found=$((issues_found + 1))
|
|
309
311
|
fi
|
|
310
312
|
|
|
311
313
|
# Post review comment to PR
|
|
@@ -487,7 +489,7 @@ ${DIM}— Shipwright auto-lifecycle manager${RESET}"
|
|
|
487
489
|
gh pr comment "$pr_number" --body "$close_comment" 2>/dev/null || true
|
|
488
490
|
gh pr close "$pr_number" 2>/dev/null && {
|
|
489
491
|
success "Closed PR #${pr_number}"
|
|
490
|
-
((closed_count
|
|
492
|
+
closed_count=$((closed_count + 1))
|
|
491
493
|
emit_event "pr.closed_stale" "pr=${pr_number}" "age_days=${age_days}"
|
|
492
494
|
}
|
|
493
495
|
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.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
|
|
|
@@ -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.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
|
# ─── 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.0.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.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
|
# ─── 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.0.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
|
|
|
@@ -145,6 +136,62 @@ validate_quality() {
|
|
|
145
136
|
emit_event "quality.validate" "pass=$all_pass" "score=$score"
|
|
146
137
|
}
|
|
147
138
|
|
|
139
|
+
# ─── Semantic audit (Claude-powered, supplements grep) ───────────────────────
|
|
140
|
+
quality_semantic_audit() {
|
|
141
|
+
local target="${1:-$REPO_DIR}"
|
|
142
|
+
local audit_type="${2:-general}"
|
|
143
|
+
local results_file="${3:-}"
|
|
144
|
+
|
|
145
|
+
if ! command -v claude &>/dev/null; then
|
|
146
|
+
return 1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
local code_sample=""
|
|
150
|
+
local changed_files
|
|
151
|
+
changed_files=$(cd "$REPO_DIR" 2>/dev/null && git diff --name-only HEAD~1 2>/dev/null) || true
|
|
152
|
+
[[ -z "$changed_files" ]] && changed_files=$(cd "$REPO_DIR" 2>/dev/null && git diff --cached --name-only 2>/dev/null) || true
|
|
153
|
+
[[ -z "$changed_files" ]] && changed_files=$(find "$target" -type f \( -name "*.sh" -o -name "*.ts" -o -name "*.js" \) 2>/dev/null | head -20)
|
|
154
|
+
|
|
155
|
+
local file_count=0
|
|
156
|
+
while IFS= read -r file; do
|
|
157
|
+
[[ -z "$file" ]] && continue
|
|
158
|
+
local full_path="$file"
|
|
159
|
+
[[ "$file" != /* ]] && full_path="$REPO_DIR/$file"
|
|
160
|
+
[[ ! -f "$full_path" ]] && continue
|
|
161
|
+
[[ "$file_count" -ge 10 ]] && break
|
|
162
|
+
local content
|
|
163
|
+
content=$(head -200 "$full_path" 2>/dev/null)
|
|
164
|
+
local display_path="$file"
|
|
165
|
+
[[ "$full_path" == "$REPO_DIR"* ]] && display_path="${full_path#$REPO_DIR/}"
|
|
166
|
+
code_sample+="
|
|
167
|
+
--- $display_path ---
|
|
168
|
+
$content
|
|
169
|
+
"
|
|
170
|
+
file_count=$((file_count + 1))
|
|
171
|
+
done <<< "$changed_files"
|
|
172
|
+
|
|
173
|
+
[[ -z "$code_sample" ]] && return 1
|
|
174
|
+
|
|
175
|
+
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:
|
|
176
|
+
[{\"severity\": \"critical|high|medium|low\", \"file\": \"path\", \"line\": N, \"category\": \"security|correctness|architecture|performance\", \"description\": \"specific issue\", \"suggestion\": \"how to fix\"}]
|
|
177
|
+
|
|
178
|
+
Only report REAL issues. Empty array [] if none found.
|
|
179
|
+
|
|
180
|
+
$code_sample"
|
|
181
|
+
|
|
182
|
+
local result
|
|
183
|
+
result=$(echo "$prompt" | timeout 60 claude -p 2>/dev/null) || return 1
|
|
184
|
+
|
|
185
|
+
local findings
|
|
186
|
+
findings=$(echo "$result" | grep -o '\[.*\]' | head -1) || findings="[]"
|
|
187
|
+
|
|
188
|
+
if [[ -n "$results_file" ]]; then
|
|
189
|
+
echo "$findings" > "$results_file"
|
|
190
|
+
else
|
|
191
|
+
echo "$findings"
|
|
192
|
+
fi
|
|
193
|
+
}
|
|
194
|
+
|
|
148
195
|
# ─── Audit subcommand ───────────────────────────────────────────────────────
|
|
149
196
|
audit_quality() {
|
|
150
197
|
info "Running adversarial quality audits..."
|
|
@@ -206,6 +253,26 @@ audit_quality() {
|
|
|
206
253
|
fi
|
|
207
254
|
fi
|
|
208
255
|
|
|
256
|
+
# Run semantic audit when Claude is available (supplements grep)
|
|
257
|
+
local semantic_results
|
|
258
|
+
if semantic_results=$(quality_semantic_audit "$REPO_DIR" "general" 2>/dev/null); then
|
|
259
|
+
local semantic_count
|
|
260
|
+
semantic_count=$(echo "$semantic_results" | jq 'length' 2>/dev/null || echo "0")
|
|
261
|
+
if [[ -n "$semantic_count" && "$semantic_count" -gt 0 ]]; then
|
|
262
|
+
info " Semantic audit found $semantic_count additional issue(s)"
|
|
263
|
+
while IFS=$'\t' read -r cat line; do
|
|
264
|
+
[[ -z "$line" ]] && continue
|
|
265
|
+
case "${cat:-correctness}" in
|
|
266
|
+
security) security_findings+=( "$line" ) ;;
|
|
267
|
+
correctness) correctness_findings+=( "$line" ) ;;
|
|
268
|
+
architecture) architecture_findings+=( "$line" ) ;;
|
|
269
|
+
performance) correctness_findings+=( "$line" ) ;;
|
|
270
|
+
*) correctness_findings+=( "$line" ) ;;
|
|
271
|
+
esac
|
|
272
|
+
done < <(echo "$semantic_results" | jq -r '.[] | "\(.category)\t[\(.severity)] \(.file):\(.line // "?") - \(.description)"' 2>/dev/null)
|
|
273
|
+
fi
|
|
274
|
+
fi
|
|
275
|
+
|
|
209
276
|
# Compile audit results
|
|
210
277
|
local security_score=100
|
|
211
278
|
[[ ${#security_findings[@]} -gt 0 ]] && security_score=$((100 - ${#security_findings[@]} * 25))
|
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.0.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
|