shipwright-cli 3.2.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 (279) 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 +4 -4
  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/dashboard/middleware/auth.ts +134 -0
  17. package/dashboard/middleware/constants.ts +21 -0
  18. package/dashboard/public/index.html +2 -6
  19. package/dashboard/public/styles.css +100 -97
  20. package/dashboard/routes/auth.ts +38 -0
  21. package/dashboard/server.ts +66 -25
  22. package/dashboard/services/config.ts +26 -0
  23. package/dashboard/services/db.ts +118 -0
  24. package/dashboard/src/canvas/pixel-agent.ts +298 -0
  25. package/dashboard/src/canvas/pixel-sprites.ts +440 -0
  26. package/dashboard/src/canvas/shipyard-effects.ts +367 -0
  27. package/dashboard/src/canvas/shipyard-scene.ts +616 -0
  28. package/dashboard/src/canvas/submarine-layout.ts +267 -0
  29. package/dashboard/src/components/header.ts +8 -7
  30. package/dashboard/src/core/router.ts +1 -0
  31. package/dashboard/src/design/submarine-theme.ts +253 -0
  32. package/dashboard/src/main.ts +2 -0
  33. package/dashboard/src/types/api.ts +2 -1
  34. package/dashboard/src/views/activity.ts +2 -1
  35. package/dashboard/src/views/shipyard.ts +39 -0
  36. package/dashboard/types/index.ts +166 -0
  37. package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
  38. package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
  39. package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
  40. package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
  41. package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
  42. package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
  43. package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
  44. package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
  45. package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
  46. package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
  47. package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
  48. package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
  49. package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
  50. package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
  51. package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
  52. package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
  53. package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
  54. package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
  55. package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
  56. package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
  57. package/docs/research/RESEARCH_INDEX.md +439 -0
  58. package/docs/research/RESEARCH_SOURCES.md +440 -0
  59. package/docs/research/RESEARCH_SUMMARY.txt +275 -0
  60. package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
  61. package/package.json +2 -2
  62. package/scripts/lib/adaptive-model.sh +427 -0
  63. package/scripts/lib/adaptive-timeout.sh +316 -0
  64. package/scripts/lib/audit-trail.sh +309 -0
  65. package/scripts/lib/auto-recovery.sh +471 -0
  66. package/scripts/lib/bandit-selector.sh +431 -0
  67. package/scripts/lib/bootstrap.sh +104 -2
  68. package/scripts/lib/causal-graph.sh +455 -0
  69. package/scripts/lib/compat.sh +126 -0
  70. package/scripts/lib/compound-audit.sh +337 -0
  71. package/scripts/lib/constitutional.sh +454 -0
  72. package/scripts/lib/context-budget.sh +359 -0
  73. package/scripts/lib/convergence.sh +594 -0
  74. package/scripts/lib/cost-optimizer.sh +634 -0
  75. package/scripts/lib/daemon-adaptive.sh +10 -0
  76. package/scripts/lib/daemon-dispatch.sh +106 -17
  77. package/scripts/lib/daemon-failure.sh +34 -4
  78. package/scripts/lib/daemon-patrol.sh +23 -2
  79. package/scripts/lib/daemon-poll-github.sh +361 -0
  80. package/scripts/lib/daemon-poll-health.sh +299 -0
  81. package/scripts/lib/daemon-poll.sh +27 -611
  82. package/scripts/lib/daemon-state.sh +112 -66
  83. package/scripts/lib/daemon-triage.sh +10 -0
  84. package/scripts/lib/dod-scorecard.sh +442 -0
  85. package/scripts/lib/error-actionability.sh +300 -0
  86. package/scripts/lib/formal-spec.sh +461 -0
  87. package/scripts/lib/helpers.sh +177 -4
  88. package/scripts/lib/intent-analysis.sh +409 -0
  89. package/scripts/lib/loop-convergence.sh +350 -0
  90. package/scripts/lib/loop-iteration.sh +682 -0
  91. package/scripts/lib/loop-progress.sh +48 -0
  92. package/scripts/lib/loop-restart.sh +185 -0
  93. package/scripts/lib/memory-effectiveness.sh +506 -0
  94. package/scripts/lib/mutation-executor.sh +352 -0
  95. package/scripts/lib/outcome-feedback.sh +521 -0
  96. package/scripts/lib/pipeline-cli.sh +336 -0
  97. package/scripts/lib/pipeline-commands.sh +1216 -0
  98. package/scripts/lib/pipeline-detection.sh +100 -2
  99. package/scripts/lib/pipeline-execution.sh +897 -0
  100. package/scripts/lib/pipeline-github.sh +28 -3
  101. package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
  102. package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
  103. package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
  104. package/scripts/lib/pipeline-intelligence.sh +100 -1136
  105. package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
  106. package/scripts/lib/pipeline-quality-checks.sh +17 -715
  107. package/scripts/lib/pipeline-quality-gates.sh +563 -0
  108. package/scripts/lib/pipeline-stages-build.sh +730 -0
  109. package/scripts/lib/pipeline-stages-delivery.sh +965 -0
  110. package/scripts/lib/pipeline-stages-intake.sh +1133 -0
  111. package/scripts/lib/pipeline-stages-monitor.sh +407 -0
  112. package/scripts/lib/pipeline-stages-review.sh +1022 -0
  113. package/scripts/lib/pipeline-stages.sh +59 -2929
  114. package/scripts/lib/pipeline-state.sh +36 -5
  115. package/scripts/lib/pipeline-util.sh +487 -0
  116. package/scripts/lib/policy-learner.sh +438 -0
  117. package/scripts/lib/process-reward.sh +493 -0
  118. package/scripts/lib/project-detect.sh +649 -0
  119. package/scripts/lib/quality-profile.sh +334 -0
  120. package/scripts/lib/recruit-commands.sh +885 -0
  121. package/scripts/lib/recruit-learning.sh +739 -0
  122. package/scripts/lib/recruit-roles.sh +648 -0
  123. package/scripts/lib/reward-aggregator.sh +458 -0
  124. package/scripts/lib/rl-optimizer.sh +362 -0
  125. package/scripts/lib/root-cause.sh +427 -0
  126. package/scripts/lib/scope-enforcement.sh +445 -0
  127. package/scripts/lib/session-restart.sh +493 -0
  128. package/scripts/lib/skill-memory.sh +300 -0
  129. package/scripts/lib/skill-registry.sh +775 -0
  130. package/scripts/lib/spec-driven.sh +476 -0
  131. package/scripts/lib/test-helpers.sh +18 -7
  132. package/scripts/lib/test-holdout.sh +429 -0
  133. package/scripts/lib/test-optimizer.sh +511 -0
  134. package/scripts/shipwright-file-suggest.sh +45 -0
  135. package/scripts/skills/adversarial-quality.md +61 -0
  136. package/scripts/skills/api-design.md +44 -0
  137. package/scripts/skills/architecture-design.md +50 -0
  138. package/scripts/skills/brainstorming.md +43 -0
  139. package/scripts/skills/data-pipeline.md +44 -0
  140. package/scripts/skills/deploy-safety.md +64 -0
  141. package/scripts/skills/documentation.md +38 -0
  142. package/scripts/skills/frontend-design.md +45 -0
  143. package/scripts/skills/generated/.gitkeep +0 -0
  144. package/scripts/skills/generated/_refinements/.gitkeep +0 -0
  145. package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
  146. package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
  147. package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
  148. package/scripts/skills/generated/cli-version-management.md +29 -0
  149. package/scripts/skills/generated/collection-system-validation.md +99 -0
  150. package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
  151. package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
  152. package/scripts/skills/generated/test-parallelization-detection.md +65 -0
  153. package/scripts/skills/observability.md +79 -0
  154. package/scripts/skills/performance.md +48 -0
  155. package/scripts/skills/pr-quality.md +49 -0
  156. package/scripts/skills/product-thinking.md +43 -0
  157. package/scripts/skills/security-audit.md +49 -0
  158. package/scripts/skills/systematic-debugging.md +40 -0
  159. package/scripts/skills/testing-strategy.md +47 -0
  160. package/scripts/skills/two-stage-review.md +52 -0
  161. package/scripts/skills/validation-thoroughness.md +55 -0
  162. package/scripts/sw +9 -3
  163. package/scripts/sw-activity.sh +9 -2
  164. package/scripts/sw-adaptive.sh +2 -1
  165. package/scripts/sw-adversarial.sh +2 -1
  166. package/scripts/sw-architecture-enforcer.sh +3 -1
  167. package/scripts/sw-auth.sh +12 -2
  168. package/scripts/sw-autonomous.sh +5 -1
  169. package/scripts/sw-changelog.sh +4 -1
  170. package/scripts/sw-checkpoint.sh +2 -1
  171. package/scripts/sw-ci.sh +5 -1
  172. package/scripts/sw-cleanup.sh +4 -26
  173. package/scripts/sw-code-review.sh +10 -4
  174. package/scripts/sw-connect.sh +2 -1
  175. package/scripts/sw-context.sh +2 -1
  176. package/scripts/sw-cost.sh +48 -3
  177. package/scripts/sw-daemon.sh +66 -9
  178. package/scripts/sw-dashboard.sh +3 -1
  179. package/scripts/sw-db.sh +59 -16
  180. package/scripts/sw-decide.sh +8 -2
  181. package/scripts/sw-decompose.sh +360 -17
  182. package/scripts/sw-deps.sh +4 -1
  183. package/scripts/sw-developer-simulation.sh +4 -1
  184. package/scripts/sw-discovery.sh +325 -2
  185. package/scripts/sw-doc-fleet.sh +4 -1
  186. package/scripts/sw-docs-agent.sh +3 -1
  187. package/scripts/sw-docs.sh +2 -1
  188. package/scripts/sw-doctor.sh +453 -2
  189. package/scripts/sw-dora.sh +4 -1
  190. package/scripts/sw-durable.sh +4 -3
  191. package/scripts/sw-e2e-orchestrator.sh +17 -16
  192. package/scripts/sw-eventbus.sh +7 -1
  193. package/scripts/sw-evidence.sh +364 -12
  194. package/scripts/sw-feedback.sh +550 -9
  195. package/scripts/sw-fix.sh +20 -1
  196. package/scripts/sw-fleet-discover.sh +6 -2
  197. package/scripts/sw-fleet-viz.sh +4 -1
  198. package/scripts/sw-fleet.sh +5 -1
  199. package/scripts/sw-github-app.sh +16 -3
  200. package/scripts/sw-github-checks.sh +3 -2
  201. package/scripts/sw-github-deploy.sh +3 -2
  202. package/scripts/sw-github-graphql.sh +18 -7
  203. package/scripts/sw-guild.sh +5 -1
  204. package/scripts/sw-heartbeat.sh +5 -30
  205. package/scripts/sw-hello.sh +67 -0
  206. package/scripts/sw-hygiene.sh +6 -1
  207. package/scripts/sw-incident.sh +265 -1
  208. package/scripts/sw-init.sh +18 -2
  209. package/scripts/sw-instrument.sh +10 -2
  210. package/scripts/sw-intelligence.sh +42 -6
  211. package/scripts/sw-jira.sh +5 -1
  212. package/scripts/sw-launchd.sh +2 -1
  213. package/scripts/sw-linear.sh +4 -1
  214. package/scripts/sw-logs.sh +4 -1
  215. package/scripts/sw-loop.sh +432 -1128
  216. package/scripts/sw-memory.sh +356 -2
  217. package/scripts/sw-mission-control.sh +6 -1
  218. package/scripts/sw-model-router.sh +481 -26
  219. package/scripts/sw-otel.sh +13 -4
  220. package/scripts/sw-oversight.sh +14 -5
  221. package/scripts/sw-patrol-meta.sh +334 -0
  222. package/scripts/sw-pipeline-composer.sh +5 -1
  223. package/scripts/sw-pipeline-vitals.sh +2 -1
  224. package/scripts/sw-pipeline.sh +53 -2664
  225. package/scripts/sw-pm.sh +12 -5
  226. package/scripts/sw-pr-lifecycle.sh +2 -1
  227. package/scripts/sw-predictive.sh +7 -1
  228. package/scripts/sw-prep.sh +185 -2
  229. package/scripts/sw-ps.sh +5 -25
  230. package/scripts/sw-public-dashboard.sh +15 -3
  231. package/scripts/sw-quality.sh +2 -1
  232. package/scripts/sw-reaper.sh +8 -25
  233. package/scripts/sw-recruit.sh +156 -2303
  234. package/scripts/sw-regression.sh +19 -12
  235. package/scripts/sw-release-manager.sh +3 -1
  236. package/scripts/sw-release.sh +4 -1
  237. package/scripts/sw-remote.sh +3 -1
  238. package/scripts/sw-replay.sh +7 -1
  239. package/scripts/sw-retro.sh +158 -1
  240. package/scripts/sw-review-rerun.sh +3 -1
  241. package/scripts/sw-scale.sh +10 -3
  242. package/scripts/sw-security-audit.sh +6 -1
  243. package/scripts/sw-self-optimize.sh +6 -3
  244. package/scripts/sw-session.sh +9 -3
  245. package/scripts/sw-setup.sh +3 -1
  246. package/scripts/sw-stall-detector.sh +406 -0
  247. package/scripts/sw-standup.sh +15 -7
  248. package/scripts/sw-status.sh +3 -1
  249. package/scripts/sw-strategic.sh +4 -1
  250. package/scripts/sw-stream.sh +7 -1
  251. package/scripts/sw-swarm.sh +18 -6
  252. package/scripts/sw-team-stages.sh +13 -6
  253. package/scripts/sw-templates.sh +5 -29
  254. package/scripts/sw-testgen.sh +7 -1
  255. package/scripts/sw-tmux-pipeline.sh +4 -1
  256. package/scripts/sw-tmux-role-color.sh +2 -0
  257. package/scripts/sw-tmux-status.sh +1 -1
  258. package/scripts/sw-tmux.sh +3 -1
  259. package/scripts/sw-trace.sh +3 -1
  260. package/scripts/sw-tracker-github.sh +3 -0
  261. package/scripts/sw-tracker-jira.sh +3 -0
  262. package/scripts/sw-tracker-linear.sh +3 -0
  263. package/scripts/sw-tracker.sh +3 -1
  264. package/scripts/sw-triage.sh +2 -1
  265. package/scripts/sw-upgrade.sh +3 -1
  266. package/scripts/sw-ux.sh +5 -2
  267. package/scripts/sw-webhook.sh +3 -1
  268. package/scripts/sw-widgets.sh +3 -1
  269. package/scripts/sw-worktree.sh +15 -3
  270. package/scripts/test-skill-injection.sh +1233 -0
  271. package/templates/pipelines/autonomous.json +27 -3
  272. package/templates/pipelines/cost-aware.json +34 -8
  273. package/templates/pipelines/deployed.json +12 -0
  274. package/templates/pipelines/enterprise.json +12 -0
  275. package/templates/pipelines/fast.json +6 -0
  276. package/templates/pipelines/full.json +27 -3
  277. package/templates/pipelines/hotfix.json +6 -0
  278. package/templates/pipelines/standard.json +12 -0
  279. package/templates/pipelines/tdd.json +12 -0
@@ -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.2.0"
9
+ VERSION="3.3.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
@@ -29,7 +29,8 @@ fi
29
29
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
30
  emit_event() {
31
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\""
32
+ local payload
33
+ payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
34
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
35
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
36
  }
@@ -42,6 +43,10 @@ fi
42
43
  # shellcheck source=sw-intelligence.sh
43
44
  [[ -f "$SCRIPT_DIR/sw-intelligence.sh" ]] && source "$SCRIPT_DIR/sw-intelligence.sh"
44
45
 
46
+ # ─── Memory Effectiveness Tracker ──────────────────────────────────────────
47
+ # shellcheck source=lib/memory-effectiveness.sh
48
+ [[ -f "$SCRIPT_DIR/lib/memory-effectiveness.sh" ]] && source "$SCRIPT_DIR/lib/memory-effectiveness.sh"
49
+
45
50
  # ─── Memory Storage Paths ──────────────────────────────────────────────────
46
51
  MEMORY_ROOT="${HOME}/.shipwright/memory"
47
52
  GLOBAL_MEMORY="${MEMORY_ROOT}/global.json"
@@ -217,6 +222,7 @@ memory_semantic_search() {
217
222
 
218
223
  # Inject relevant memories into agent prompts (goal-based)
219
224
  memory_inject_goal_context() {
225
+ # shellcheck disable=SC2034
220
226
  local goal="$1" repo_hash="${2:-}" max_tokens="${3:-2000}"
221
227
 
222
228
  local memories
@@ -330,6 +336,7 @@ memory_capture_pipeline() {
330
336
  # Record review patterns to global memory for cross-repo learning
331
337
  local tmp_global
332
338
  tmp_global=$(mktemp)
339
+ # shellcheck disable=SC2064
333
340
  trap "rm -f '$tmp_global'" RETURN
334
341
  jq --arg repo "$repo" \
335
342
  --arg ts "$captured_at" \
@@ -395,6 +402,7 @@ memory_capture_failure() {
395
402
  fi
396
403
  local tmp_file
397
404
  tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
405
+ # shellcheck disable=SC2064
398
406
  trap "rm -f '$tmp_file'" EXIT
399
407
 
400
408
  if [[ "$existing_idx" != "-1" && "$existing_idx" != "null" ]]; then
@@ -471,6 +479,7 @@ memory_record_fix_outcome() {
471
479
  fi
472
480
  local tmp_file
473
481
  tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
482
+ # shellcheck disable=SC2064
474
483
  trap "rm -f '$tmp_file'" EXIT
475
484
 
476
485
  jq --argjson idx "$match_idx" \
@@ -637,6 +646,7 @@ _memory_aggregate_global() {
637
646
  # Add to global, cap at 100 entries
638
647
  local tmp_global
639
648
  tmp_global=$(mktemp "${global_file}.tmp.XXXXXX")
649
+ # shellcheck disable=SC2064
640
650
  trap "rm -f '$tmp_global'" RETURN
641
651
  jq --arg p "$pattern" \
642
652
  --arg ts "$(now_iso)" \
@@ -789,6 +799,7 @@ Return JSON only, no markdown fences, no explanation."
789
799
  # Update the most recent failure entry with root_cause, fix, category
790
800
  local tmp_file
791
801
  tmp_file=$(mktemp)
802
+ # shellcheck disable=SC2064
792
803
  trap "rm -f '$tmp_file'" RETURN
793
804
  jq --arg rc "$root_cause" \
794
805
  --arg fix "$fix" \
@@ -819,6 +830,7 @@ memory_capture_pattern() {
819
830
 
820
831
  local tmp_file
821
832
  tmp_file=$(mktemp)
833
+ # shellcheck disable=SC2064
822
834
  trap "rm -f '$tmp_file'" RETURN
823
835
 
824
836
  case "$pattern_type" in
@@ -1337,6 +1349,7 @@ memory_update_metrics() {
1337
1349
  # Update baseline using atomic write
1338
1350
  local tmp_file
1339
1351
  tmp_file=$(mktemp)
1352
+ # shellcheck disable=SC2064
1340
1353
  trap "rm -f '$tmp_file'" RETURN
1341
1354
  jq --arg m "$metric_name" \
1342
1355
  --argjson v "$value" \
@@ -1361,6 +1374,7 @@ memory_capture_decision() {
1361
1374
 
1362
1375
  local tmp_file
1363
1376
  tmp_file=$(mktemp)
1377
+ # shellcheck disable=SC2064
1364
1378
  trap "rm -f '$tmp_file'" RETURN
1365
1379
  jq --arg type "$dec_type" \
1366
1380
  --arg summary "$summary" \
@@ -1702,6 +1716,7 @@ memory_import() {
1702
1716
  # Extract and write each section
1703
1717
  local tmp_file
1704
1718
  tmp_file=$(mktemp)
1719
+ # shellcheck disable=SC2064
1705
1720
  trap "rm -f '$tmp_file'" RETURN
1706
1721
 
1707
1722
  jq '.patterns // {}' "$import_file" > "$tmp_file" && mv "$tmp_file" "$mem_dir/patterns.json"
@@ -1787,6 +1802,219 @@ memory_stats() {
1787
1802
  echo ""
1788
1803
  }
1789
1804
 
1805
+ # ─── A/B Testing Framework ─────────────────────────────────────────────────
1806
+ # Test memory system effectiveness by randomly assigning control vs treatment.
1807
+ # - Control: pipeline runs without memory injection
1808
+ # - Treatment: pipeline runs with memory injection
1809
+ # Emits events to track metrics: iterations, cost, test_failures, completion_status
1810
+
1811
+ AB_RESULTS_DIR="${HOME}/.shipwright/memory"
1812
+ AB_RESULTS_FILE="${AB_RESULTS_DIR}/ab-results.jsonl"
1813
+
1814
+ # Assign control or treatment for this pipeline run
1815
+ # Returns: "control" or "treatment"
1816
+ memory_ab_assign_group() {
1817
+ local ab_ratio="${1:-0.2}" # Read from daemon-config intelligence.ab_test_ratio
1818
+
1819
+ # Validate ratio is between 0 and 1
1820
+ if ! echo "$ab_ratio" | grep -qE '^0(\.[0-9]+)?$|^1(\.0+)?$'; then
1821
+ ab_ratio="0.2"
1822
+ fi
1823
+
1824
+ # Generate random 0-100
1825
+ local rand=$((RANDOM % 100))
1826
+ local threshold=$(echo "$ab_ratio * 100" | bc 2>/dev/null || echo "20")
1827
+ threshold=${threshold%.*} # Remove decimal
1828
+
1829
+ if [[ "$rand" -lt "$threshold" ]]; then
1830
+ echo "control"
1831
+ else
1832
+ echo "treatment"
1833
+ fi
1834
+ }
1835
+
1836
+ # Record A/B test assignment at pipeline start
1837
+ # $1: pipeline_id
1838
+ # $2: group (control|treatment)
1839
+ memory_ab_record_assignment() {
1840
+ local pipeline_id="$1"
1841
+ local group="${2:-}"
1842
+
1843
+ [[ -z "$pipeline_id" || -z "$group" ]] && return 1
1844
+
1845
+ # Emit event for tracking
1846
+ emit_event "memory.ab_assigned" \
1847
+ "pipeline_id=$pipeline_id" \
1848
+ "group=$group" \
1849
+ "timestamp=$(now_iso)"
1850
+
1851
+ return 0
1852
+ }
1853
+
1854
+ # Record A/B test result after pipeline completion
1855
+ # $1: pipeline_id
1856
+ # $2: group (control|treatment)
1857
+ # $3: iterations (number of build iterations)
1858
+ # $4: cost (estimated token cost)
1859
+ # $5: test_failures (number of test failures)
1860
+ # $6: completion_status (success|failure)
1861
+ memory_ab_record_result() {
1862
+ local pipeline_id="$1"
1863
+ local group="$2"
1864
+ local iterations="$3"
1865
+ local cost="$4"
1866
+ local test_failures="$5"
1867
+ local completion_status="$6"
1868
+
1869
+ [[ -z "$pipeline_id" || -z "$group" ]] && return 1
1870
+
1871
+ mkdir -p "$AB_RESULTS_DIR"
1872
+
1873
+ # Record result as JSONL
1874
+ local result_json
1875
+ result_json=$(jq -n \
1876
+ --arg pipeline_id "$pipeline_id" \
1877
+ --arg group "$group" \
1878
+ --arg timestamp "$(now_iso)" \
1879
+ --arg iterations "$iterations" \
1880
+ --arg cost "$cost" \
1881
+ --arg test_failures "$test_failures" \
1882
+ --arg completion_status "$completion_status" \
1883
+ '{
1884
+ pipeline_id: $pipeline_id,
1885
+ group: $group,
1886
+ timestamp: $timestamp,
1887
+ iterations: ($iterations | tonumber? // 0),
1888
+ cost: ($cost | tonumber? // 0),
1889
+ test_failures: ($test_failures | tonumber? // 0),
1890
+ completion_status: $completion_status
1891
+ }')
1892
+
1893
+ echo "$result_json" >> "$AB_RESULTS_FILE"
1894
+
1895
+ # Emit event
1896
+ emit_event "memory.ab_result" \
1897
+ "pipeline_id=$pipeline_id" \
1898
+ "group=$group" \
1899
+ "iterations=$iterations" \
1900
+ "cost=$cost" \
1901
+ "test_failures=$test_failures" \
1902
+ "completion_status=$completion_status"
1903
+
1904
+ return 0
1905
+ }
1906
+
1907
+ # Generate A/B test report comparing control vs treatment
1908
+ cmd_memory_ab_report() {
1909
+ if [[ ! -f "$AB_RESULTS_FILE" ]]; then
1910
+ warn "No A/B test results found at $AB_RESULTS_FILE"
1911
+ return 1
1912
+ fi
1913
+
1914
+ if ! command -v jq >/dev/null 2>&1; then
1915
+ error "jq required for A/B report generation"
1916
+ return 1
1917
+ fi
1918
+
1919
+ info "Memory A/B Test Report"
1920
+ echo ""
1921
+
1922
+ local control_count treatment_count
1923
+ control_count=$(grep -c '"control"' "$AB_RESULTS_FILE" 2>/dev/null || echo "0")
1924
+ treatment_count=$(grep -c '"treatment"' "$AB_RESULTS_FILE" 2>/dev/null || echo "0")
1925
+
1926
+ echo -e "${BOLD}Sample Sizes${RESET}"
1927
+ printf " Control: %3d pipelines\n" "$control_count"
1928
+ printf " Treatment: %3d pipelines\n" "$treatment_count"
1929
+ echo ""
1930
+
1931
+ # Calculate metrics for control group
1932
+ local control_data
1933
+ control_data=$(grep '"control"' "$AB_RESULTS_FILE" 2>/dev/null | jq -s '
1934
+ if length == 0 then
1935
+ {count: 0, avg_iterations: 0, avg_cost: 0, success_rate: 0}
1936
+ else
1937
+ {
1938
+ count: length,
1939
+ avg_iterations: ([.[].iterations // 0] | add / length | floor),
1940
+ avg_cost: ([.[].cost // 0] | add / length | floor),
1941
+ success_rate: (([.[] | select(.completion_status == "success")] | length) / length * 100 | floor)
1942
+ }
1943
+ end
1944
+ ' || echo '{"count": 0, "avg_iterations": 0, "avg_cost": 0, "success_rate": 0}')
1945
+
1946
+ # Calculate metrics for treatment group
1947
+ local treatment_data
1948
+ treatment_data=$(grep '"treatment"' "$AB_RESULTS_FILE" 2>/dev/null | jq -s '
1949
+ if length == 0 then
1950
+ {count: 0, avg_iterations: 0, avg_cost: 0, success_rate: 0}
1951
+ else
1952
+ {
1953
+ count: length,
1954
+ avg_iterations: ([.[].iterations // 0] | add / length | floor),
1955
+ avg_cost: ([.[].cost // 0] | add / length | floor),
1956
+ success_rate: (([.[] | select(.completion_status == "success")] | length) / length * 100 | floor)
1957
+ }
1958
+ end
1959
+ ' || echo '{"count": 0, "avg_iterations": 0, "avg_cost": 0, "success_rate": 0}')
1960
+
1961
+ # Extract values
1962
+ local c_iterations t_iterations c_cost t_cost c_success t_success
1963
+ c_iterations=$(echo "$control_data" | jq -r '.avg_iterations // 0')
1964
+ t_iterations=$(echo "$treatment_data" | jq -r '.avg_iterations // 0')
1965
+ c_cost=$(echo "$control_data" | jq -r '.avg_cost // 0')
1966
+ t_cost=$(echo "$treatment_data" | jq -r '.avg_cost // 0')
1967
+ c_success=$(echo "$control_data" | jq -r '.success_rate // 0')
1968
+ t_success=$(echo "$treatment_data" | jq -r '.success_rate // 0')
1969
+
1970
+ # Calculate deltas
1971
+ local iter_delta cost_delta success_delta
1972
+ iter_delta=$((c_iterations - t_iterations))
1973
+ cost_delta=$((c_cost - t_cost))
1974
+ success_delta=$((t_success - c_success))
1975
+
1976
+ # Direction indicators
1977
+ local iter_dir cost_dir success_dir
1978
+ [[ $iter_delta -gt 0 ]] && iter_dir="${GREEN}↓${RESET}" || iter_dir="${RED}↑${RESET}"
1979
+ [[ $cost_delta -gt 0 ]] && cost_dir="${GREEN}↓${RESET}" || cost_dir="${RED}↑${RESET}"
1980
+ [[ $success_delta -gt 0 ]] && success_dir="${GREEN}↑${RESET}" || success_dir="${RED}↓${RESET}"
1981
+
1982
+ echo -e "${BOLD}Metrics${RESET}"
1983
+ echo ""
1984
+ printf " %-28s %10s %10s %10s\n" "Metric" "Control" "Treatment" "Delta"
1985
+ printf " %s\n" "$(printf '%.0s-' {1..60})"
1986
+ printf " %-28s %10d %10d %10s %s\n" "Avg Iterations" "$c_iterations" "$t_iterations" "$iter_delta" "$iter_dir"
1987
+ printf " %-28s %10d %10d %10s %s\n" "Avg Cost (tokens)" "$c_cost" "$t_cost" "$cost_delta" "$cost_dir"
1988
+ printf " %-28s %10d%% %10d%% %10s %s\n" "Success Rate" "$c_success" "$t_success" "$success_delta" "$success_dir"
1989
+ echo ""
1990
+
1991
+ # Summary
1992
+ echo -e "${BOLD}Summary${RESET}"
1993
+ if [[ $iter_delta -gt 0 ]]; then
1994
+ success "Memory injection reduces iterations by ${iter_delta} (${GREEN}$(echo "scale=1; $iter_delta * 100 / $c_iterations" | bc)% improvement${RESET})"
1995
+ elif [[ $iter_delta -lt 0 ]]; then
1996
+ warn "Memory injection increases iterations by $((iter_delta * -1)) (regression)"
1997
+ else
1998
+ info "No significant difference in iteration count"
1999
+ fi
2000
+
2001
+ if [[ $cost_delta -gt 0 ]]; then
2002
+ success "Memory injection reduces cost by ${cost_delta} tokens (${GREEN}$(echo "scale=1; $cost_delta * 100 / $c_cost" | bc)% savings${RESET})"
2003
+ elif [[ $cost_delta -lt 0 ]]; then
2004
+ warn "Memory injection increases cost by $((cost_delta * -1)) tokens (regression)"
2005
+ fi
2006
+
2007
+ if [[ $success_delta -gt 0 ]]; then
2008
+ success "Memory injection improves success rate by ${success_delta}pp (${GREEN}$(echo "scale=1; $success_delta" | bc)% better${RESET})"
2009
+ elif [[ $success_delta -lt 0 ]]; then
2010
+ warn "Memory injection reduces success rate by $((success_delta * -1))pp (regression)"
2011
+ fi
2012
+
2013
+ echo ""
2014
+ echo -e "${PURPLE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
2015
+ echo ""
2016
+ }
2017
+
1790
2018
  # ─── Help ──────────────────────────────────────────────────────────────────
1791
2019
 
1792
2020
  show_help() {
@@ -1813,6 +2041,7 @@ show_help() {
1813
2041
  echo -e " ${CYAN}decision${RESET} <type> <summary> Record a design decision"
1814
2042
  echo -e " ${CYAN}analyze-failure${RESET} <log> <stage> Analyze failure root cause via AI"
1815
2043
  echo -e " ${CYAN}fix-outcome${RESET} <pattern> <applied> <resolved> Record fix effectiveness"
2044
+ echo -e " ${CYAN}ab-report${RESET} Compare control vs treatment in A/B tests"
1816
2045
  echo ""
1817
2046
  echo -e "${BOLD}EXAMPLES${RESET}"
1818
2047
  echo -e " ${DIM}shipwright memory show${RESET} # View repo memory"
@@ -1824,6 +2053,122 @@ show_help() {
1824
2053
  echo -e " ${DIM}shipwright memory inject build${RESET} # Get context for build stage"
1825
2054
  }
1826
2055
 
2056
+ # ─── Weighted Search (RL integration) ──────────────────────────────────────
2057
+
2058
+ # Search memory with recency + success weighting.
2059
+ # Args: $1=query, $2=memory_dir (optional), $3=max_results (default 5)
2060
+ # Returns JSON array of results with recency_weight applied.
2061
+ memory_search_weighted() {
2062
+ local query="${1:-}"
2063
+ local memory_dir="${2:-}"
2064
+ local max_results="${3:-5}"
2065
+
2066
+ if [[ -z "$memory_dir" ]] && type repo_memory_dir >/dev/null 2>&1; then
2067
+ memory_dir="$(repo_memory_dir)"
2068
+ fi
2069
+ memory_dir="${memory_dir:-$HOME/.shipwright/memory}"
2070
+
2071
+ if [[ ! -d "$memory_dir" ]]; then
2072
+ echo "[]"
2073
+ return 0
2074
+ fi
2075
+
2076
+ # Get base ranked results
2077
+ local base_results
2078
+ base_results="$(memory_ranked_search "$query" "$memory_dir" "$max_results" 2>/dev/null || echo "[]")"
2079
+
2080
+ if [[ "$base_results" == "[]" ]] || [[ -z "$base_results" ]]; then
2081
+ echo "[]"
2082
+ return 0
2083
+ fi
2084
+
2085
+ # Apply recency weighting: boost results from files modified recently
2086
+ local now_epoch
2087
+ now_epoch="$(date +%s)"
2088
+
2089
+ echo "$base_results" | jq --argjson now "$now_epoch" '
2090
+ [.[] | . + {
2091
+ recency_weight: (
2092
+ if .timestamp then
2093
+ (($now - (.timestamp // $now)) / 86400) as $age |
2094
+ if $age <= 7 then 1.5
2095
+ elif $age <= 30 then 1.0
2096
+ elif $age <= 90 then 0.7
2097
+ else 0.4 end
2098
+ else 0.8 end
2099
+ )
2100
+ }] |
2101
+ [.[] | .combined_score = ((.relevance // 50) * .recency_weight)] |
2102
+ sort_by(-.combined_score)
2103
+ ' 2>/dev/null || echo "$base_results"
2104
+ }
2105
+
2106
+ # Reduce weight of memory entries older than threshold.
2107
+ # Args: $1=days_threshold (default 30), $2=memory_dir (optional)
2108
+ memory_decay_old() {
2109
+ local days_threshold="${1:-30}"
2110
+ local memory_dir="${2:-}"
2111
+
2112
+ if [[ -z "$memory_dir" ]] && type repo_memory_dir >/dev/null 2>&1; then
2113
+ memory_dir="$(repo_memory_dir)"
2114
+ fi
2115
+ memory_dir="${memory_dir:-$HOME/.shipwright/memory}"
2116
+
2117
+ if [[ ! -d "$memory_dir" ]]; then
2118
+ return 0
2119
+ fi
2120
+
2121
+ local now_epoch decayed_count
2122
+ now_epoch="$(date +%s)"
2123
+ decayed_count=0
2124
+ local threshold_epoch
2125
+ threshold_epoch=$(( now_epoch - (days_threshold * 86400) ))
2126
+
2127
+ # Process failure patterns file if it exists
2128
+ local failures_file="${memory_dir}/failures.json"
2129
+ if [[ -f "$failures_file" ]]; then
2130
+ local tmp
2131
+ tmp="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/mem-decay-$$.tmp")"
2132
+ jq --argjson threshold "$threshold_epoch" --argjson half "$days_threshold" '
2133
+ if type == "array" then
2134
+ [.[] | if (.timestamp // 0) < $threshold then
2135
+ .weight = ((.weight // 1) * 0.5 | if . < 0.1 then 0.1 else . end)
2136
+ else . end]
2137
+ else . end
2138
+ ' "$failures_file" > "$tmp" 2>/dev/null
2139
+ if [[ -s "$tmp" ]]; then
2140
+ mv "$tmp" "$failures_file"
2141
+ decayed_count=$((decayed_count + 1))
2142
+ else
2143
+ rm -f "$tmp"
2144
+ fi
2145
+ fi
2146
+
2147
+ # Process decisions file if it exists
2148
+ local decisions_file="${memory_dir}/decisions.json"
2149
+ if [[ -f "$decisions_file" ]]; then
2150
+ local tmp
2151
+ tmp="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/mem-decay2-$$.tmp")"
2152
+ jq --argjson threshold "$threshold_epoch" '
2153
+ if type == "array" then
2154
+ [.[] | if (.timestamp // 0) < $threshold then
2155
+ .weight = ((.weight // 1) * 0.5 | if . < 0.1 then 0.1 else . end)
2156
+ else . end]
2157
+ else . end
2158
+ ' "$decisions_file" > "$tmp" 2>/dev/null
2159
+ if [[ -s "$tmp" ]]; then
2160
+ mv "$tmp" "$decisions_file"
2161
+ decayed_count=$((decayed_count + 1))
2162
+ else
2163
+ rm -f "$tmp"
2164
+ fi
2165
+ fi
2166
+
2167
+ if [[ "$decayed_count" -gt 0 ]]; then
2168
+ emit_event "memory.decay_applied" "files=$decayed_count" "threshold_days=$days_threshold"
2169
+ fi
2170
+ }
2171
+
1827
2172
  # ─── Command Router ─────────────────────────────────────────────────────────
1828
2173
 
1829
2174
  if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
@@ -1873,6 +2218,15 @@ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
1873
2218
  fix-outcome)
1874
2219
  memory_record_fix_outcome "$@"
1875
2220
  ;;
2221
+ search-weighted)
2222
+ memory_search_weighted "$@"
2223
+ ;;
2224
+ decay)
2225
+ memory_decay_old "$@"
2226
+ ;;
2227
+ ab-report)
2228
+ cmd_memory_ab_report "$@"
2229
+ ;;
1876
2230
  help|--help|-h)
1877
2231
  show_help
1878
2232
  ;;
@@ -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.2.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
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -30,6 +32,7 @@ fi
30
32
  if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
31
33
  emit_event() {
32
34
  local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
35
+ # shellcheck disable=SC2155
33
36
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
34
37
  while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
35
38
  echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
@@ -100,6 +103,7 @@ get_recent_alerts() {
100
103
  tail -"$limit" | while IFS= read -r line; do
101
104
  local ts
102
105
  local type
106
+ # shellcheck disable=SC2034
103
107
  local msg
104
108
 
105
109
  ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || echo "")
@@ -167,6 +171,7 @@ show_overview() {
167
171
  2>/dev/null | while IFS= read -r line; do
168
172
  local issue
169
173
  local title
174
+ # shellcheck disable=SC2034
170
175
  local worktree
171
176
 
172
177
  issue=$(echo "$line" | jq -r '.[0]' 2>/dev/null || echo "")