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,407 @@
1
+ # pipeline-stages-monitor.sh — validate, monitor stages
2
+ # Source from pipeline-stages.sh. Requires all pipeline globals and dependencies.
3
+ [[ -n "${_PIPELINE_STAGES_MONITOR_LOADED:-}" ]] && return 0
4
+ _PIPELINE_STAGES_MONITOR_LOADED=1
5
+
6
+ stage_validate() {
7
+ CURRENT_STAGE_ID="validate"
8
+ # Consume retry context if this is a retry attempt
9
+ local _retry_ctx="${ARTIFACTS_DIR}/.retry-context-validate.md"
10
+ if [[ -s "$_retry_ctx" ]]; then
11
+ local _validate_retry_hints
12
+ _validate_retry_hints=$(cat "$_retry_ctx" 2>/dev/null || true)
13
+ rm -f "$_retry_ctx"
14
+ fi
15
+ # Load validation thoroughness skills
16
+ if type skill_load_prompts >/dev/null 2>&1; then
17
+ local _validate_skills
18
+ _validate_skills=$(skill_load_prompts "${INTELLIGENCE_ISSUE_TYPE:-backend}" "validate" 2>/dev/null || true)
19
+ if [[ -n "$_validate_skills" ]]; then
20
+ echo "$_validate_skills" > "${ARTIFACTS_DIR}/.validation-skills.md" 2>/dev/null || true
21
+ fi
22
+ fi
23
+ local smoke_cmd
24
+ smoke_cmd=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.smoke_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
25
+ [[ "$smoke_cmd" == "null" ]] && smoke_cmd=""
26
+
27
+ local health_url
28
+ health_url=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.health_url) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
29
+ [[ "$health_url" == "null" ]] && health_url=""
30
+
31
+ local close_issue
32
+ close_issue=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.close_issue) // false' "$PIPELINE_CONFIG" 2>/dev/null) || true
33
+
34
+ # Smoke tests
35
+ if [[ -n "$smoke_cmd" ]]; then
36
+ info "Running smoke tests..."
37
+ bash -c "$smoke_cmd" > "$ARTIFACTS_DIR/smoke.log" 2>&1 || {
38
+ error "Smoke tests failed"
39
+ if [[ -n "$ISSUE_NUMBER" ]]; then
40
+ gh issue create --title "Deploy validation failed: $GOAL" \
41
+ --label "incident" --body "Pipeline smoke tests failed after deploy.
42
+
43
+ Related issue: ${GITHUB_ISSUE}
44
+ Branch: ${GIT_BRANCH}
45
+ PR: $(cat "$ARTIFACTS_DIR/pr-url.txt" 2>/dev/null || echo 'unknown')" 2>/dev/null || true
46
+ fi
47
+ return 1
48
+ }
49
+ success "Smoke tests passed"
50
+ fi
51
+
52
+ # Health check with retry
53
+ if [[ -n "$health_url" ]]; then
54
+ info "Health check: $health_url"
55
+ local attempts=0
56
+ while [[ $attempts -lt 5 ]]; do
57
+ if curl -sf "$health_url" >/dev/null 2>&1; then
58
+ success "Health check passed"
59
+ break
60
+ fi
61
+ attempts=$((attempts + 1))
62
+ [[ $attempts -lt 5 ]] && { info "Retry ${attempts}/5..."; sleep "$(_exponential_backoff "$attempts" 5 60)"; }
63
+ done
64
+ if [[ $attempts -ge 5 ]]; then
65
+ error "Health check failed after 5 attempts"
66
+ return 1
67
+ fi
68
+ fi
69
+
70
+ # Compute total duration once for both issue close and wiki report
71
+ local total_dur=""
72
+ if [[ -n "$PIPELINE_START_EPOCH" ]]; then
73
+ total_dur=$(format_duration $(( $(now_epoch) - PIPELINE_START_EPOCH )))
74
+ fi
75
+
76
+ # Close original issue with comprehensive summary
77
+ if [[ "$close_issue" == "true" && -n "$ISSUE_NUMBER" ]]; then
78
+ gh issue close "$ISSUE_NUMBER" --comment "## ✅ Complete — Deployed & Validated
79
+
80
+ | Metric | Value |
81
+ |--------|-------|
82
+ | Pipeline | \`${PIPELINE_NAME}\` |
83
+ | Branch | \`${GIT_BRANCH}\` |
84
+ | PR | $(cat "$ARTIFACTS_DIR/pr-url.txt" 2>/dev/null || echo 'N/A') |
85
+ | Duration | ${total_dur:-unknown} |
86
+
87
+ _Closed automatically by \`shipwright pipeline\`_" 2>/dev/null || true
88
+
89
+ gh_remove_label "$ISSUE_NUMBER" "pipeline/pr-created"
90
+ gh_add_labels "$ISSUE_NUMBER" "pipeline/complete"
91
+ success "Issue #$ISSUE_NUMBER closed"
92
+ fi
93
+
94
+ # Push pipeline report to wiki
95
+ local report="# Pipeline Report — ${GOAL}
96
+
97
+ | Metric | Value |
98
+ |--------|-------|
99
+ | Pipeline | \`${PIPELINE_NAME}\` |
100
+ | Branch | \`${GIT_BRANCH}\` |
101
+ | PR | $(cat "$ARTIFACTS_DIR/pr-url.txt" 2>/dev/null || echo 'N/A') |
102
+ | Duration | ${total_dur:-unknown} |
103
+ | Stages | $(echo "$STAGE_TIMINGS" | tr '|' '\n' | wc -l | xargs) completed |
104
+
105
+ ## Stage Timings
106
+ $(echo "$STAGE_TIMINGS" | tr '|' '\n' | sed 's/^/- /')
107
+
108
+ ## Artifacts
109
+ $(ls -1 "$ARTIFACTS_DIR" 2>/dev/null | sed 's/^/- /')
110
+
111
+ ---
112
+ _Generated by \`shipwright pipeline\` at $(now_iso)_"
113
+ gh_wiki_page "Pipeline-Report-${ISSUE_NUMBER:-inline}" "$report"
114
+
115
+ log_stage "validate" "Validation complete"
116
+ }
117
+
118
+ stage_monitor() {
119
+ CURRENT_STAGE_ID="monitor"
120
+ # Consume retry context if this is a retry attempt
121
+ local _retry_ctx="${ARTIFACTS_DIR}/.retry-context-monitor.md"
122
+ if [[ -s "$_retry_ctx" ]]; then
123
+ local _monitor_retry_hints
124
+ _monitor_retry_hints=$(cat "$_retry_ctx" 2>/dev/null || true)
125
+ rm -f "$_retry_ctx"
126
+ fi
127
+ # Load observability skills
128
+ if type skill_load_prompts >/dev/null 2>&1; then
129
+ local _monitor_skills
130
+ _monitor_skills=$(skill_load_prompts "${INTELLIGENCE_ISSUE_TYPE:-backend}" "monitor" 2>/dev/null || true)
131
+ if [[ -n "$_monitor_skills" ]]; then
132
+ echo "$_monitor_skills" > "${ARTIFACTS_DIR}/.monitoring-skills.md" 2>/dev/null || true
133
+ fi
134
+ fi
135
+
136
+ # Read config from pipeline template
137
+ local duration_minutes health_url error_threshold log_pattern log_cmd rollback_cmd auto_rollback
138
+ duration_minutes=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.duration_minutes) // 5' "$PIPELINE_CONFIG" 2>/dev/null) || true
139
+ [[ -z "$duration_minutes" || "$duration_minutes" == "null" ]] && duration_minutes=5
140
+ health_url=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.health_url) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
141
+ [[ "$health_url" == "null" ]] && health_url=""
142
+ error_threshold=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.error_threshold) // 5' "$PIPELINE_CONFIG" 2>/dev/null) || true
143
+ [[ -z "$error_threshold" || "$error_threshold" == "null" ]] && error_threshold=5
144
+
145
+ # Adaptive monitor: use historical baselines if available
146
+ local repo_hash
147
+ repo_hash=$(echo "${PROJECT_ROOT:-$(pwd)}" | cksum | awk '{print $1}')
148
+ local baseline_file="${HOME}/.shipwright/baselines/${repo_hash}/deploy-monitor.json"
149
+ if [[ -f "$baseline_file" ]]; then
150
+ local hist_duration hist_threshold
151
+ hist_duration=$(jq -r '.p90_stabilization_minutes // empty' "$baseline_file" 2>/dev/null || true)
152
+ hist_threshold=$(jq -r '.p90_error_threshold // empty' "$baseline_file" 2>/dev/null || true)
153
+ if [[ -n "$hist_duration" && "$hist_duration" != "null" ]]; then
154
+ duration_minutes="$hist_duration"
155
+ info "Monitor duration: ${duration_minutes}m ${DIM}(from baseline)${RESET}"
156
+ fi
157
+ if [[ -n "$hist_threshold" && "$hist_threshold" != "null" ]]; then
158
+ error_threshold="$hist_threshold"
159
+ info "Error threshold: ${error_threshold} ${DIM}(from baseline)${RESET}"
160
+ fi
161
+ fi
162
+ log_pattern=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.log_pattern) // "ERROR|FATAL|PANIC"' "$PIPELINE_CONFIG" 2>/dev/null) || true
163
+ [[ -z "$log_pattern" || "$log_pattern" == "null" ]] && log_pattern="ERROR|FATAL|PANIC"
164
+ log_cmd=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.log_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
165
+ [[ "$log_cmd" == "null" ]] && log_cmd=""
166
+ rollback_cmd=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.rollback_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
167
+ [[ "$rollback_cmd" == "null" ]] && rollback_cmd=""
168
+ auto_rollback=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.auto_rollback) // false' "$PIPELINE_CONFIG" 2>/dev/null) || true
169
+ [[ -z "$auto_rollback" || "$auto_rollback" == "null" ]] && auto_rollback="false"
170
+
171
+ if [[ -z "$health_url" && -z "$log_cmd" ]]; then
172
+ warn "No health_url or log_cmd configured — skipping monitor stage"
173
+ log_stage "monitor" "Skipped (no monitoring configured)"
174
+ return 0
175
+ fi
176
+
177
+ local report_file="$ARTIFACTS_DIR/monitor-report.md"
178
+ local deploy_log_file="$ARTIFACTS_DIR/deploy-logs.txt"
179
+ : > "$deploy_log_file"
180
+ local total_errors=0
181
+ local poll_interval=30 # seconds between polls
182
+ local total_polls=$(( (duration_minutes * 60) / poll_interval ))
183
+ [[ "$total_polls" -lt 1 ]] && total_polls=1
184
+
185
+ info "Post-deploy monitoring: ${duration_minutes}m (${total_polls} polls, threshold: ${error_threshold} errors)"
186
+
187
+ emit_event "monitor.started" \
188
+ "issue=${ISSUE_NUMBER:-0}" \
189
+ "duration_minutes=$duration_minutes" \
190
+ "error_threshold=$error_threshold"
191
+
192
+ {
193
+ echo "# Post-Deploy Monitor Report"
194
+ echo ""
195
+ echo "- Duration: ${duration_minutes} minutes"
196
+ echo "- Health URL: ${health_url:-none}"
197
+ echo "- Log command: ${log_cmd:-none}"
198
+ echo "- Error threshold: ${error_threshold}"
199
+ echo "- Auto-rollback: ${auto_rollback}"
200
+ echo ""
201
+ echo "## Poll Results"
202
+ echo ""
203
+ } > "$report_file"
204
+
205
+ local poll=0
206
+ local health_failures=0
207
+ local log_errors=0
208
+ while [[ "$poll" -lt "$total_polls" ]]; do
209
+ poll=$((poll + 1))
210
+ local poll_time
211
+ poll_time=$(now_iso)
212
+
213
+ # Health URL check
214
+ if [[ -n "$health_url" ]]; then
215
+ local http_status
216
+ http_status=$(curl -sf -o /dev/null -w "%{http_code}" "$health_url" 2>/dev/null || echo "000")
217
+ if [[ "$http_status" -ge 200 && "$http_status" -lt 400 ]]; then
218
+ echo "- [${poll_time}] Health: ✅ (HTTP ${http_status})" >> "$report_file"
219
+ else
220
+ health_failures=$((health_failures + 1))
221
+ total_errors=$((total_errors + 1))
222
+ echo "- [${poll_time}] Health: ❌ (HTTP ${http_status})" >> "$report_file"
223
+ warn "Health check failed: HTTP ${http_status}"
224
+ fi
225
+ fi
226
+
227
+ # Log command check (accumulate deploy logs for feedback collect)
228
+ if [[ -n "$log_cmd" ]]; then
229
+ local log_output
230
+ log_output=$(bash -c "$log_cmd" 2>/dev/null || true)
231
+ [[ -n "$log_output" ]] && echo "$log_output" >> "$deploy_log_file"
232
+ local error_count=0
233
+ if [[ -n "$log_output" ]]; then
234
+ error_count=$(echo "$log_output" | grep -cE "$log_pattern" 2>/dev/null || true)
235
+ error_count="${error_count:-0}"
236
+ fi
237
+ if [[ "$error_count" -gt 0 ]]; then
238
+ log_errors=$((log_errors + error_count))
239
+ total_errors=$((total_errors + error_count))
240
+ echo "- [${poll_time}] Logs: ⚠️ ${error_count} error(s) matching '${log_pattern}'" >> "$report_file"
241
+ warn "Log errors detected: ${error_count}"
242
+ else
243
+ echo "- [${poll_time}] Logs: ✅ clean" >> "$report_file"
244
+ fi
245
+ fi
246
+
247
+ emit_event "monitor.check" \
248
+ "issue=${ISSUE_NUMBER:-0}" \
249
+ "poll=$poll" \
250
+ "total_errors=$total_errors" \
251
+ "health_failures=$health_failures"
252
+
253
+ # Check threshold
254
+ if [[ "$total_errors" -ge "$error_threshold" ]]; then
255
+ error "Error threshold exceeded: ${total_errors} >= ${error_threshold}"
256
+
257
+ echo "" >> "$report_file"
258
+ echo "## ❌ THRESHOLD EXCEEDED" >> "$report_file"
259
+ echo "Total errors: ${total_errors} (threshold: ${error_threshold})" >> "$report_file"
260
+
261
+ emit_event "monitor.alert" \
262
+ "issue=${ISSUE_NUMBER:-0}" \
263
+ "total_errors=$total_errors" \
264
+ "threshold=$error_threshold"
265
+
266
+ # Feedback loop: collect deploy logs and optionally create issue
267
+ if [[ -f "$deploy_log_file" ]] && [[ -s "$deploy_log_file" ]] && [[ -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
268
+ (cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" collect "$deploy_log_file" 2>/dev/null) || true
269
+ (cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" create-issue 2>/dev/null) || true
270
+ fi
271
+
272
+ # Auto-rollback: feedback rollback (GitHub Deployments API) and/or config rollback_cmd
273
+ if [[ "$auto_rollback" == "true" ]]; then
274
+ warn "Auto-rolling back..."
275
+ echo "" >> "$report_file"
276
+ echo "## Rollback" >> "$report_file"
277
+
278
+ # Trigger feedback rollback (calls sw-github-deploy.sh rollback)
279
+ if [[ -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
280
+ (cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" rollback production "Monitor threshold exceeded (${total_errors} errors)" >> "$report_file" 2>&1) || true
281
+ fi
282
+
283
+ if [[ -n "$rollback_cmd" ]] && bash -c "$rollback_cmd" >> "$report_file" 2>&1; then
284
+ success "Rollback executed"
285
+ echo "Rollback: ✅ success" >> "$report_file"
286
+
287
+ # Post-rollback smoke test verification
288
+ local smoke_cmd
289
+ smoke_cmd=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.smoke_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
290
+ [[ "$smoke_cmd" == "null" ]] && smoke_cmd=""
291
+
292
+ if [[ -n "$smoke_cmd" ]]; then
293
+ info "Verifying rollback with smoke tests..."
294
+ if bash -c "$smoke_cmd" > "$ARTIFACTS_DIR/rollback-smoke.log" 2>&1; then
295
+ success "Rollback verified — smoke tests pass"
296
+ echo "Rollback verification: ✅ smoke tests pass" >> "$report_file"
297
+ emit_event "monitor.rollback_verified" \
298
+ "issue=${ISSUE_NUMBER:-0}" \
299
+ "status=pass"
300
+ else
301
+ error "Rollback verification FAILED — smoke tests still failing"
302
+ echo "Rollback verification: ❌ smoke tests FAILED — manual intervention required" >> "$report_file"
303
+ emit_event "monitor.rollback_verified" \
304
+ "issue=${ISSUE_NUMBER:-0}" \
305
+ "status=fail"
306
+ if [[ -n "$ISSUE_NUMBER" ]]; then
307
+ gh_comment_issue "$ISSUE_NUMBER" "🚨 **Rollback executed but verification failed** — smoke tests still failing after rollback. Manual intervention required.
308
+
309
+ Smoke command: \`${smoke_cmd}\`
310
+ Log: see \`pipeline-artifacts/rollback-smoke.log\`" 2>/dev/null || true
311
+ fi
312
+ fi
313
+ fi
314
+ else
315
+ error "Rollback failed!"
316
+ echo "Rollback: ❌ failed" >> "$report_file"
317
+ fi
318
+
319
+ emit_event "monitor.rollback" \
320
+ "issue=${ISSUE_NUMBER:-0}" \
321
+ "total_errors=$total_errors"
322
+
323
+ # Post to GitHub
324
+ if [[ -n "$ISSUE_NUMBER" ]]; then
325
+ gh_comment_issue "$ISSUE_NUMBER" "🚨 **Auto-rollback triggered** — ${total_errors} errors exceeded threshold (${error_threshold})
326
+
327
+ Rollback command: \`${rollback_cmd}\`" 2>/dev/null || true
328
+
329
+ # Create hotfix issue
330
+ if [[ "$GH_AVAILABLE" == "true" ]]; then
331
+ gh issue create \
332
+ --title "Hotfix: Deploy regression for ${GOAL}" \
333
+ --label "hotfix,incident" \
334
+ --body "Auto-rollback triggered during post-deploy monitoring.
335
+
336
+ **Original issue:** ${GITHUB_ISSUE:-N/A}
337
+ **Errors detected:** ${total_errors}
338
+ **Threshold:** ${error_threshold}
339
+ **Branch:** ${GIT_BRANCH}
340
+
341
+ ## Monitor Report
342
+ $(cat "$report_file")
343
+
344
+ ---
345
+ _Created automatically by \`shipwright pipeline\` monitor stage_" 2>/dev/null || true
346
+ fi
347
+ fi
348
+ fi
349
+
350
+ log_stage "monitor" "Failed — ${total_errors} errors (threshold: ${error_threshold})"
351
+ return 1
352
+ fi
353
+
354
+ # Sleep between polls (skip on last poll)
355
+ if [[ "$poll" -lt "$total_polls" ]]; then
356
+ sleep "$poll_interval"
357
+ fi
358
+ done
359
+
360
+ # Monitoring complete — all clear
361
+ echo "" >> "$report_file"
362
+ echo "## ✅ Monitoring Complete" >> "$report_file"
363
+ echo "Total errors: ${total_errors} (threshold: ${error_threshold})" >> "$report_file"
364
+ echo "Health failures: ${health_failures}" >> "$report_file"
365
+ echo "Log errors: ${log_errors}" >> "$report_file"
366
+
367
+ success "Post-deploy monitoring clean (${total_errors} errors in ${duration_minutes}m)"
368
+
369
+ # Proactive feedback collection: always collect deploy logs for trend analysis
370
+ if [[ -f "$deploy_log_file" ]] && [[ -s "$deploy_log_file" ]] && [[ -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
371
+ (cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" collect "$deploy_log_file" 2>/dev/null) || true
372
+ fi
373
+
374
+ if [[ -n "$ISSUE_NUMBER" ]]; then
375
+ gh_comment_issue "$ISSUE_NUMBER" "✅ **Post-deploy monitoring passed** — ${duration_minutes}m, ${total_errors} errors" 2>/dev/null || true
376
+ fi
377
+
378
+ log_stage "monitor" "Clean — ${total_errors} errors in ${duration_minutes}m"
379
+
380
+ # Record baseline for adaptive monitoring on future runs
381
+ local baseline_dir="${HOME}/.shipwright/baselines/${repo_hash}"
382
+ mkdir -p "$baseline_dir" 2>/dev/null || true
383
+ local baseline_tmp
384
+ baseline_tmp="$(mktemp)"
385
+ if [[ -f "${baseline_dir}/deploy-monitor.json" ]]; then
386
+ # Append to history and recalculate p90
387
+ jq --arg dur "$duration_minutes" --arg errs "$total_errors" \
388
+ '.history += [{"duration_minutes": ($dur | tonumber), "errors": ($errs | tonumber)}] |
389
+ .p90_stabilization_minutes = ([.history[].duration_minutes] | sort | .[length * 9 / 10 | floor]) |
390
+ .p90_error_threshold = (([.history[].errors] | sort | .[length * 9 / 10 | floor]) + 2) |
391
+ .updated_at = now' \
392
+ "${baseline_dir}/deploy-monitor.json" > "$baseline_tmp" 2>/dev/null && \
393
+ mv "$baseline_tmp" "${baseline_dir}/deploy-monitor.json" || rm -f "$baseline_tmp"
394
+ else
395
+ jq -n --arg dur "$duration_minutes" --arg errs "$total_errors" \
396
+ '{history: [{"duration_minutes": ($dur | tonumber), "errors": ($errs | tonumber)}],
397
+ p90_stabilization_minutes: ($dur | tonumber),
398
+ p90_error_threshold: (($errs | tonumber) + 2),
399
+ updated_at: now}' \
400
+ > "$baseline_tmp" 2>/dev/null && \
401
+ mv "$baseline_tmp" "${baseline_dir}/deploy-monitor.json" || rm -f "$baseline_tmp"
402
+ fi
403
+ }
404
+
405
+ # ─── Multi-Dimensional Quality Checks ─────────────────────────────────────
406
+ # Beyond tests: security, bundle size, perf regression, API compat, coverage
407
+