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
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bash
2
+ # Module guard - prevent double-sourcing
3
+ [[ -n "${_LOOP_PROGRESS_LOADED:-}" ]] && return 0
4
+ _LOOP_PROGRESS_LOADED=1
5
+
6
+ # ─── Progress File Management ──────────────────────────────────────────────────
7
+
8
+ write_progress() {
9
+ local progress_file="$LOG_DIR/progress.md"
10
+ local recent_commits
11
+ recent_commits=$(git -C "$PROJECT_ROOT" log --oneline -5 2>/dev/null || echo "(no commits)")
12
+ local changed_files
13
+ changed_files=$(git -C "$PROJECT_ROOT" diff --name-only HEAD~3 2>/dev/null | head -20 || echo "(none)")
14
+ local last_error=""
15
+ local prev_test_log="$LOG_DIR/tests-iter-${ITERATION}.log"
16
+ if [[ -f "$prev_test_log" ]] && [[ "${TEST_PASSED:-}" == "false" ]]; then
17
+ last_error=$(tail -10 "$prev_test_log" 2>/dev/null || true)
18
+ fi
19
+
20
+ # Use printf to avoid heredoc delimiter injection from GOAL content
21
+ local tmp_progress="${progress_file}.tmp.$$"
22
+ {
23
+ printf '# Session Progress (Auto-Generated)\n\n'
24
+ printf '## Goal\n%s\n\n' "${GOAL}"
25
+ printf '## Status\n'
26
+ printf -- '- Iteration: %s/%s\n' "${ITERATION}" "${MAX_ITERATIONS}"
27
+ printf -- '- Session restart: %s/%s\n' "${RESTART_COUNT:-0}" "${MAX_RESTARTS:-0}"
28
+ printf -- '- Tests passing: %s\n' "${TEST_PASSED:-unknown}"
29
+ printf -- '- Status: %s\n\n' "${STATUS:-running}"
30
+ printf '## Recent Commits\n%s\n\n' "${recent_commits}"
31
+ printf '## Changed Files\n%s\n\n' "${changed_files}"
32
+ if [[ -n "$last_error" ]]; then
33
+ printf '## Last Error\n%s\n\n' "$last_error"
34
+ fi
35
+ printf '## Timestamp\n%s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
36
+ } > "$tmp_progress" 2>/dev/null
37
+ mv "$tmp_progress" "$progress_file" 2>/dev/null || rm -f "$tmp_progress" 2>/dev/null
38
+ }
39
+
40
+ append_log_entry() {
41
+ local entry="$1"
42
+ if [[ -n "$LOG_ENTRIES" ]]; then
43
+ LOG_ENTRIES="${LOG_ENTRIES}
44
+ ${entry}"
45
+ else
46
+ LOG_ENTRIES="$entry"
47
+ fi
48
+ }
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env bash
2
+ # Module guard - prevent double-sourcing
3
+ [[ -n "${_LOOP_RESTART_LOADED:-}" ]] && return 0
4
+ _LOOP_RESTART_LOADED=1
5
+
6
+ # ─── State Management ────────────────────────────────────────────────────────
7
+
8
+ initialize_state() {
9
+ ITERATION=0
10
+ CONSECUTIVE_FAILURES=0
11
+ TOTAL_COMMITS=0
12
+ START_EPOCH="$(now_epoch)"
13
+ STATUS="running"
14
+ LOG_ENTRIES=""
15
+
16
+ # Record starting commit for cumulative diff in quality gates
17
+ LOOP_START_COMMIT="$(git -C "$PROJECT_ROOT" rev-parse HEAD 2>/dev/null || echo "")"
18
+
19
+ write_state
20
+ }
21
+
22
+ resume_state() {
23
+ if [[ ! -f "$STATE_FILE" ]]; then
24
+ error "No state file found at $STATE_FILE"
25
+ echo -e " Start a new loop instead: ${DIM}shipwright loop \"<goal>\"${RESET}"
26
+ exit 1
27
+ fi
28
+
29
+ info "Resuming from $STATE_FILE"
30
+
31
+ # Save CLI values before parsing state (CLI takes precedence)
32
+ local cli_max_iterations="$MAX_ITERATIONS"
33
+
34
+ # Parse YAML front matter
35
+ local in_frontmatter=false
36
+ while IFS= read -r line; do
37
+ if [[ "$line" == "---" ]]; then
38
+ if $in_frontmatter; then
39
+ break
40
+ else
41
+ in_frontmatter=true
42
+ continue
43
+ fi
44
+ fi
45
+ if $in_frontmatter; then
46
+ case "$line" in
47
+ goal:*) [[ -z "$GOAL" ]] && GOAL="$(echo "${line#goal:}" | sed 's/^ *"//;s/" *$//')" ;;
48
+ iteration:*) ITERATION="$(echo "${line#iteration:}" | tr -d ' ')" ;;
49
+ max_iterations:*) MAX_ITERATIONS="$(echo "${line#max_iterations:}" | tr -d ' ')" ;;
50
+ status:*) STATUS="$(echo "${line#status:}" | tr -d ' ')" ;;
51
+ test_cmd:*) [[ -z "$TEST_CMD" ]] && TEST_CMD="$(echo "${line#test_cmd:}" | sed 's/^ *"//;s/" *$//')" ;;
52
+ model:*) MODEL="$(echo "${line#model:}" | tr -d ' ')" ;;
53
+ agents:*) AGENTS="$(echo "${line#agents:}" | tr -d ' ')" ;;
54
+ consecutive_failures:*) CONSECUTIVE_FAILURES="$(echo "${line#consecutive_failures:}" | tr -d ' ')" ;;
55
+ total_commits:*) TOTAL_COMMITS="$(echo "${line#total_commits:}" | tr -d ' ')" ;;
56
+ audit_enabled:*) AUDIT_ENABLED="$(echo "${line#audit_enabled:}" | tr -d ' ')" ;;
57
+ audit_agent_enabled:*) AUDIT_AGENT_ENABLED="$(echo "${line#audit_agent_enabled:}" | tr -d ' ')" ;;
58
+ quality_gates_enabled:*) QUALITY_GATES_ENABLED="$(echo "${line#quality_gates_enabled:}" | tr -d ' ')" ;;
59
+ dod_file:*) DOD_FILE="$(echo "${line#dod_file:}" | sed 's/^ *"//;s/" *$//')" ;;
60
+ auto_extend:*) AUTO_EXTEND="$(echo "${line#auto_extend:}" | tr -d ' ')" ;;
61
+ extension_count:*) EXTENSION_COUNT="$(echo "${line#extension_count:}" | tr -d ' ')" ;;
62
+ max_extensions:*) MAX_EXTENSIONS="$(echo "${line#max_extensions:}" | tr -d ' ')" ;;
63
+ esac
64
+ fi
65
+ done < "$STATE_FILE"
66
+
67
+ # CLI --max-iterations overrides state file
68
+ if $MAX_ITERATIONS_EXPLICIT; then
69
+ MAX_ITERATIONS="$cli_max_iterations"
70
+ fi
71
+
72
+ # Extract the log section (everything after ## Log)
73
+ LOG_ENTRIES="$(sed -n '/^## Log$/,$ { /^## Log$/d; p; }' "$STATE_FILE" 2>/dev/null || true)"
74
+
75
+ if [[ -z "$GOAL" ]]; then
76
+ error "Could not parse goal from state file."
77
+ exit 1
78
+ fi
79
+
80
+ if [[ "$STATUS" == "complete" ]]; then
81
+ warn "Previous loop completed. Start a new one or edit the state file."
82
+ exit 0
83
+ fi
84
+
85
+ # Reset circuit breaker on resume
86
+ CONSECUTIVE_FAILURES=0
87
+ START_EPOCH="$(now_epoch)"
88
+ STATUS="running"
89
+
90
+ # Set starting commit for cumulative diff (approximate: use earliest tracked commit)
91
+ if [[ -z "${LOOP_START_COMMIT:-}" ]]; then
92
+ LOOP_START_COMMIT="$(git -C "$PROJECT_ROOT" rev-list --max-parents=0 HEAD 2>/dev/null | tail -1 || echo "")"
93
+ fi
94
+
95
+ # If we hit max iterations before, warn user to extend
96
+ if [[ "$ITERATION" -ge "$MAX_ITERATIONS" ]] && ! $MAX_ITERATIONS_EXPLICIT; then
97
+ warn "Previous run stopped at iteration $ITERATION/$MAX_ITERATIONS."
98
+ echo -e " Extend with: ${DIM}shipwright loop --resume --max-iterations $(( MAX_ITERATIONS + 10 ))${RESET}"
99
+ exit 0
100
+ fi
101
+
102
+ # Restore Claude context for meaningful resume (source so exports persist to this shell)
103
+ if [[ -f "$SCRIPT_DIR/sw-checkpoint.sh" ]] && [[ -d "${PROJECT_ROOT:-}" ]]; then
104
+ source "$SCRIPT_DIR/sw-checkpoint.sh"
105
+ local _orig_pwd="$PWD"
106
+ cd "$PROJECT_ROOT" 2>/dev/null || true
107
+ if checkpoint_restore_context "build" 2>/dev/null; then
108
+ RESUMED_FROM_ITERATION="${RESTORED_ITERATION:-}"
109
+ RESUMED_MODIFIED="${RESTORED_MODIFIED:-}"
110
+ RESUMED_FINDINGS="${RESTORED_FINDINGS:-}"
111
+ RESUMED_TEST_OUTPUT="${RESTORED_TEST_OUTPUT:-}"
112
+ [[ -n "${RESTORED_ITERATION:-}" && "${RESTORED_ITERATION:-0}" -gt 0 ]] && info "Restored context from iteration ${RESTORED_ITERATION}"
113
+ fi
114
+ cd "$_orig_pwd" 2>/dev/null || true
115
+ fi
116
+
117
+ success "Resumed: iteration $ITERATION/$MAX_ITERATIONS"
118
+ }
119
+
120
+ write_state() {
121
+ local tmp_state="${STATE_FILE}.tmp.$$"
122
+ # Use printf instead of heredoc to avoid delimiter injection from GOAL
123
+ {
124
+ printf -- '---\n'
125
+ printf 'goal: "%s"\n' "$GOAL"
126
+ printf 'iteration: %s\n' "$ITERATION"
127
+ printf 'max_iterations: %s\n' "$MAX_ITERATIONS"
128
+ printf 'status: %s\n' "$STATUS"
129
+ printf 'test_cmd: "%s"\n' "$TEST_CMD"
130
+ printf 'model: %s\n' "$MODEL"
131
+ printf 'agents: %s\n' "$AGENTS"
132
+ printf 'started_at: %s\n' "$(now_iso)"
133
+ printf 'last_iteration_at: %s\n' "$(now_iso)"
134
+ printf 'consecutive_failures: %s\n' "$CONSECUTIVE_FAILURES"
135
+ printf 'total_commits: %s\n' "$TOTAL_COMMITS"
136
+ printf 'audit_enabled: %s\n' "$AUDIT_ENABLED"
137
+ printf 'audit_agent_enabled: %s\n' "$AUDIT_AGENT_ENABLED"
138
+ printf 'quality_gates_enabled: %s\n' "$QUALITY_GATES_ENABLED"
139
+ printf 'dod_file: "%s"\n' "$DOD_FILE"
140
+ printf 'auto_extend: %s\n' "$AUTO_EXTEND"
141
+ printf 'extension_count: %s\n' "$EXTENSION_COUNT"
142
+ printf 'max_extensions: %s\n' "$MAX_EXTENSIONS"
143
+ printf -- '---\n\n'
144
+ printf '## Log\n'
145
+ printf '%s\n' "$LOG_ENTRIES"
146
+ } > "$tmp_state"
147
+ if ! mv "$tmp_state" "$STATE_FILE" 2>/dev/null; then
148
+ warn "Failed to write state file: $STATE_FILE"
149
+ rm -f "$tmp_state"
150
+ fi
151
+ }
152
+
153
+ check_fatal_error() {
154
+ local log_file="$1"
155
+ local cli_exit_code="${2:-0}"
156
+ [[ -f "$log_file" ]] || return 1
157
+
158
+ # Known fatal error patterns from Claude CLI / Anthropic API
159
+ local fatal_patterns="Invalid API key|invalid_api_key|authentication_error|API key expired"
160
+ fatal_patterns="${fatal_patterns}|rate_limit_error|overloaded_error|billing"
161
+ fatal_patterns="${fatal_patterns}|Could not resolve host|connection refused|ECONNREFUSED"
162
+ fatal_patterns="${fatal_patterns}|ANTHROPIC_API_KEY.*not set|No API key"
163
+
164
+ if grep -qiE "$fatal_patterns" "$log_file" 2>/dev/null; then
165
+ local match
166
+ match=$(grep -iE "$fatal_patterns" "$log_file" 2>/dev/null | head -1 | cut -c1-120)
167
+ error "Fatal CLI error: $match"
168
+ return 1 # fatal error detected
169
+ fi
170
+
171
+ # Non-zero exit + tiny output = likely CLI crash
172
+ if [[ "$cli_exit_code" -ne 0 ]]; then
173
+ local line_count
174
+ line_count=$(grep -cv '^$' "$log_file" 2>/dev/null || true)
175
+ line_count="${line_count:-0}"
176
+ if [[ "$line_count" -lt 3 ]]; then
177
+ local content
178
+ content=$(head -3 "$log_file" 2>/dev/null | cut -c1-120)
179
+ error "CLI exited $cli_exit_code with minimal output: $content"
180
+ return 0
181
+ fi
182
+ fi
183
+
184
+ return 1 # no fatal error
185
+ }