shipwright-cli 3.1.0 → 3.3.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 (283) hide show
  1. package/.claude/agents/code-reviewer.md +2 -0
  2. package/.claude/agents/devops-engineer.md +2 -0
  3. package/.claude/agents/doc-fleet-agent.md +2 -0
  4. package/.claude/agents/pipeline-agent.md +2 -0
  5. package/.claude/agents/shell-script-specialist.md +2 -0
  6. package/.claude/agents/test-specialist.md +2 -0
  7. package/.claude/hooks/agent-crash-capture.sh +32 -0
  8. package/.claude/hooks/post-tool-use.sh +3 -2
  9. package/.claude/hooks/pre-tool-use.sh +35 -3
  10. package/README.md +22 -8
  11. package/claude-code/hooks/config-change.sh +18 -0
  12. package/claude-code/hooks/instructions-reloaded.sh +7 -0
  13. package/claude-code/hooks/worktree-create.sh +25 -0
  14. package/claude-code/hooks/worktree-remove.sh +20 -0
  15. package/config/code-constitution.json +130 -0
  16. package/config/defaults.json +25 -2
  17. package/config/policy.json +1 -1
  18. package/dashboard/middleware/auth.ts +134 -0
  19. package/dashboard/middleware/constants.ts +21 -0
  20. package/dashboard/public/index.html +8 -6
  21. package/dashboard/public/styles.css +176 -97
  22. package/dashboard/routes/auth.ts +38 -0
  23. package/dashboard/server.ts +117 -25
  24. package/dashboard/services/config.ts +26 -0
  25. package/dashboard/services/db.ts +118 -0
  26. package/dashboard/src/canvas/pixel-agent.ts +298 -0
  27. package/dashboard/src/canvas/pixel-sprites.ts +440 -0
  28. package/dashboard/src/canvas/shipyard-effects.ts +367 -0
  29. package/dashboard/src/canvas/shipyard-scene.ts +616 -0
  30. package/dashboard/src/canvas/submarine-layout.ts +267 -0
  31. package/dashboard/src/components/header.ts +8 -7
  32. package/dashboard/src/core/api.ts +5 -0
  33. package/dashboard/src/core/router.ts +1 -0
  34. package/dashboard/src/design/submarine-theme.ts +253 -0
  35. package/dashboard/src/main.ts +2 -0
  36. package/dashboard/src/types/api.ts +12 -1
  37. package/dashboard/src/views/activity.ts +2 -1
  38. package/dashboard/src/views/metrics.ts +69 -1
  39. package/dashboard/src/views/shipyard.ts +39 -0
  40. package/dashboard/types/index.ts +166 -0
  41. package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
  42. package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
  43. package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
  44. package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
  45. package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
  46. package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
  47. package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
  48. package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
  49. package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
  50. package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
  51. package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
  52. package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
  53. package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
  54. package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
  55. package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
  56. package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
  57. package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
  58. package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
  59. package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
  60. package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
  61. package/docs/research/RESEARCH_INDEX.md +439 -0
  62. package/docs/research/RESEARCH_SOURCES.md +440 -0
  63. package/docs/research/RESEARCH_SUMMARY.txt +275 -0
  64. package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
  65. package/package.json +2 -2
  66. package/scripts/lib/adaptive-model.sh +427 -0
  67. package/scripts/lib/adaptive-timeout.sh +316 -0
  68. package/scripts/lib/audit-trail.sh +309 -0
  69. package/scripts/lib/auto-recovery.sh +471 -0
  70. package/scripts/lib/bandit-selector.sh +431 -0
  71. package/scripts/lib/bootstrap.sh +104 -2
  72. package/scripts/lib/causal-graph.sh +455 -0
  73. package/scripts/lib/compat.sh +126 -0
  74. package/scripts/lib/compound-audit.sh +337 -0
  75. package/scripts/lib/constitutional.sh +454 -0
  76. package/scripts/lib/context-budget.sh +359 -0
  77. package/scripts/lib/convergence.sh +594 -0
  78. package/scripts/lib/cost-optimizer.sh +634 -0
  79. package/scripts/lib/daemon-adaptive.sh +14 -2
  80. package/scripts/lib/daemon-dispatch.sh +106 -17
  81. package/scripts/lib/daemon-failure.sh +34 -4
  82. package/scripts/lib/daemon-patrol.sh +25 -4
  83. package/scripts/lib/daemon-poll-github.sh +361 -0
  84. package/scripts/lib/daemon-poll-health.sh +299 -0
  85. package/scripts/lib/daemon-poll.sh +27 -611
  86. package/scripts/lib/daemon-state.sh +119 -66
  87. package/scripts/lib/daemon-triage.sh +10 -0
  88. package/scripts/lib/dod-scorecard.sh +442 -0
  89. package/scripts/lib/error-actionability.sh +300 -0
  90. package/scripts/lib/formal-spec.sh +461 -0
  91. package/scripts/lib/helpers.sh +180 -5
  92. package/scripts/lib/intent-analysis.sh +409 -0
  93. package/scripts/lib/loop-convergence.sh +350 -0
  94. package/scripts/lib/loop-iteration.sh +682 -0
  95. package/scripts/lib/loop-progress.sh +48 -0
  96. package/scripts/lib/loop-restart.sh +185 -0
  97. package/scripts/lib/memory-effectiveness.sh +506 -0
  98. package/scripts/lib/mutation-executor.sh +352 -0
  99. package/scripts/lib/outcome-feedback.sh +521 -0
  100. package/scripts/lib/pipeline-cli.sh +336 -0
  101. package/scripts/lib/pipeline-commands.sh +1216 -0
  102. package/scripts/lib/pipeline-detection.sh +101 -3
  103. package/scripts/lib/pipeline-execution.sh +897 -0
  104. package/scripts/lib/pipeline-github.sh +28 -3
  105. package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
  106. package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
  107. package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
  108. package/scripts/lib/pipeline-intelligence.sh +104 -1138
  109. package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
  110. package/scripts/lib/pipeline-quality-checks.sh +17 -711
  111. package/scripts/lib/pipeline-quality-gates.sh +563 -0
  112. package/scripts/lib/pipeline-stages-build.sh +730 -0
  113. package/scripts/lib/pipeline-stages-delivery.sh +965 -0
  114. package/scripts/lib/pipeline-stages-intake.sh +1133 -0
  115. package/scripts/lib/pipeline-stages-monitor.sh +407 -0
  116. package/scripts/lib/pipeline-stages-review.sh +1022 -0
  117. package/scripts/lib/pipeline-stages.sh +161 -2901
  118. package/scripts/lib/pipeline-state.sh +36 -5
  119. package/scripts/lib/pipeline-util.sh +487 -0
  120. package/scripts/lib/policy-learner.sh +438 -0
  121. package/scripts/lib/process-reward.sh +493 -0
  122. package/scripts/lib/project-detect.sh +649 -0
  123. package/scripts/lib/quality-profile.sh +334 -0
  124. package/scripts/lib/recruit-commands.sh +885 -0
  125. package/scripts/lib/recruit-learning.sh +739 -0
  126. package/scripts/lib/recruit-roles.sh +648 -0
  127. package/scripts/lib/reward-aggregator.sh +458 -0
  128. package/scripts/lib/rl-optimizer.sh +362 -0
  129. package/scripts/lib/root-cause.sh +427 -0
  130. package/scripts/lib/scope-enforcement.sh +445 -0
  131. package/scripts/lib/session-restart.sh +493 -0
  132. package/scripts/lib/skill-memory.sh +300 -0
  133. package/scripts/lib/skill-registry.sh +775 -0
  134. package/scripts/lib/spec-driven.sh +476 -0
  135. package/scripts/lib/test-helpers.sh +18 -7
  136. package/scripts/lib/test-holdout.sh +429 -0
  137. package/scripts/lib/test-optimizer.sh +511 -0
  138. package/scripts/shipwright-file-suggest.sh +45 -0
  139. package/scripts/skills/adversarial-quality.md +61 -0
  140. package/scripts/skills/api-design.md +44 -0
  141. package/scripts/skills/architecture-design.md +50 -0
  142. package/scripts/skills/brainstorming.md +43 -0
  143. package/scripts/skills/data-pipeline.md +44 -0
  144. package/scripts/skills/deploy-safety.md +64 -0
  145. package/scripts/skills/documentation.md +38 -0
  146. package/scripts/skills/frontend-design.md +45 -0
  147. package/scripts/skills/generated/.gitkeep +0 -0
  148. package/scripts/skills/generated/_refinements/.gitkeep +0 -0
  149. package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
  150. package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
  151. package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
  152. package/scripts/skills/generated/cli-version-management.md +29 -0
  153. package/scripts/skills/generated/collection-system-validation.md +99 -0
  154. package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
  155. package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
  156. package/scripts/skills/generated/test-parallelization-detection.md +65 -0
  157. package/scripts/skills/observability.md +79 -0
  158. package/scripts/skills/performance.md +48 -0
  159. package/scripts/skills/pr-quality.md +49 -0
  160. package/scripts/skills/product-thinking.md +43 -0
  161. package/scripts/skills/security-audit.md +49 -0
  162. package/scripts/skills/systematic-debugging.md +40 -0
  163. package/scripts/skills/testing-strategy.md +47 -0
  164. package/scripts/skills/two-stage-review.md +52 -0
  165. package/scripts/skills/validation-thoroughness.md +55 -0
  166. package/scripts/sw +9 -3
  167. package/scripts/sw-activity.sh +9 -8
  168. package/scripts/sw-adaptive.sh +8 -7
  169. package/scripts/sw-adversarial.sh +2 -1
  170. package/scripts/sw-architecture-enforcer.sh +3 -1
  171. package/scripts/sw-auth.sh +12 -2
  172. package/scripts/sw-autonomous.sh +5 -1
  173. package/scripts/sw-changelog.sh +4 -1
  174. package/scripts/sw-checkpoint.sh +2 -1
  175. package/scripts/sw-ci.sh +15 -6
  176. package/scripts/sw-cleanup.sh +4 -26
  177. package/scripts/sw-code-review.sh +45 -20
  178. package/scripts/sw-connect.sh +2 -1
  179. package/scripts/sw-context.sh +2 -1
  180. package/scripts/sw-cost.sh +107 -5
  181. package/scripts/sw-daemon.sh +71 -11
  182. package/scripts/sw-dashboard.sh +3 -1
  183. package/scripts/sw-db.sh +71 -20
  184. package/scripts/sw-decide.sh +8 -2
  185. package/scripts/sw-decompose.sh +360 -17
  186. package/scripts/sw-deps.sh +4 -1
  187. package/scripts/sw-developer-simulation.sh +4 -1
  188. package/scripts/sw-discovery.sh +378 -5
  189. package/scripts/sw-doc-fleet.sh +4 -1
  190. package/scripts/sw-docs-agent.sh +3 -1
  191. package/scripts/sw-docs.sh +2 -1
  192. package/scripts/sw-doctor.sh +453 -2
  193. package/scripts/sw-dora.sh +4 -1
  194. package/scripts/sw-durable.sh +12 -7
  195. package/scripts/sw-e2e-orchestrator.sh +17 -16
  196. package/scripts/sw-eventbus.sh +13 -4
  197. package/scripts/sw-evidence.sh +364 -12
  198. package/scripts/sw-feedback.sh +550 -9
  199. package/scripts/sw-fix.sh +20 -1
  200. package/scripts/sw-fleet-discover.sh +6 -2
  201. package/scripts/sw-fleet-viz.sh +9 -4
  202. package/scripts/sw-fleet.sh +5 -1
  203. package/scripts/sw-github-app.sh +18 -4
  204. package/scripts/sw-github-checks.sh +3 -2
  205. package/scripts/sw-github-deploy.sh +3 -2
  206. package/scripts/sw-github-graphql.sh +18 -7
  207. package/scripts/sw-guild.sh +5 -1
  208. package/scripts/sw-heartbeat.sh +5 -30
  209. package/scripts/sw-hello.sh +67 -0
  210. package/scripts/sw-hygiene.sh +10 -3
  211. package/scripts/sw-incident.sh +273 -5
  212. package/scripts/sw-init.sh +18 -2
  213. package/scripts/sw-instrument.sh +10 -2
  214. package/scripts/sw-intelligence.sh +44 -7
  215. package/scripts/sw-jira.sh +5 -1
  216. package/scripts/sw-launchd.sh +2 -1
  217. package/scripts/sw-linear.sh +4 -1
  218. package/scripts/sw-logs.sh +4 -1
  219. package/scripts/sw-loop.sh +436 -1076
  220. package/scripts/sw-memory.sh +357 -3
  221. package/scripts/sw-mission-control.sh +6 -1
  222. package/scripts/sw-model-router.sh +483 -27
  223. package/scripts/sw-otel.sh +15 -4
  224. package/scripts/sw-oversight.sh +14 -5
  225. package/scripts/sw-patrol-meta.sh +334 -0
  226. package/scripts/sw-pipeline-composer.sh +7 -1
  227. package/scripts/sw-pipeline-vitals.sh +12 -6
  228. package/scripts/sw-pipeline.sh +54 -2653
  229. package/scripts/sw-pm.sh +16 -8
  230. package/scripts/sw-pr-lifecycle.sh +2 -1
  231. package/scripts/sw-predictive.sh +17 -5
  232. package/scripts/sw-prep.sh +185 -2
  233. package/scripts/sw-ps.sh +5 -25
  234. package/scripts/sw-public-dashboard.sh +17 -4
  235. package/scripts/sw-quality.sh +14 -6
  236. package/scripts/sw-reaper.sh +8 -25
  237. package/scripts/sw-recruit.sh +156 -2303
  238. package/scripts/sw-regression.sh +19 -12
  239. package/scripts/sw-release-manager.sh +3 -1
  240. package/scripts/sw-release.sh +4 -1
  241. package/scripts/sw-remote.sh +3 -1
  242. package/scripts/sw-replay.sh +7 -1
  243. package/scripts/sw-retro.sh +158 -1
  244. package/scripts/sw-review-rerun.sh +3 -1
  245. package/scripts/sw-scale.sh +14 -5
  246. package/scripts/sw-security-audit.sh +6 -1
  247. package/scripts/sw-self-optimize.sh +173 -6
  248. package/scripts/sw-session.sh +9 -3
  249. package/scripts/sw-setup.sh +3 -1
  250. package/scripts/sw-stall-detector.sh +406 -0
  251. package/scripts/sw-standup.sh +15 -7
  252. package/scripts/sw-status.sh +3 -1
  253. package/scripts/sw-strategic.sh +14 -6
  254. package/scripts/sw-stream.sh +13 -4
  255. package/scripts/sw-swarm.sh +20 -7
  256. package/scripts/sw-team-stages.sh +13 -6
  257. package/scripts/sw-templates.sh +7 -31
  258. package/scripts/sw-testgen.sh +17 -6
  259. package/scripts/sw-tmux-pipeline.sh +4 -1
  260. package/scripts/sw-tmux-role-color.sh +2 -0
  261. package/scripts/sw-tmux-status.sh +1 -1
  262. package/scripts/sw-tmux.sh +37 -1
  263. package/scripts/sw-trace.sh +3 -1
  264. package/scripts/sw-tracker-github.sh +3 -0
  265. package/scripts/sw-tracker-jira.sh +3 -0
  266. package/scripts/sw-tracker-linear.sh +3 -0
  267. package/scripts/sw-tracker.sh +3 -1
  268. package/scripts/sw-triage.sh +3 -2
  269. package/scripts/sw-upgrade.sh +3 -1
  270. package/scripts/sw-ux.sh +5 -2
  271. package/scripts/sw-webhook.sh +5 -2
  272. package/scripts/sw-widgets.sh +9 -4
  273. package/scripts/sw-worktree.sh +15 -3
  274. package/scripts/test-skill-injection.sh +1233 -0
  275. package/templates/pipelines/autonomous.json +27 -3
  276. package/templates/pipelines/cost-aware.json +34 -8
  277. package/templates/pipelines/deployed.json +12 -0
  278. package/templates/pipelines/enterprise.json +12 -0
  279. package/templates/pipelines/fast.json +6 -0
  280. package/templates/pipelines/full.json +27 -3
  281. package/templates/pipelines/hotfix.json +6 -0
  282. package/templates/pipelines/standard.json +12 -0
  283. package/templates/pipelines/tdd.json +12 -0
@@ -7,8 +7,10 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="3.1.0"
10
+ # shellcheck disable=SC2034
11
+ VERSION="3.3.0"
11
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ # shellcheck disable=SC2034
12
14
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
15
 
14
16
  # ─── Dependency check ─────────────────────────────────────────────────────────
@@ -36,6 +38,7 @@ fi
36
38
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
37
39
  emit_event() {
38
40
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
41
+ # shellcheck disable=SC2155
39
42
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
40
43
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
41
44
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
@@ -156,10 +159,60 @@ query_discoveries() {
156
159
  fi
157
160
  done < "$DISCOVERIES_FILE"
158
161
 
159
- # Optionally use Claude to rank when many candidates
162
+ # Use Claude to rank candidates by relevance when there are many
160
163
  if [[ "${INTELLIGENCE_ENABLED:-auto}" != "false" ]] && command -v claude &>/dev/null 2>&1 && [[ ${#candidates[@]} -gt 5 ]]; then
161
- # TODO: batch Claude call to rank by relevance (future enhancement)
162
- :
164
+ local ranked_json=""
165
+ local candidate_summaries=""
166
+ local idx=0
167
+ for line in "${candidates[@]+"${candidates[@]}"}"; do
168
+ local disc cat_name
169
+ disc=$(echo "$line" | jq -r '.discovery // ""' 2>/dev/null || echo "")
170
+ cat_name=$(echo "$line" | jq -r '.category // ""' 2>/dev/null || echo "")
171
+ candidate_summaries="${candidate_summaries}${idx}: [${cat_name}] ${disc}"$'\n'
172
+ idx=$((idx + 1))
173
+ done
174
+
175
+ local rank_prompt
176
+ rank_prompt="Given these discoveries and the query context '${query_context}', return a JSON array of indices sorted by relevance (most relevant first). Only return the JSON array, no explanation.
177
+
178
+ Discoveries:
179
+ ${candidate_summaries}"
180
+
181
+ local _claude_timeout
182
+ _claude_timeout=30
183
+ local _timeout_cmd=""
184
+ if command -v gtimeout >/dev/null 2>&1; then _timeout_cmd="gtimeout $_claude_timeout"
185
+ elif command -v timeout >/dev/null 2>&1; then _timeout_cmd="timeout $_claude_timeout"
186
+ fi
187
+
188
+ ranked_json=$($_timeout_cmd claude -p "$rank_prompt" 2>/dev/null || true)
189
+
190
+ # Extract array from response (handle markdown fences)
191
+ local indices_str=""
192
+ if [[ -n "$ranked_json" ]]; then
193
+ indices_str=$(echo "$ranked_json" | sed -n 's/.*\(\[[ 0-9,]*\]\).*/\1/p' | head -1)
194
+ fi
195
+
196
+ if [[ -n "$indices_str" ]] && echo "$indices_str" | jq -e 'type == "array"' >/dev/null 2>&1; then
197
+ local reordered=()
198
+ local seen=""
199
+ while IFS= read -r rank_idx; do
200
+ [[ -z "$rank_idx" ]] && continue
201
+ if [[ "$rank_idx" -ge 0 && "$rank_idx" -lt "${#candidates[@]}" ]]; then
202
+ # Avoid duplicates
203
+ case " $seen " in *" $rank_idx "*) continue ;; esac
204
+ seen="$seen $rank_idx"
205
+ reordered+=("${candidates[$rank_idx]}")
206
+ fi
207
+ done < <(echo "$indices_str" | jq -r '.[]' 2>/dev/null)
208
+ # Append any candidates not in the ranking
209
+ idx=0
210
+ for line in "${candidates[@]+"${candidates[@]}"}"; do
211
+ case " $seen " in *" $idx "*) ;; *) reordered+=("$line") ;; esac
212
+ idx=$((idx + 1))
213
+ done
214
+ candidates=("${reordered[@]+"${reordered[@]}"}")
215
+ fi
163
216
  fi
164
217
 
165
218
  # Output up to limit
@@ -449,6 +502,284 @@ show_status() {
449
502
  [[ -f "$DISCOVERIES_FILE" ]] && echo -e " ${CYAN}Size:${RESET} $(du -h "$DISCOVERIES_FILE" | cut -f1)"
450
503
  }
451
504
 
505
+ # ─── Real-Time Bus Integration ──────────────────────────────────────────
506
+ # Event bus publish/subscribe for instant knowledge sharing
507
+ discovery_bus_publish() {
508
+ local discovery_id="$1"
509
+ local priority="$2"
510
+ local confidence="$3"
511
+ local entry_json="$4"
512
+
513
+ # Try eventbus if available, fallback to JSONL
514
+ if command -v shipwright >/dev/null 2>&1 && shipwright eventbus status >/dev/null 2>&1; then
515
+ # Publish to event bus with discovery metadata
516
+ local payload
517
+ payload=$(jq -cn \
518
+ --arg discovery_id "$discovery_id" \
519
+ --arg priority "$priority" \
520
+ --arg confidence "$confidence" \
521
+ --argjson entry "$entry_json" \
522
+ '{discovery_id: $discovery_id, priority: $priority, confidence: $confidence, entry: $entry}')
523
+
524
+ shipwright eventbus publish "discovery.new" "discovery" "$discovery_id" "$payload" 2>/dev/null || true
525
+ emit_event "discovery.published" "discovery_id=$discovery_id" "priority=$priority" "confidence=$confidence"
526
+ else
527
+ # Fallback: just log to events.jsonl
528
+ emit_event "discovery.new" "discovery_id=$discovery_id" "priority=$priority" "confidence=$confidence"
529
+ fi
530
+ }
531
+
532
+ discovery_bus_subscribe() {
533
+ local repo_filter="${1:-}"
534
+ local domain_filter="${2:-}"
535
+
536
+ # Subscribe via eventbus if available
537
+ if command -v shipwright >/dev/null 2>&1; then
538
+ shipwright eventbus subscribe "discovery.new" 2>/dev/null | while IFS= read -r event; do
539
+ [[ -z "$event" ]] && continue
540
+
541
+ local entry_repo entry_domain
542
+ entry_repo=$(echo "$event" | jq -r '.entry.repo // ""' 2>/dev/null || echo "")
543
+ entry_domain=$(echo "$event" | jq -r '.entry.category // ""' 2>/dev/null || echo "")
544
+
545
+ # Filter by repo and domain if specified
546
+ if [[ -n "$repo_filter" && "$entry_repo" != "$repo_filter" ]]; then
547
+ continue
548
+ fi
549
+ if [[ -n "$domain_filter" && "$entry_domain" != "$domain_filter" ]]; then
550
+ continue
551
+ fi
552
+
553
+ echo "$event"
554
+ done
555
+ else
556
+ warn "Event bus not available — fallback to JSONL polling"
557
+ fi
558
+ }
559
+
560
+ # ─── Fleet Broadcasting ──────────────────────────────────────────────────
561
+ discovery_fleet_broadcast() {
562
+ local discovery_id="$1"
563
+ local entry_json="$2"
564
+ local fleet_config="${3:-.claude/fleet-config.json}"
565
+
566
+ # If fleet config exists, broadcast to all peer repos
567
+ if [[ -f "$fleet_config" ]]; then
568
+ local peer_repos
569
+ peer_repos=$(jq -r '.repos[]?.path // empty' "$fleet_config" 2>/dev/null || true)
570
+
571
+ if [[ -n "$peer_repos" ]]; then
572
+ local repo_count=0
573
+ while IFS= read -r repo_path; do
574
+ [[ -z "$repo_path" ]] && continue
575
+
576
+ local peer_discovery_dir
577
+ peer_discovery_dir="${repo_path}/.shipwright/discoveries"
578
+
579
+ # Skip if this is the current repo
580
+ if [[ "$repo_path" == "$(pwd)" ]]; then
581
+ continue
582
+ fi
583
+
584
+ # Write discovery to peer's discovery directory
585
+ if mkdir -p "$peer_discovery_dir"; then
586
+ local tmp_file peer_file
587
+ tmp_file=$(mktemp)
588
+ peer_file="${peer_discovery_dir}/fleet-sync.jsonl"
589
+
590
+ echo "$entry_json" >> "$tmp_file"
591
+ mv "$tmp_file" "$peer_file" 2>/dev/null || true
592
+ repo_count=$((repo_count + 1))
593
+ fi
594
+ done <<< "$peer_repos"
595
+
596
+ [[ "$repo_count" -gt 0 ]] && success "Broadcasted to ${repo_count} fleet repos"
597
+ fi
598
+ fi
599
+ }
600
+
601
+ # ─── Priority & Urgency Assignment ──────────────────────────────────────
602
+ discovery_prioritize() {
603
+ local severity="${1:-}"
604
+ local impact="${2:-normal}"
605
+
606
+ # Assign priority based on severity and impact
607
+ local priority="P3"
608
+
609
+ case "$severity" in
610
+ security|critical|data-loss|crash)
611
+ priority="P0"
612
+ ;;
613
+ test-failure|regression|blocking)
614
+ priority="P1"
615
+ ;;
616
+ performance|deprecation|warning)
617
+ priority="P2"
618
+ ;;
619
+ info|enhancement|suggestion)
620
+ priority="P3"
621
+ ;;
622
+ esac
623
+
624
+ # Elevate if high impact
625
+ if [[ "$impact" == "high" ]]; then
626
+ case "$priority" in
627
+ P3) priority="P2" ;;
628
+ P2) priority="P1" ;;
629
+ P1) priority="P0" ;;
630
+ esac
631
+ fi
632
+
633
+ echo "$priority"
634
+ }
635
+
636
+ # ─── Confidence Scoring ──────────────────────────────────────────────────
637
+ discovery_score_confidence() {
638
+ local pattern_occurrences="${1:-1}"
639
+ local fix_success_rate="${2:-50}"
640
+ local semantic_relevance="${3:-50}"
641
+
642
+ # Confidence = (occurrences * 10) + (success_rate * 0.4) + (relevance * 0.3)
643
+ # Capped at 100
644
+ local confidence=0
645
+
646
+ # Base score from occurrences (max 50 points: 1 occ=10, 5+ occ=50)
647
+ local occ_score=$((pattern_occurrences * 10))
648
+ [[ "$occ_score" -gt 50 ]] && occ_score=50
649
+ confidence=$((confidence + occ_score))
650
+
651
+ # Success rate contribution (max 40 points)
652
+ local success_score=$((fix_success_rate * 4 / 10))
653
+ [[ "$success_score" -gt 40 ]] && success_score=40
654
+ confidence=$((confidence + success_score))
655
+
656
+ # Semantic relevance contribution (max 10 points)
657
+ local relevance_score=$((semantic_relevance * 1 / 10))
658
+ [[ "$relevance_score" -gt 10 ]] && relevance_score=10
659
+ confidence=$((confidence + relevance_score))
660
+
661
+ [[ "$confidence" -gt 100 ]] && confidence=100
662
+
663
+ echo "$confidence"
664
+ }
665
+
666
+ # ─── Consumption Tracking ───────────────────────────────────────────────
667
+ get_consumption_file() {
668
+ local discovery_id="$1"
669
+ echo "${DISCOVERIES_DIR}/consumption-${discovery_id}.json"
670
+ }
671
+
672
+ discovery_acknowledge() {
673
+ local discovery_id="$1"
674
+ local pipeline_id="${SHIPWRIGHT_PIPELINE_ID:-unknown}"
675
+ local helpful="${2:-true}"
676
+
677
+ ensure_discoveries_dir
678
+
679
+ local consumption_file
680
+ consumption_file=$(get_consumption_file "$discovery_id")
681
+
682
+ # Initialize or append to consumption tracking
683
+ if [[ ! -f "$consumption_file" ]]; then
684
+ echo '{"discovery_id":"'"$discovery_id"'","consumed_by":[],"consumption_count":0,"helpful_count":0}' > "$consumption_file"
685
+ fi
686
+
687
+ # Update consumption data
688
+ local tmp_file
689
+ tmp_file=$(mktemp)
690
+
691
+ jq \
692
+ --arg pipeline_id "$pipeline_id" \
693
+ --arg ts "$(now_iso)" \
694
+ --arg helpful "$helpful" \
695
+ '.consumed_by += [{"pipeline_id": $pipeline_id, "ts": $ts, "helpful": ($helpful == "true")}] |
696
+ .consumption_count += 1 |
697
+ .helpful_count += (if ($helpful == "true") then 1 else 0 end)' \
698
+ "$consumption_file" > "$tmp_file"
699
+
700
+ mv "$tmp_file" "$consumption_file"
701
+ emit_event "discovery.consumed" "discovery_id=$discovery_id" "pipeline_id=$pipeline_id" "helpful=$helpful"
702
+ }
703
+
704
+ discovery_consumption_stats() {
705
+ local discovery_id="$1"
706
+
707
+ ensure_discoveries_dir
708
+
709
+ local consumption_file
710
+ consumption_file=$(get_consumption_file "$discovery_id")
711
+
712
+ if [[ ! -f "$consumption_file" ]]; then
713
+ echo '{"consumption_count":0,"helpfulness_rate":0.0}'
714
+ return 0
715
+ fi
716
+
717
+ jq '{
718
+ consumption_count: .consumption_count,
719
+ helpfulness_rate: (if .consumption_count > 0 then (.helpful_count / .consumption_count) else 0 end),
720
+ helpful_count: .helpful_count,
721
+ consumers: (.consumed_by | length)
722
+ }' "$consumption_file" 2>/dev/null || echo '{"consumption_count":0,"helpfulness_rate":0.0}'
723
+ }
724
+
725
+ # ─── Memory Promotion ───────────────────────────────────────────────────
726
+ discovery_promote_to_memory() {
727
+ local discovery_id="$1"
728
+ local category="${2:-}"
729
+ local discovery_text="${3:-}"
730
+
731
+ ensure_discoveries_dir
732
+
733
+ local consumption_file
734
+ consumption_file=$(get_consumption_file "$discovery_id")
735
+
736
+ if [[ ! -f "$consumption_file" ]]; then
737
+ warn "No consumption data for discovery: $discovery_id"
738
+ return 1
739
+ fi
740
+
741
+ # Check if consumed 3+ times and helpful
742
+ local stats
743
+ stats=$(jq '{consumed: .consumption_count >= 3, helpful: (.helpful_count / .consumption_count > 0.5)}' "$consumption_file" 2>/dev/null || echo "{}")
744
+
745
+ local consumed helpful
746
+ consumed=$(echo "$stats" | jq -r '.consumed // false' 2>/dev/null)
747
+ helpful=$(echo "$stats" | jq -r '.helpful // false' 2>/dev/null)
748
+
749
+ if [[ "$consumed" != "true" || "$helpful" != "true" ]]; then
750
+ info "Discovery not yet ready for memory promotion (consumed=${consumed}, helpful=${helpful})"
751
+ return 1
752
+ fi
753
+
754
+ # Manually write to memory directory (memory system may not be sourced)
755
+ local mem_root="${HOME}/.shipwright/memory"
756
+ mkdir -p "$mem_root"
757
+
758
+ local failures_file="$mem_root/failures.json"
759
+ local tmp_file
760
+
761
+ # Build the memory entry
762
+ local memory_entry
763
+ memory_entry=$(jq -cn \
764
+ --arg pattern "$category" \
765
+ --arg root_cause "$discovery_text" \
766
+ --arg fix "Applied based on cross-pipeline discovery: $discovery_id" \
767
+ --arg ts "$(now_iso)" \
768
+ '{pattern: $pattern, root_cause: $root_cause, fix: $fix, fix_effectiveness_rate: 80, discovered_at: $ts}')
769
+
770
+ # Append to failures.json
771
+ if [[ -f "$failures_file" ]]; then
772
+ tmp_file=$(mktemp)
773
+ jq '.failures += ['"$memory_entry"']' "$failures_file" > "$tmp_file"
774
+ mv "$tmp_file" "$failures_file"
775
+ else
776
+ echo "{\"failures\":[${memory_entry}]}" > "$failures_file"
777
+ fi
778
+
779
+ emit_event "discovery.promoted" "discovery_id=$discovery_id" "category=$category"
780
+ success "Promoted discovery to persistent memory: $discovery_id"
781
+ }
782
+
452
783
  # show_help: display usage
453
784
  show_help() {
454
785
  echo -e "${CYAN}${BOLD}shipwright discovery${RESET} — Cross-Pipeline Real-Time Learning"
@@ -472,6 +803,18 @@ show_help() {
472
803
  echo -e " ${CYAN}status${RESET}"
473
804
  echo -e " Show discovery channel statistics and health"
474
805
  echo ""
806
+ echo -e " ${CYAN}acknowledge${RESET} <discovery-id> [helpful]"
807
+ echo -e " Track consumption of a discovery (helpful=true/false)"
808
+ echo ""
809
+ echo -e " ${CYAN}prioritize${RESET} <severity> [impact]"
810
+ echo -e " Assign P0-P3 priority to a discovery"
811
+ echo ""
812
+ echo -e " ${CYAN}score${RESET} <occurrences> [success_rate] [relevance]"
813
+ echo -e " Score confidence for a discovery (0-100)"
814
+ echo ""
815
+ echo -e " ${CYAN}promote${RESET} <discovery-id> <category> <text>"
816
+ echo -e " Promote discovery to persistent memory (if 3+ consumptions)"
817
+ echo ""
475
818
  echo -e " ${CYAN}help${RESET}"
476
819
  echo -e " Show this help message"
477
820
  echo ""
@@ -482,7 +825,9 @@ show_help() {
482
825
  echo -e " ${DIM}shipwright discovery broadcast \"auth-fix\" \"src/auth/*.ts\" \"JWT validation failure resolved\" \"Added claim verification\"${RESET}"
483
826
  echo -e " ${DIM}shipwright discovery query \"src/**/*.js,src/**/*.ts\" 5${RESET}"
484
827
  echo -e " ${DIM}shipwright discovery inject \"src/api/**\" 2>&1 | xargs -I {} echo \"Learning: {}\"${RESET}"
485
- echo -e " ${DIM}shipwright discovery clean 172800${RESET} # Remove discoveries older than 48h"
828
+ echo -e " ${DIM}shipwright discovery acknowledge abc123 true${RESET}"
829
+ echo -e " ${DIM}shipwright discovery prioritize security high${RESET}"
830
+ echo -e " ${DIM}shipwright discovery score 5 80 75${RESET}"
486
831
  echo -e " ${DIM}shipwright discovery status${RESET}"
487
832
  }
488
833
 
@@ -520,6 +865,34 @@ main() {
520
865
  status)
521
866
  show_status
522
867
  ;;
868
+ acknowledge)
869
+ [[ $# -lt 1 ]] && {
870
+ error "acknowledge requires: discovery-id [helpful]"
871
+ exit 1
872
+ }
873
+ discovery_acknowledge "$1" "${2:-true}"
874
+ ;;
875
+ prioritize)
876
+ [[ $# -lt 1 ]] && {
877
+ error "prioritize requires: severity [impact]"
878
+ exit 1
879
+ }
880
+ discovery_prioritize "$1" "${2:-normal}"
881
+ ;;
882
+ score)
883
+ [[ $# -lt 1 ]] && {
884
+ error "score requires: occurrences [success_rate] [relevance]"
885
+ exit 1
886
+ }
887
+ discovery_score_confidence "$1" "${2:-50}" "${3:-50}"
888
+ ;;
889
+ promote)
890
+ [[ $# -lt 3 ]] && {
891
+ error "promote requires: discovery-id, category, text"
892
+ exit 1
893
+ }
894
+ discovery_promote_to_memory "$1" "$2" "$3"
895
+ ;;
523
896
  help|--help|-h)
524
897
  show_help
525
898
  ;;
@@ -6,7 +6,8 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.1.0"
9
+ # shellcheck disable=SC2034
10
+ VERSION="3.3.0"
10
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
13
 
@@ -27,6 +28,7 @@ fi
27
28
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
28
29
  emit_event() {
29
30
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
31
+ # shellcheck disable=SC2155
30
32
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
31
33
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
32
34
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
@@ -673,6 +675,7 @@ cmd_report() {
673
675
 
674
676
  # JSON output if requested
675
677
  if [[ "$format" == "--json" || "$format" == "json" ]]; then
678
+ # shellcheck disable=SC2155
676
679
  local report_file="${FLEET_REPORT_DIR}/report-$(date +%Y%m%d-%H%M%S).json"
677
680
  jq -n \
678
681
  --arg ts "$(now_iso)" \
@@ -6,7 +6,8 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="3.1.0"
9
+ # shellcheck disable=SC2034
10
+ VERSION="3.3.0"
10
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
13
 
@@ -29,6 +30,7 @@ fi
29
30
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
31
  emit_event() {
31
32
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
33
+ # shellcheck disable=SC2155
32
34
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
35
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
36
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
@@ -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="3.1.0"
9
+ VERSION="3.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -31,6 +31,7 @@ fi
31
31
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
32
32
  emit_event() {
33
33
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
34
+ # shellcheck disable=SC2155
34
35
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
35
36
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
36
37
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"