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
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env bash
2
+ # Module guard - prevent double-sourcing
3
+ [[ -n "${_MUTATION_EXECUTOR_LOADED:-}" ]] && return 0
4
+ _MUTATION_EXECUTOR_LOADED=1
5
+
6
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
7
+ # ║ shipwright mutation-executor — Real Mutation Testing Engine ║
8
+ # ║ Generate code mutations via sed, run tests against each mutant, ║
9
+ # ║ track killed/survived, report mutation score and weak tests ║
10
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
11
+
12
+ # shellcheck disable=SC2034
13
+ VERSION="3.3.0"
14
+
15
+ # ─── Output Helpers ──────────────────────────────────────────────────────────
16
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
17
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
18
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
19
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
20
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
21
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
22
+ now_epoch() { date +%s; }
23
+ fi
24
+
25
+ # ─── Configuration ───────────────────────────────────────────────────────────
26
+
27
+ MUTATION_DIR="${MUTATION_DIR:-.claude/mutations}"
28
+ MUTATION_REPORT_FILE="${MUTATION_REPORT_FILE:-.claude/pipeline-artifacts/mutation-report.json}"
29
+ MUTATION_MAX_MUTANTS="${MUTATION_MAX_MUTANTS:-50}"
30
+ MUTATION_TIMEOUT="${MUTATION_TIMEOUT:-60}"
31
+
32
+ # ─── Generate Mutations ─────────────────────────────────────────────────────
33
+ # Generate code mutations for a file using sed-based transformations.
34
+ # Input: $1 = source file to mutate
35
+ # Output: mutation descriptors in $MUTATION_DIR, count echoed
36
+
37
+ mutation_generate() {
38
+ local source_file="${1:-}"
39
+ local output_dir="${2:-$MUTATION_DIR}"
40
+
41
+ if [[ -z "$source_file" || ! -f "$source_file" ]]; then
42
+ echo "0"
43
+ return 0
44
+ fi
45
+
46
+ mkdir -p "$output_dir" 2>/dev/null || true
47
+
48
+ local file_hash
49
+ file_hash=$(cksum "$source_file" 2>/dev/null | cut -d' ' -f1 || echo "$$")
50
+ local mutation_count=0
51
+
52
+ # ── Mutation operators ──
53
+
54
+ # 1. Flip comparisons: == → !=, != → ==, > → <, < → >, >= → <=, <= → >=
55
+ local line_num=0
56
+ while IFS= read -r line; do
57
+ line_num=$((line_num + 1))
58
+ [[ "$mutation_count" -ge "$MUTATION_MAX_MUTANTS" ]] && break
59
+
60
+ # Skip comments and strings (heuristic: lines starting with # or //)
61
+ if echo "$line" | grep -qE '^\s*(#|//)' 2>/dev/null; then
62
+ continue
63
+ fi
64
+
65
+ # == → !=
66
+ if echo "$line" | grep -qE '==' 2>/dev/null; then
67
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
68
+ "comparison_flip" "== to !=" \
69
+ "s/==/!=/" "$file_hash" "$mutation_count"
70
+ mutation_count=$((mutation_count + 1))
71
+ fi
72
+
73
+ # != → ==
74
+ if echo "$line" | grep -qE '!=' 2>/dev/null; then
75
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
76
+ "comparison_flip" "!= to ==" \
77
+ "s/!=/==/" "$file_hash" "$mutation_count"
78
+ mutation_count=$((mutation_count + 1))
79
+ fi
80
+
81
+ # >= → <
82
+ if echo "$line" | grep -qE '>=' 2>/dev/null; then
83
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
84
+ "boundary_flip" ">= to <" \
85
+ "s/>=/< /" "$file_hash" "$mutation_count"
86
+ mutation_count=$((mutation_count + 1))
87
+ fi
88
+
89
+ # <= → >
90
+ if echo "$line" | grep -qE '<=' 2>/dev/null; then
91
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
92
+ "boundary_flip" "<= to >" \
93
+ "s/<=/> /" "$file_hash" "$mutation_count"
94
+ mutation_count=$((mutation_count + 1))
95
+ fi
96
+
97
+ # && → ||
98
+ if echo "$line" | grep -qE '&&' 2>/dev/null; then
99
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
100
+ "logical_flip" "&& to ||" \
101
+ "s/&&/||/" "$file_hash" "$mutation_count"
102
+ mutation_count=$((mutation_count + 1))
103
+ fi
104
+
105
+ # || → &&
106
+ if echo "$line" | grep -qE '\|\|' 2>/dev/null; then
107
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
108
+ "logical_flip" "|| to &&" \
109
+ "s/||/\&\&/" "$file_hash" "$mutation_count"
110
+ mutation_count=$((mutation_count + 1))
111
+ fi
112
+
113
+ # true → false
114
+ if echo "$line" | grep -qE '\btrue\b' 2>/dev/null; then
115
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
116
+ "boolean_flip" "true to false" \
117
+ "s/\\btrue\\b/false/" "$file_hash" "$mutation_count"
118
+ mutation_count=$((mutation_count + 1))
119
+ fi
120
+
121
+ # false → true
122
+ if echo "$line" | grep -qE '\bfalse\b' 2>/dev/null; then
123
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
124
+ "boolean_flip" "false to true" \
125
+ "s/\\bfalse\\b/true/" "$file_hash" "$mutation_count"
126
+ mutation_count=$((mutation_count + 1))
127
+ fi
128
+
129
+ # + → - (only in arithmetic context, not string concat)
130
+ if echo "$line" | grep -qE '[0-9]\s*\+\s*[0-9]' 2>/dev/null; then
131
+ _write_mutation "$output_dir" "$source_file" "$line_num" \
132
+ "arithmetic_flip" "+ to -" \
133
+ "s/+/-/" "$file_hash" "$mutation_count"
134
+ mutation_count=$((mutation_count + 1))
135
+ fi
136
+
137
+ done < "$source_file"
138
+
139
+ if [[ "$(type -t emit_event 2>/dev/null)" == "function" ]]; then
140
+ emit_event "mutation.generated" \
141
+ "file=$source_file" "count=$mutation_count" 2>/dev/null || true
142
+ fi
143
+
144
+ echo "$mutation_count"
145
+ }
146
+
147
+ # Helper: write a mutation descriptor to disk
148
+ _write_mutation() {
149
+ local dir="$1" file="$2" line="$3" category="$4" desc="$5" sed_expr="$6" hash="$7" idx="$8"
150
+
151
+ local mut_id="mut_${hash}_${idx}"
152
+ local mut_file="${dir}/${mut_id}.json"
153
+
154
+ jq -n --arg id "$mut_id" --arg file "$file" --argjson line "$line" \
155
+ --arg category "$category" --arg description "$desc" --arg sed "$sed_expr" \
156
+ '{"id":$id,"file":$file,"line":$line,"category":$category,"description":$description,"sed_expression":$sed}' \
157
+ > "$mut_file" 2>/dev/null || true
158
+ }
159
+
160
+ # ─── Execute Mutations ───────────────────────────────────────────────────────
161
+ # Run test suite against each mutant, track killed/survived.
162
+ # Input: $1 = mutation dir, $2 = test command, $3 = project root
163
+ # Output: results written to mutation dir, summary echoed as JSON
164
+
165
+ mutation_execute() {
166
+ local mut_dir="${1:-$MUTATION_DIR}"
167
+ local test_cmd="${2:-}"
168
+ local project_root="${3:-.}"
169
+
170
+ if [[ -z "$test_cmd" ]]; then
171
+ error "mutation_execute requires a test command"
172
+ echo '{"killed":0,"survived":0,"errors":0,"total":0}'
173
+ return 1
174
+ fi
175
+
176
+ if [[ ! -d "$mut_dir" ]]; then
177
+ echo '{"killed":0,"survived":0,"errors":0,"total":0}'
178
+ return 0
179
+ fi
180
+
181
+ local total=0 killed=0 survived=0 errors=0
182
+
183
+ # Process each mutation
184
+ local mut_file
185
+ for mut_file in "$mut_dir"/mut_*.json; do
186
+ [[ ! -f "$mut_file" ]] && continue
187
+ total=$((total + 1))
188
+
189
+ local src_file line_num sed_expr mut_id
190
+ mut_id=$(jq -r '.id // ""' "$mut_file" 2>/dev/null || true)
191
+ src_file=$(jq -r '.file // ""' "$mut_file" 2>/dev/null || true)
192
+ line_num=$(jq -r '.line // 0' "$mut_file" 2>/dev/null || true)
193
+ sed_expr=$(jq -r '.sed_expression // ""' "$mut_file" 2>/dev/null || true)
194
+
195
+ if [[ -z "$src_file" || ! -f "$src_file" || -z "$sed_expr" ]]; then
196
+ errors=$((errors + 1))
197
+ continue
198
+ fi
199
+
200
+ # Backup original file
201
+ local backup_file
202
+ backup_file=$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/mutation-backup.$$.tmp")
203
+ cp "$src_file" "$backup_file" 2>/dev/null || {
204
+ errors=$((errors + 1))
205
+ continue
206
+ }
207
+
208
+ # Apply mutation (cross-platform sed -i)
209
+ if type sed_i >/dev/null 2>&1; then
210
+ sed_i "${line_num}${sed_expr}" "$src_file" 2>/dev/null
211
+ elif [[ "$(uname -s)" == "Darwin" ]]; then
212
+ sed -i '' "${line_num}${sed_expr}" "$src_file" 2>/dev/null
213
+ else
214
+ sed -i "${line_num}${sed_expr}" "$src_file" 2>/dev/null
215
+ fi || {
216
+ # Revert on sed failure
217
+ cp "$backup_file" "$src_file" 2>/dev/null || true
218
+ rm -f "$backup_file" 2>/dev/null || true
219
+ errors=$((errors + 1))
220
+ continue
221
+ }
222
+
223
+ # Run tests against mutant
224
+ local test_exit=0
225
+ (cd "$project_root" && timeout "$MUTATION_TIMEOUT" bash -c "$test_cmd" > /dev/null 2>&1) || test_exit=$?
226
+
227
+ # Revert mutation
228
+ cp "$backup_file" "$src_file" 2>/dev/null || true
229
+ rm -f "$backup_file" 2>/dev/null || true
230
+
231
+ # Record result
232
+ if [[ "$test_exit" -ne 0 ]]; then
233
+ killed=$((killed + 1))
234
+ # Update mutation file with result
235
+ local tmp_mut
236
+ tmp_mut=$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/mut-result.$$.tmp")
237
+ jq '. + {"result":"killed"}' "$mut_file" > "$tmp_mut" 2>/dev/null && mv "$tmp_mut" "$mut_file" 2>/dev/null || rm -f "$tmp_mut" 2>/dev/null
238
+ else
239
+ survived=$((survived + 1))
240
+ local tmp_mut
241
+ tmp_mut=$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/mut-result.$$.tmp")
242
+ jq '. + {"result":"survived"}' "$mut_file" > "$tmp_mut" 2>/dev/null && mv "$tmp_mut" "$mut_file" 2>/dev/null || rm -f "$tmp_mut" 2>/dev/null
243
+ fi
244
+ done
245
+
246
+ if [[ "$(type -t emit_event 2>/dev/null)" == "function" ]]; then
247
+ emit_event "mutation.executed" \
248
+ "total=$total" "killed=$killed" "survived=$survived" "errors=$errors" 2>/dev/null || true
249
+ fi
250
+
251
+ jq -n --argjson total "$total" --argjson killed "$killed" \
252
+ --argjson survived "$survived" --argjson errors "$errors" \
253
+ '{"killed":$killed,"survived":$survived,"errors":$errors,"total":$total}'
254
+ }
255
+
256
+ # ─── Mutation Report ─────────────────────────────────────────────────────────
257
+ # Generate mutation testing report with score and weak test identification.
258
+ # Input: $1 = mutation dir, $2 = output file
259
+ # Output: report JSON path echoed
260
+
261
+ mutation_report() {
262
+ local mut_dir="${1:-$MUTATION_DIR}"
263
+ local report_file="${2:-$MUTATION_REPORT_FILE}"
264
+
265
+ local out_dir
266
+ out_dir=$(dirname "$report_file")
267
+ mkdir -p "$out_dir" 2>/dev/null || true
268
+
269
+ local total=0 killed=0 survived=0 errors=0
270
+ local survived_json='[]'
271
+ local categories_killed='{}'
272
+ local categories_total='{}'
273
+
274
+ local mut_file
275
+ for mut_file in "$mut_dir"/mut_*.json; do
276
+ [[ ! -f "$mut_file" ]] && continue
277
+ total=$((total + 1))
278
+
279
+ local result category description src_file line_num
280
+ result=$(jq -r '.result // "unknown"' "$mut_file" 2>/dev/null || true)
281
+ category=$(jq -r '.category // "unknown"' "$mut_file" 2>/dev/null || true)
282
+ description=$(jq -r '.description // ""' "$mut_file" 2>/dev/null || true)
283
+ src_file=$(jq -r '.file // ""' "$mut_file" 2>/dev/null || true)
284
+ line_num=$(jq -r '.line // 0' "$mut_file" 2>/dev/null || true)
285
+
286
+ # Track category totals
287
+ local cat_count
288
+ cat_count=$(echo "$categories_total" | jq --arg c "$category" '.[$c] // 0' 2>/dev/null || echo "0")
289
+ categories_total=$(echo "$categories_total" | jq --arg c "$category" --argjson n "$((cat_count + 1))" '.[$c] = $n' 2>/dev/null || echo "$categories_total")
290
+
291
+ case "$result" in
292
+ killed)
293
+ killed=$((killed + 1))
294
+ local ck
295
+ ck=$(echo "$categories_killed" | jq --arg c "$category" '.[$c] // 0' 2>/dev/null || echo "0")
296
+ categories_killed=$(echo "$categories_killed" | jq --arg c "$category" --argjson n "$((ck + 1))" '.[$c] = $n' 2>/dev/null || echo "$categories_killed")
297
+ ;;
298
+ survived)
299
+ survived=$((survived + 1))
300
+ survived_json=$(echo "$survived_json" | jq --arg file "$src_file" --argjson line "$line_num" \
301
+ --arg cat "$category" --arg desc "$description" \
302
+ '. + [{"file":$file,"line":$line,"category":$cat,"description":$desc}]' 2>/dev/null || echo "$survived_json")
303
+ ;;
304
+ *)
305
+ errors=$((errors + 1))
306
+ ;;
307
+ esac
308
+ done
309
+
310
+ # Calculate mutation score
311
+ local mutation_score=0
312
+ local effective_total=$((total - errors))
313
+ if [[ "$effective_total" -gt 0 ]]; then
314
+ mutation_score=$(( (killed * 100) / effective_total ))
315
+ fi
316
+
317
+ # Identify weak areas (files with surviving mutants)
318
+ local weak_files='[]'
319
+ weak_files=$(echo "$survived_json" | jq '[group_by(.file)[] | {"file":.[0].file,"surviving_count":length,"mutations":[.[] | .description]}]' 2>/dev/null || echo "[]")
320
+
321
+ # Build report
322
+ jq -n --argjson total "$total" --argjson killed "$killed" \
323
+ --argjson survived "$survived" --argjson errors "$errors" \
324
+ --argjson score "$mutation_score" \
325
+ --argjson surviving "$survived_json" \
326
+ --argjson weak "$weak_files" \
327
+ --argjson cat_killed "$categories_killed" \
328
+ --argjson cat_total "$categories_total" \
329
+ --arg ts "$(now_iso)" \
330
+ '{
331
+ "mutation_score_pct": $score,
332
+ "total": $total,
333
+ "killed": $killed,
334
+ "survived": $survived,
335
+ "errors": $errors,
336
+ "target_pct": 80,
337
+ "meets_target": ($score >= 80),
338
+ "surviving_mutants": $surviving,
339
+ "weak_files": $weak,
340
+ "categories_killed": $cat_killed,
341
+ "categories_total": $cat_total,
342
+ "generated_at": $ts
343
+ }' > "$report_file" 2>/dev/null
344
+
345
+ if [[ "$(type -t emit_event 2>/dev/null)" == "function" ]]; then
346
+ emit_event "mutation.report" \
347
+ "score=$mutation_score" "total=$total" "killed=$killed" \
348
+ "survived=$survived" 2>/dev/null || true
349
+ fi
350
+
351
+ echo "$report_file"
352
+ }