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.
Files changed (143) hide show
  1. package/README.md +21 -7
  2. package/completions/_shipwright +247 -93
  3. package/completions/shipwright.bash +69 -15
  4. package/completions/shipwright.fish +309 -41
  5. package/config/decision-tiers.json +55 -0
  6. package/config/defaults.json +25 -2
  7. package/config/event-schema.json +142 -5
  8. package/config/policy.json +8 -0
  9. package/dashboard/public/index.html +6 -0
  10. package/dashboard/public/styles.css +76 -0
  11. package/dashboard/server.ts +51 -0
  12. package/dashboard/src/core/api.ts +5 -0
  13. package/dashboard/src/types/api.ts +10 -0
  14. package/dashboard/src/views/metrics.ts +69 -1
  15. package/package.json +3 -3
  16. package/scripts/lib/architecture.sh +2 -1
  17. package/scripts/lib/bootstrap.sh +0 -0
  18. package/scripts/lib/config.sh +0 -0
  19. package/scripts/lib/daemon-adaptive.sh +4 -2
  20. package/scripts/lib/daemon-dispatch.sh +24 -1
  21. package/scripts/lib/daemon-failure.sh +0 -0
  22. package/scripts/lib/daemon-health.sh +0 -0
  23. package/scripts/lib/daemon-patrol.sh +42 -7
  24. package/scripts/lib/daemon-poll.sh +17 -0
  25. package/scripts/lib/daemon-state.sh +17 -0
  26. package/scripts/lib/daemon-triage.sh +1 -1
  27. package/scripts/lib/decide-autonomy.sh +295 -0
  28. package/scripts/lib/decide-scoring.sh +228 -0
  29. package/scripts/lib/decide-signals.sh +462 -0
  30. package/scripts/lib/fleet-failover.sh +0 -0
  31. package/scripts/lib/helpers.sh +19 -18
  32. package/scripts/lib/pipeline-detection.sh +1 -1
  33. package/scripts/lib/pipeline-github.sh +0 -0
  34. package/scripts/lib/pipeline-intelligence.sh +23 -4
  35. package/scripts/lib/pipeline-quality-checks.sh +11 -6
  36. package/scripts/lib/pipeline-quality.sh +0 -0
  37. package/scripts/lib/pipeline-stages.sh +330 -33
  38. package/scripts/lib/pipeline-state.sh +14 -0
  39. package/scripts/lib/policy.sh +0 -0
  40. package/scripts/lib/test-helpers.sh +0 -0
  41. package/scripts/postinstall.mjs +75 -1
  42. package/scripts/signals/example-collector.sh +36 -0
  43. package/scripts/sw +8 -4
  44. package/scripts/sw-activity.sh +1 -7
  45. package/scripts/sw-adaptive.sh +7 -7
  46. package/scripts/sw-adversarial.sh +1 -1
  47. package/scripts/sw-architecture-enforcer.sh +1 -1
  48. package/scripts/sw-auth.sh +1 -1
  49. package/scripts/sw-autonomous.sh +1 -1
  50. package/scripts/sw-changelog.sh +1 -1
  51. package/scripts/sw-checkpoint.sh +1 -1
  52. package/scripts/sw-ci.sh +11 -6
  53. package/scripts/sw-cleanup.sh +1 -1
  54. package/scripts/sw-code-review.sh +36 -17
  55. package/scripts/sw-connect.sh +1 -1
  56. package/scripts/sw-context.sh +1 -1
  57. package/scripts/sw-cost.sh +71 -5
  58. package/scripts/sw-daemon.sh +6 -3
  59. package/scripts/sw-dashboard.sh +1 -1
  60. package/scripts/sw-db.sh +53 -38
  61. package/scripts/sw-decide.sh +685 -0
  62. package/scripts/sw-decompose.sh +1 -1
  63. package/scripts/sw-deps.sh +1 -1
  64. package/scripts/sw-developer-simulation.sh +1 -1
  65. package/scripts/sw-discovery.sh +80 -4
  66. package/scripts/sw-doc-fleet.sh +1 -1
  67. package/scripts/sw-docs-agent.sh +1 -1
  68. package/scripts/sw-docs.sh +1 -1
  69. package/scripts/sw-doctor.sh +1 -1
  70. package/scripts/sw-dora.sh +1 -1
  71. package/scripts/sw-durable.sh +9 -5
  72. package/scripts/sw-e2e-orchestrator.sh +1 -1
  73. package/scripts/sw-eventbus.sh +7 -4
  74. package/scripts/sw-evidence.sh +1 -1
  75. package/scripts/sw-feedback.sh +1 -1
  76. package/scripts/sw-fix.sh +1 -1
  77. package/scripts/sw-fleet-discover.sh +1 -1
  78. package/scripts/sw-fleet-viz.sh +6 -4
  79. package/scripts/sw-fleet.sh +1 -1
  80. package/scripts/sw-github-app.sh +3 -2
  81. package/scripts/sw-github-checks.sh +1 -1
  82. package/scripts/sw-github-deploy.sh +1 -1
  83. package/scripts/sw-github-graphql.sh +1 -1
  84. package/scripts/sw-guild.sh +1 -1
  85. package/scripts/sw-heartbeat.sh +1 -1
  86. package/scripts/sw-hygiene.sh +5 -3
  87. package/scripts/sw-incident.sh +9 -5
  88. package/scripts/sw-init.sh +1 -1
  89. package/scripts/sw-instrument.sh +1 -1
  90. package/scripts/sw-intelligence.sh +11 -6
  91. package/scripts/sw-jira.sh +1 -1
  92. package/scripts/sw-launchd.sh +1 -1
  93. package/scripts/sw-linear.sh +1 -1
  94. package/scripts/sw-logs.sh +1 -1
  95. package/scripts/sw-loop.sh +338 -32
  96. package/scripts/sw-memory.sh +23 -6
  97. package/scripts/sw-mission-control.sh +1 -1
  98. package/scripts/sw-model-router.sh +3 -2
  99. package/scripts/sw-otel.sh +8 -4
  100. package/scripts/sw-oversight.sh +1 -1
  101. package/scripts/sw-pipeline-composer.sh +3 -1
  102. package/scripts/sw-pipeline-vitals.sh +11 -6
  103. package/scripts/sw-pipeline.sh +92 -8
  104. package/scripts/sw-pm.sh +5 -4
  105. package/scripts/sw-pr-lifecycle.sh +7 -4
  106. package/scripts/sw-predictive.sh +11 -5
  107. package/scripts/sw-prep.sh +1 -1
  108. package/scripts/sw-ps.sh +1 -1
  109. package/scripts/sw-public-dashboard.sh +3 -2
  110. package/scripts/sw-quality.sh +21 -10
  111. package/scripts/sw-reaper.sh +1 -1
  112. package/scripts/sw-recruit.sh +1 -1
  113. package/scripts/sw-regression.sh +1 -1
  114. package/scripts/sw-release-manager.sh +1 -1
  115. package/scripts/sw-release.sh +1 -1
  116. package/scripts/sw-remote.sh +1 -1
  117. package/scripts/sw-replay.sh +1 -1
  118. package/scripts/sw-retro.sh +1 -1
  119. package/scripts/sw-review-rerun.sh +1 -1
  120. package/scripts/sw-scale.sh +69 -11
  121. package/scripts/sw-security-audit.sh +1 -1
  122. package/scripts/sw-self-optimize.sh +168 -4
  123. package/scripts/sw-session.sh +3 -3
  124. package/scripts/sw-setup.sh +1 -1
  125. package/scripts/sw-standup.sh +1 -1
  126. package/scripts/sw-status.sh +1 -1
  127. package/scripts/sw-strategic.sh +11 -6
  128. package/scripts/sw-stream.sh +7 -4
  129. package/scripts/sw-swarm.sh +3 -2
  130. package/scripts/sw-team-stages.sh +1 -1
  131. package/scripts/sw-templates.sh +3 -3
  132. package/scripts/sw-testgen.sh +11 -6
  133. package/scripts/sw-tmux-pipeline.sh +1 -1
  134. package/scripts/sw-tmux.sh +35 -1
  135. package/scripts/sw-trace.sh +1 -1
  136. package/scripts/sw-tracker.sh +1 -1
  137. package/scripts/sw-triage.sh +7 -7
  138. package/scripts/sw-upgrade.sh +1 -1
  139. package/scripts/sw-ux.sh +1 -1
  140. package/scripts/sw-webhook.sh +3 -2
  141. package/scripts/sw-widgets.sh +7 -4
  142. package/scripts/sw-worktree.sh +1 -1
  143. 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
+ }