shipwright-cli 3.0.0 → 3.2.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 +21 -7
- package/completions/_shipwright +247 -93
- package/completions/shipwright.bash +69 -15
- package/completions/shipwright.fish +309 -41
- package/config/decision-tiers.json +55 -0
- package/config/defaults.json +25 -2
- package/config/event-schema.json +142 -5
- package/config/policy.json +8 -0
- package/dashboard/public/index.html +6 -0
- package/dashboard/public/styles.css +76 -0
- package/dashboard/server.ts +51 -0
- package/dashboard/src/core/api.ts +5 -0
- package/dashboard/src/types/api.ts +10 -0
- package/dashboard/src/views/metrics.ts +69 -1
- package/package.json +3 -3
- package/scripts/lib/architecture.sh +2 -1
- package/scripts/lib/bootstrap.sh +0 -0
- package/scripts/lib/config.sh +0 -0
- package/scripts/lib/daemon-adaptive.sh +4 -2
- package/scripts/lib/daemon-dispatch.sh +24 -1
- package/scripts/lib/daemon-failure.sh +0 -0
- package/scripts/lib/daemon-health.sh +0 -0
- package/scripts/lib/daemon-patrol.sh +42 -7
- package/scripts/lib/daemon-poll.sh +17 -0
- package/scripts/lib/daemon-state.sh +17 -0
- package/scripts/lib/daemon-triage.sh +1 -1
- 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 +0 -0
- package/scripts/lib/helpers.sh +19 -18
- package/scripts/lib/pipeline-detection.sh +1 -1
- package/scripts/lib/pipeline-github.sh +0 -0
- package/scripts/lib/pipeline-intelligence.sh +23 -4
- package/scripts/lib/pipeline-quality-checks.sh +11 -6
- package/scripts/lib/pipeline-quality.sh +0 -0
- package/scripts/lib/pipeline-stages.sh +330 -33
- package/scripts/lib/pipeline-state.sh +14 -0
- package/scripts/lib/policy.sh +0 -0
- package/scripts/lib/test-helpers.sh +0 -0
- package/scripts/postinstall.mjs +75 -1
- package/scripts/signals/example-collector.sh +36 -0
- package/scripts/sw +8 -4
- package/scripts/sw-activity.sh +1 -7
- package/scripts/sw-adaptive.sh +7 -7
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +1 -1
- package/scripts/sw-autonomous.sh +1 -1
- package/scripts/sw-changelog.sh +1 -1
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +11 -6
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +36 -17
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +1 -1
- package/scripts/sw-cost.sh +71 -5
- package/scripts/sw-daemon.sh +6 -3
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +53 -38
- package/scripts/sw-decide.sh +685 -0
- package/scripts/sw-decompose.sh +1 -1
- package/scripts/sw-deps.sh +1 -1
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +80 -4
- package/scripts/sw-doc-fleet.sh +1 -1
- package/scripts/sw-docs-agent.sh +1 -1
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +1 -1
- package/scripts/sw-dora.sh +1 -1
- package/scripts/sw-durable.sh +9 -5
- package/scripts/sw-e2e-orchestrator.sh +1 -1
- package/scripts/sw-eventbus.sh +7 -4
- package/scripts/sw-evidence.sh +1 -1
- package/scripts/sw-feedback.sh +1 -1
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +1 -1
- package/scripts/sw-fleet-viz.sh +6 -4
- package/scripts/sw-fleet.sh +1 -1
- package/scripts/sw-github-app.sh +3 -2
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +1 -1
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +5 -3
- package/scripts/sw-incident.sh +9 -5
- package/scripts/sw-init.sh +1 -1
- package/scripts/sw-instrument.sh +1 -1
- package/scripts/sw-intelligence.sh +11 -6
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +1 -1
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +338 -32
- package/scripts/sw-memory.sh +23 -6
- package/scripts/sw-mission-control.sh +1 -1
- package/scripts/sw-model-router.sh +3 -2
- package/scripts/sw-otel.sh +8 -4
- package/scripts/sw-oversight.sh +1 -1
- package/scripts/sw-pipeline-composer.sh +3 -1
- package/scripts/sw-pipeline-vitals.sh +11 -6
- package/scripts/sw-pipeline.sh +92 -8
- package/scripts/sw-pm.sh +5 -4
- package/scripts/sw-pr-lifecycle.sh +7 -4
- package/scripts/sw-predictive.sh +11 -5
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +3 -2
- package/scripts/sw-quality.sh +21 -10
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +1 -1
- package/scripts/sw-regression.sh +1 -1
- package/scripts/sw-release-manager.sh +1 -1
- package/scripts/sw-release.sh +1 -1
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +1 -1
- package/scripts/sw-retro.sh +1 -1
- package/scripts/sw-review-rerun.sh +1 -1
- package/scripts/sw-scale.sh +69 -11
- package/scripts/sw-security-audit.sh +1 -1
- package/scripts/sw-self-optimize.sh +168 -4
- package/scripts/sw-session.sh +3 -3
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +1 -1
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +11 -6
- package/scripts/sw-stream.sh +7 -4
- package/scripts/sw-swarm.sh +3 -2
- package/scripts/sw-team-stages.sh +1 -1
- package/scripts/sw-templates.sh +3 -3
- package/scripts/sw-testgen.sh +11 -6
- package/scripts/sw-tmux-pipeline.sh +1 -1
- package/scripts/sw-tmux.sh +35 -1
- package/scripts/sw-trace.sh +1 -1
- package/scripts/sw-tracker.sh +1 -1
- package/scripts/sw-triage.sh +7 -7
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +1 -1
- package/scripts/sw-webhook.sh +3 -2
- package/scripts/sw-widgets.sh +7 -4
- package/scripts/sw-worktree.sh +1 -1
- package/scripts/update-homebrew-sha.sh +21 -15
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# decide-scoring.sh — Value scoring for the decision engine
|
|
2
|
+
# Source from sw-decide.sh. Requires helpers.sh.
|
|
3
|
+
[[ -n "${_DECIDE_SCORING_LOADED:-}" ]] && return 0
|
|
4
|
+
_DECIDE_SCORING_LOADED=1
|
|
5
|
+
|
|
6
|
+
# ─── State ────────────────────────────────────────────────────────────────────
|
|
7
|
+
WEIGHTS_FILE="${HOME}/.shipwright/decisions/weights.json"
|
|
8
|
+
|
|
9
|
+
# Default weights
|
|
10
|
+
_W_IMPACT=30
|
|
11
|
+
_W_URGENCY=25
|
|
12
|
+
_W_EFFORT=20
|
|
13
|
+
_W_CONFIDENCE=15
|
|
14
|
+
_W_RISK=10
|
|
15
|
+
|
|
16
|
+
# ─── Weight Management ───────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
scoring_load_weights() {
|
|
19
|
+
if [[ -f "$WEIGHTS_FILE" ]]; then
|
|
20
|
+
_W_IMPACT=$(jq -r '.impact // 30' "$WEIGHTS_FILE" 2>/dev/null || echo "30")
|
|
21
|
+
_W_URGENCY=$(jq -r '.urgency // 25' "$WEIGHTS_FILE" 2>/dev/null || echo "25")
|
|
22
|
+
_W_EFFORT=$(jq -r '.effort // 20' "$WEIGHTS_FILE" 2>/dev/null || echo "20")
|
|
23
|
+
_W_CONFIDENCE=$(jq -r '.confidence // 15' "$WEIGHTS_FILE" 2>/dev/null || echo "15")
|
|
24
|
+
_W_RISK=$(jq -r '.risk // 10' "$WEIGHTS_FILE" 2>/dev/null || echo "10")
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Also try loading from tiers config
|
|
28
|
+
if [[ -n "${TIERS_FILE:-}" && -f "${TIERS_FILE:-}" ]]; then
|
|
29
|
+
local cfg_impact
|
|
30
|
+
cfg_impact=$(jq -r '.scoring_weights.impact // empty' "$TIERS_FILE" 2>/dev/null || true)
|
|
31
|
+
if [[ -n "$cfg_impact" ]]; then
|
|
32
|
+
_W_IMPACT=$(echo "$cfg_impact" | awk '{printf "%.0f", $1 * 100}')
|
|
33
|
+
_W_URGENCY=$(jq -r '.scoring_weights.urgency' "$TIERS_FILE" | awk '{printf "%.0f", $1 * 100}')
|
|
34
|
+
_W_EFFORT=$(jq -r '.scoring_weights.effort' "$TIERS_FILE" | awk '{printf "%.0f", $1 * 100}')
|
|
35
|
+
_W_CONFIDENCE=$(jq -r '.scoring_weights.confidence' "$TIERS_FILE" | awk '{printf "%.0f", $1 * 100}')
|
|
36
|
+
_W_RISK=$(jq -r '.scoring_weights.risk' "$TIERS_FILE" | awk '{printf "%.0f", $1 * 100}')
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
scoring_save_weights() {
|
|
42
|
+
mkdir -p "$(dirname "$WEIGHTS_FILE")"
|
|
43
|
+
local tmp
|
|
44
|
+
tmp=$(mktemp)
|
|
45
|
+
jq -n \
|
|
46
|
+
--argjson i "$_W_IMPACT" \
|
|
47
|
+
--argjson u "$_W_URGENCY" \
|
|
48
|
+
--argjson e "$_W_EFFORT" \
|
|
49
|
+
--argjson c "$_W_CONFIDENCE" \
|
|
50
|
+
--argjson r "$_W_RISK" \
|
|
51
|
+
--arg ts "$(now_iso)" \
|
|
52
|
+
'{impact:$i, urgency:$u, effort:$e, confidence:$c, risk:$r, updated_at:$ts}' \
|
|
53
|
+
> "$tmp" && mv "$tmp" "$WEIGHTS_FILE"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# ─── Dimension Scorers ────────────────────────────────────────────────────────
|
|
57
|
+
# Each returns 0-100
|
|
58
|
+
|
|
59
|
+
_score_impact() {
|
|
60
|
+
local candidate="$1"
|
|
61
|
+
local signal category risk_score
|
|
62
|
+
signal=$(echo "$candidate" | jq -r '.signal // "unknown"')
|
|
63
|
+
category=$(echo "$candidate" | jq -r '.category // "unknown"')
|
|
64
|
+
risk_score=$(echo "$candidate" | jq -r '.risk_score // 50')
|
|
65
|
+
|
|
66
|
+
case "$signal" in
|
|
67
|
+
security)
|
|
68
|
+
local severity
|
|
69
|
+
severity=$(echo "$candidate" | jq -r '.evidence.severity // "medium"')
|
|
70
|
+
case "$severity" in
|
|
71
|
+
critical) echo 90 ;; high) echo 70 ;; medium) echo 50 ;; *) echo 30 ;;
|
|
72
|
+
esac ;;
|
|
73
|
+
deps)
|
|
74
|
+
local diff
|
|
75
|
+
diff=$(echo "$candidate" | jq -r '.evidence.major_versions_behind // 1')
|
|
76
|
+
if [[ "${diff:-1}" -ge 3 ]]; then echo 70
|
|
77
|
+
elif [[ "${diff:-1}" -ge 2 ]]; then echo 55
|
|
78
|
+
else echo 35; fi ;;
|
|
79
|
+
coverage) echo 45 ;;
|
|
80
|
+
docs) echo 30 ;;
|
|
81
|
+
dead_code) echo 25 ;;
|
|
82
|
+
performance)
|
|
83
|
+
local pct
|
|
84
|
+
pct=$(echo "$candidate" | jq -r '.evidence.regression_pct // 0')
|
|
85
|
+
if [[ "${pct:-0}" -ge 50 ]]; then echo 75
|
|
86
|
+
elif [[ "${pct:-0}" -ge 30 ]]; then echo 60
|
|
87
|
+
else echo 40; fi ;;
|
|
88
|
+
failures) echo 55 ;;
|
|
89
|
+
dora) echo 60 ;;
|
|
90
|
+
architecture) echo 50 ;;
|
|
91
|
+
intelligence) echo 45 ;;
|
|
92
|
+
*) echo 40 ;;
|
|
93
|
+
esac
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_score_urgency() {
|
|
97
|
+
local candidate="$1"
|
|
98
|
+
local signal
|
|
99
|
+
signal=$(echo "$candidate" | jq -r '.signal // "unknown"')
|
|
100
|
+
|
|
101
|
+
case "$signal" in
|
|
102
|
+
security)
|
|
103
|
+
local severity
|
|
104
|
+
severity=$(echo "$candidate" | jq -r '.evidence.severity // "medium"')
|
|
105
|
+
case "$severity" in
|
|
106
|
+
critical) echo 95 ;; high) echo 75 ;; *) echo 45 ;;
|
|
107
|
+
esac ;;
|
|
108
|
+
performance) echo 60 ;;
|
|
109
|
+
dora) echo 55 ;;
|
|
110
|
+
failures) echo 65 ;;
|
|
111
|
+
deps) echo 35 ;;
|
|
112
|
+
coverage) echo 30 ;;
|
|
113
|
+
docs) echo 20 ;;
|
|
114
|
+
dead_code) echo 15 ;;
|
|
115
|
+
*) echo 40 ;;
|
|
116
|
+
esac
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_score_effort() {
|
|
120
|
+
# Inverted: easy = high score, hard = low score
|
|
121
|
+
local candidate="$1"
|
|
122
|
+
local category
|
|
123
|
+
category=$(echo "$candidate" | jq -r '.category // "unknown"')
|
|
124
|
+
|
|
125
|
+
case "$category" in
|
|
126
|
+
deps_patch) echo 90 ;;
|
|
127
|
+
deps_minor) echo 75 ;;
|
|
128
|
+
doc_sync) echo 85 ;;
|
|
129
|
+
dead_code) echo 70 ;;
|
|
130
|
+
test_coverage) echo 60 ;;
|
|
131
|
+
security_patch) echo 65 ;;
|
|
132
|
+
deps_major) echo 40 ;;
|
|
133
|
+
security_critical) echo 45 ;;
|
|
134
|
+
performance_regression) echo 35 ;;
|
|
135
|
+
recurring_failure) echo 30 ;;
|
|
136
|
+
refactor_hotspot) echo 25 ;;
|
|
137
|
+
architecture_drift) echo 20 ;;
|
|
138
|
+
dora_regression) echo 30 ;;
|
|
139
|
+
*) echo 50 ;;
|
|
140
|
+
esac
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_score_confidence() {
|
|
144
|
+
local candidate="$1"
|
|
145
|
+
local raw_conf
|
|
146
|
+
raw_conf=$(echo "$candidate" | jq -r '.confidence // "0.80"')
|
|
147
|
+
# Convert 0.0-1.0 to 0-100
|
|
148
|
+
echo "$raw_conf" | awk '{printf "%.0f", $1 * 100}'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_score_risk() {
|
|
152
|
+
local candidate="$1"
|
|
153
|
+
local risk_score
|
|
154
|
+
risk_score=$(echo "$candidate" | jq -r '.risk_score // 50')
|
|
155
|
+
echo "$risk_score"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# ─── Main Scorer ──────────────────────────────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
score_candidate() {
|
|
161
|
+
local candidate="$1"
|
|
162
|
+
|
|
163
|
+
local impact urgency effort confidence risk
|
|
164
|
+
impact=$(_score_impact "$candidate")
|
|
165
|
+
urgency=$(_score_urgency "$candidate")
|
|
166
|
+
effort=$(_score_effort "$candidate")
|
|
167
|
+
confidence=$(_score_confidence "$candidate")
|
|
168
|
+
risk=$(_score_risk "$candidate")
|
|
169
|
+
|
|
170
|
+
# Formula: value = (impact * w1) + (urgency * w2) + (effort * w3) + (confidence * w4) - (risk * w5)
|
|
171
|
+
# All weights are integers summing to 100, scores are 0-100
|
|
172
|
+
local value
|
|
173
|
+
value=$(( (impact * _W_IMPACT + urgency * _W_URGENCY + effort * _W_EFFORT + confidence * _W_CONFIDENCE - risk * _W_RISK) / 100 ))
|
|
174
|
+
|
|
175
|
+
# Clamp to 0-100
|
|
176
|
+
[[ "$value" -lt 0 ]] && value=0
|
|
177
|
+
[[ "$value" -gt 100 ]] && value=100
|
|
178
|
+
|
|
179
|
+
echo "$candidate" | jq \
|
|
180
|
+
--argjson vs "$value" \
|
|
181
|
+
--argjson imp "$impact" \
|
|
182
|
+
--argjson urg "$urgency" \
|
|
183
|
+
--argjson eff "$effort" \
|
|
184
|
+
--argjson conf "$confidence" \
|
|
185
|
+
--argjson rsk "$risk" \
|
|
186
|
+
'. + {value_score: $vs, scores: {impact: $imp, urgency: $urg, effort: $eff, confidence: $conf, risk: $rsk}}'
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
# ─── Outcome Learning ────────────────────────────────────────────────────────
|
|
190
|
+
# EMA (exponential moving average) weight adjustment based on decision outcomes
|
|
191
|
+
|
|
192
|
+
scoring_update_weights() {
|
|
193
|
+
local outcome="$1"
|
|
194
|
+
local result
|
|
195
|
+
result=$(echo "$outcome" | jq -r '.result // "unknown"')
|
|
196
|
+
local alpha=20 # EMA factor (out of 100): 20% new, 80% old
|
|
197
|
+
|
|
198
|
+
# Adjust weights based on which dimension was most predictive
|
|
199
|
+
# Success: boost the dominant scoring dimension; Failure: dampen it
|
|
200
|
+
local signal
|
|
201
|
+
signal=$(echo "$outcome" | jq -r '.signal // "unknown"')
|
|
202
|
+
|
|
203
|
+
case "$result" in
|
|
204
|
+
success)
|
|
205
|
+
case "$signal" in
|
|
206
|
+
security) _W_URGENCY=$(( (_W_URGENCY * (100 - alpha) + 30 * alpha) / 100 )) ;;
|
|
207
|
+
deps) _W_EFFORT=$(( (_W_EFFORT * (100 - alpha) + 25 * alpha) / 100 )) ;;
|
|
208
|
+
performance) _W_IMPACT=$(( (_W_IMPACT * (100 - alpha) + 35 * alpha) / 100 )) ;;
|
|
209
|
+
failures) _W_URGENCY=$(( (_W_URGENCY * (100 - alpha) + 30 * alpha) / 100 )) ;;
|
|
210
|
+
*) ;; # No adjustment for generic signals
|
|
211
|
+
esac ;;
|
|
212
|
+
failure)
|
|
213
|
+
# On failure, slightly increase risk weight
|
|
214
|
+
_W_RISK=$(( (_W_RISK * (100 - alpha) + 15 * alpha) / 100 )) ;;
|
|
215
|
+
esac
|
|
216
|
+
|
|
217
|
+
# Normalize weights to sum to 100
|
|
218
|
+
local total=$(( _W_IMPACT + _W_URGENCY + _W_EFFORT + _W_CONFIDENCE + _W_RISK ))
|
|
219
|
+
if [[ "$total" -gt 0 && "$total" -ne 100 ]]; then
|
|
220
|
+
_W_IMPACT=$(( _W_IMPACT * 100 / total ))
|
|
221
|
+
_W_URGENCY=$(( _W_URGENCY * 100 / total ))
|
|
222
|
+
_W_EFFORT=$(( _W_EFFORT * 100 / total ))
|
|
223
|
+
_W_CONFIDENCE=$(( _W_CONFIDENCE * 100 / total ))
|
|
224
|
+
_W_RISK=$((100 - _W_IMPACT - _W_URGENCY - _W_EFFORT - _W_CONFIDENCE))
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
scoring_save_weights
|
|
228
|
+
}
|