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,427 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ root-cause — Failure Root Cause Classification & Platform Issue Auto-Create
4
+ # ║
5
+ # ║ Categorizes pipeline failures into systematic root cause types:
6
+ # ║ - code_bug: User code problems (test failures, syntax errors)
7
+ # ║ - infra_issue: Infrastructure problems (timeouts, disk, network)
8
+ # ║ - rate_limit: API rate limiting (Claude, GitHub)
9
+ # ║ - context_exhaustion: Claude context window exceeded
10
+ # ║ - platform_bug: Shipwright script errors, missing functions
11
+ # ║ - config_error: Invalid pipeline/environment configuration
12
+ # ║ - external_dep: Dependency failures (npm, pip, cargo, etc.)
13
+ # ║
14
+ # ║ Auto-creates GitHub issues for platform bugs (confidence >70%)
15
+ # ║ Records classification patterns for learning
16
+ # ║ Provides automated fix suggestions and MTTR analytics
17
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
18
+ set -euo pipefail
19
+
20
+ VERSION="3.3.0"
21
+
22
+ # Module guard
23
+ [[ -n "${_ROOT_CAUSE_LOADED:-}" ]] && return 0; _ROOT_CAUSE_LOADED=1
24
+
25
+ # ─── Defaults ──────────────────────────────────────────────────────────────
26
+ SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
27
+ REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
28
+ PROJECT_ROOT="${PROJECT_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
29
+ STATE_DIR="${STATE_DIR:-$PROJECT_ROOT/.claude}"
30
+ ARTIFACTS_DIR="${ARTIFACTS_DIR:-$STATE_DIR/pipeline-artifacts}"
31
+ NO_GITHUB="${NO_GITHUB:-}"
32
+
33
+ # Ensure helpers are loaded
34
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh" 2>/dev/null || true
35
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo "$*"; }
36
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo "$*" >&2; }
37
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo "$*" >&2; }
38
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo "$*"; }
39
+ [[ "$(type -t emit_event 2>/dev/null)" == "function" ]] || emit_event() { true; }
40
+
41
+ # ═══════════════════════════════════════════════════════════════════════════════
42
+ # Classify a failure into root cause categories
43
+ # ═══════════════════════════════════════════════════════════════════════════════
44
+
45
+ rootcause_classify() {
46
+ local error_message="${1:-}"
47
+ local stage="${2:-unknown}"
48
+ local exit_code="${3:-1}"
49
+
50
+ [[ -z "$error_message" ]] && { echo '{"category":"unknown","confidence":0,"evidence":[],"suggested_action":"Review error logs"}'; return 0; }
51
+
52
+ local category="unknown"
53
+ local confidence=0
54
+ local evidence=()
55
+
56
+ # ─── Rate Limit Detection ───────────────────────────────────────────────────
57
+ if echo "$error_message" | grep -qiE '(rate limit|429|too many requests|throttled|limited|quota|backoff)'; then
58
+ category="rate_limit"
59
+ confidence=95
60
+ evidence+=("Explicit rate limit message detected")
61
+ [[ "$error_message" =~ claude ]] && evidence+=("Claude API rate limit")
62
+ [[ "$error_message" =~ github ]] && evidence+=("GitHub API rate limit")
63
+ # ─── Context Exhaustion ──────────────────────────────────────────────────────
64
+ elif echo "$error_message" | grep -qiE '(context window|context.*exceed|token.*limit|auto-compact|maximum context|context.*exhaust)'; then
65
+ category="context_exhaustion"
66
+ confidence=90
67
+ evidence+=("Context window exhaustion detected")
68
+ # ─── Infrastructure Issues ───────────────────────────────────────────────────
69
+ elif echo "$error_message" | grep -qiE '(timeout|timed out|ETIMEDOUT|ECONNREFUSED|ECONNRESET|network|socket hang|OOM|out of memory|killed|signal 9|cannot allocate|disk full|no space|ENOMEM|ENOSPC)'; then
70
+ category="infra_issue"
71
+ confidence=85
72
+ evidence+=("Infrastructure problem detected")
73
+ [[ "$error_message" =~ timeout ]] && evidence+=("Timeout detected")
74
+ [[ "$error_message" =~ OOM|memory ]] && evidence+=("Memory exhaustion")
75
+ [[ "$error_message" =~ disk|space ]] && evidence+=("Disk space issue")
76
+ [[ "$error_message" =~ network|socket ]] && evidence+=("Network issue")
77
+ # ─── Platform Bugs (Shipwright errors) ──────────────────────────────────────
78
+ elif echo "$error_message" | grep -qiE '(sw-.*\.sh|shipwright|unbound variable|command not found.*sw-|pipeline-state|unexpected end)'; then
79
+ category="platform_bug"
80
+ confidence=80
81
+ evidence+=("Shipwright platform error detected")
82
+ [[ "$error_message" =~ unbound ]] && evidence+=("Unbound variable in Shipwright code")
83
+ [[ "$error_message" =~ "command not found" ]] && evidence+=("Missing Shipwright function or script")
84
+ # ─── Configuration Errors ───────────────────────────────────────────────────
85
+ elif echo "$error_message" | grep -qiE '(missing.*config|invalid.*json|PIPELINE_CONFIG|no such template|bad config|invalid.*template|unknown.*option)'; then
86
+ category="config_error"
87
+ confidence=85
88
+ evidence+=("Configuration error detected")
89
+ [[ "$error_message" =~ config ]] && evidence+=("Missing or invalid configuration")
90
+ [[ "$error_message" =~ template ]] && evidence+=("Unknown pipeline template")
91
+ # ─── External Dependency Failures ───────────────────────────────────────────
92
+ elif echo "$error_message" | grep -qiE '(npm ERR|pip.*install|gem.*install|cargo.*error|go.*get|npm:.*not found|cannot find module|dependency.*fail)'; then
93
+ category="external_dep"
94
+ confidence=80
95
+ evidence+=("Dependency installation failure")
96
+ [[ "$error_message" =~ npm ]] && evidence+=("npm dependency issue")
97
+ [[ "$error_message" =~ pip ]] && evidence+=("Python pip issue")
98
+ [[ "$error_message" =~ cargo ]] && evidence+=("Rust cargo issue")
99
+ # ─── Code Bug Detection ──────────────────────────────────────────────────────
100
+ elif echo "$error_message" | grep -qiE '(AssertionError|assert.*fail|Expected.*but.*got|TypeError|ReferenceError|SyntaxError|CompileError|type mismatch|cannot assign|incompatible type|FAILED.*test|Test.*failed|test.*fail)'; then
101
+ category="code_bug"
102
+ confidence=85
103
+ evidence+=("Code logic error detected")
104
+ [[ "$exit_code" != "0" ]] && evidence+=("Non-zero exit code")
105
+ [[ "$stage" == "test" ]] && evidence+=("Failure in test stage")
106
+ fi
107
+
108
+ # ─── Default to code_bug if no match ────────────────────────────────────────
109
+ if [[ "$category" == "unknown" ]]; then
110
+ category="code_bug"
111
+ confidence=45
112
+ evidence+=("No infrastructure/platform patterns detected; likely user code issue")
113
+ fi
114
+
115
+ # Output JSON result
116
+ printf '{"category":"%s","confidence":%d,"evidence":%s,"suggested_action":"See rootcause_suggest_fix"}\n' \
117
+ "$category" "$confidence" "$(printf '"%s"' "${evidence[@]}" | jq -Rs 'split("\n") | map(select(length > 0))')"
118
+ }
119
+
120
+ # ═══════════════════════════════════════════════════════════════════════════════
121
+ # Analyze error-log.jsonl for error patterns
122
+ # ═══════════════════════════════════════════════════════════════════════════════
123
+
124
+ rootcause_analyze_error_log() {
125
+ local error_log="${ARTIFACTS_DIR}/error-log.jsonl"
126
+ [[ ! -f "$error_log" ]] && { echo '{"patterns_analyzed":0,"top_categories":[],"summary":"No error log found"}'; return 0; }
127
+
128
+ local tmp_dir
129
+ tmp_dir=$(mktemp -d) || return 1
130
+ trap "rm -rf '$tmp_dir'" RETURN
131
+
132
+ # Analyze each error entry and collect classifications
133
+ local classifications="$tmp_dir/classifications.json"
134
+ > "$classifications"
135
+
136
+ local entry_count=0
137
+ while IFS= read -r line; do
138
+ [[ -z "$line" ]] && continue
139
+ local error_msg
140
+ error_msg=$(echo "$line" | jq -r '.error // .message // .' 2>/dev/null || echo "$line")
141
+ [[ -z "$error_msg" || "$error_msg" == "null" ]] && continue
142
+
143
+ local classification
144
+ classification=$(rootcause_classify "$error_msg" "unknown" "1" 2>/dev/null || echo '{}')
145
+ echo "$classification" >> "$classifications"
146
+ entry_count=$((entry_count + 1))
147
+ done < <(tail -50 "$error_log" 2>/dev/null)
148
+
149
+ # Count patterns by category
150
+ local summary
151
+ if [[ "$entry_count" -gt 0 ]]; then
152
+ summary=$(jq -s '[.[] | .category] | group_by(.) | map({category: .[0], count: length}) | sort_by(-.count)' "$classifications" 2>/dev/null || echo "[]")
153
+ else
154
+ summary="[]"
155
+ fi
156
+
157
+ # Safely output JSON
158
+ echo '{"patterns_analyzed":'$entry_count',"top_categories":'$summary',"summary":"Analysis complete"}'
159
+ }
160
+
161
+ # ═══════════════════════════════════════════════════════════════════════════════
162
+ # Create GitHub issue for platform bugs
163
+ # ═══════════════════════════════════════════════════════════════════════════════
164
+
165
+ rootcause_create_platform_issue() {
166
+ local classification_json="${1:-}"
167
+ local error_message="${2:-}"
168
+ local stage="${3:-unknown}"
169
+
170
+ [[ -n "$NO_GITHUB" ]] && { info "Skipping GitHub issue creation (NO_GITHUB set)"; return 0; }
171
+ [[ ! -x "$(command -v gh 2>/dev/null)" ]] && { warn "gh CLI not found, cannot create issue"; return 1; }
172
+
173
+ # Parse classification
174
+ local category confidence
175
+ category=$(echo "$classification_json" | jq -r '.category // "unknown"' 2>/dev/null || echo "unknown")
176
+ confidence=$(echo "$classification_json" | jq -r '.confidence // 0' 2>/dev/null || echo "0")
177
+
178
+ # Only create issues for high-confidence platform/config errors
179
+ if [[ ! "$category" =~ ^(platform_bug|config_error)$ ]] || [[ "$confidence" -lt 70 ]]; then
180
+ info "Skipping issue creation: category=$category, confidence=$confidence (threshold: platform_bug|config_error with >70%)"
181
+ return 0
182
+ fi
183
+
184
+ # Check for duplicate issues first
185
+ local error_sig
186
+ error_sig=$(echo "$error_message" | cksum | awk '{print $1}')
187
+ local existing_issues
188
+ existing_issues=$(gh issue list --state open --search "error-sig:$error_sig" --limit 1 2>/dev/null || true)
189
+
190
+ if [[ -n "$existing_issues" ]]; then
191
+ info "Duplicate issue already exists for error signature $error_sig"
192
+ echo "$existing_issues" | grep -oE '#[0-9]+' | head -1
193
+ return 0
194
+ fi
195
+
196
+ # Build issue body with context
197
+ local pipeline_config="unknown"
198
+ [[ -f "$STATE_DIR/pipeline-config.json" ]] && pipeline_config=$(cat "$STATE_DIR/pipeline-config.json" | head -20)
199
+
200
+ local issue_title="[PLATFORM BUG] $category in $stage stage"
201
+ local issue_body="## Root Cause Classification
202
+
203
+ **Category:** \`$category\`
204
+ **Confidence:** $confidence%
205
+ **Stage:** $stage
206
+ **Error Signature:** \`$error_sig\`
207
+
208
+ ## Error Message
209
+ \`\`\`
210
+ $(echo "$error_message" | head -20)
211
+ \`\`\`
212
+
213
+ ## Pipeline Configuration
214
+ \`\`\`json
215
+ $pipeline_config
216
+ \`\`\`
217
+
218
+ ## System Info
219
+ - Shipwright version: $VERSION
220
+ - Pipeline state: see .claude/pipeline-state.md
221
+ - Error log: see .claude/pipeline-artifacts/error-log.jsonl
222
+
223
+ ## Auto-Created
224
+ This issue was automatically created by Shipwright's root cause classifier.
225
+ If this is not a platform bug, please close with \`resolution:not-our-bug\`.
226
+ If you've fixed this, tag it with \`resolved\`.
227
+
228
+ ---
229
+ error-sig: $error_sig
230
+ "
231
+
232
+ # Create the issue
233
+ local issue_url
234
+ issue_url=$(gh issue create \
235
+ --title "$issue_title" \
236
+ --body "$issue_body" \
237
+ --label "platform-bug,auto-created" \
238
+ 2>/dev/null || echo "")
239
+
240
+ if [[ -n "$issue_url" ]]; then
241
+ success "Created platform bug issue: $issue_url"
242
+ echo "$issue_url" | grep -oE '#[0-9]+' | tr -d '#'
243
+ emit_event "rootcause.platform_issue_created" "error_sig=$error_sig" "issue=$issue_url"
244
+ return 0
245
+ fi
246
+
247
+ warn "Failed to create GitHub issue"
248
+ return 1
249
+ }
250
+
251
+ # ═══════════════════════════════════════════════════════════════════════════════
252
+ # Suggest automated fixes by category
253
+ # ═══════════════════════════════════════════════════════════════════════════════
254
+
255
+ rootcause_suggest_fix() {
256
+ local category="${1:-unknown}"
257
+ local error_message="${2:-}"
258
+ local stage="${3:-unknown}"
259
+
260
+ local suggestions=""
261
+ local actionability=0
262
+
263
+ case "$category" in
264
+ rate_limit)
265
+ suggestions="Rate limit detected. Suggested fixes: Wait and retry with exponential backoff, check API quota with shipwright cost show, reduce concurrency in daemon-config.json, time-shift pipeline execution to off-peak hours"
266
+ actionability=85
267
+ ;;
268
+ context_exhaustion)
269
+ suggestions="Context window exhausted. Suggested fixes: Increase max-restarts for fresh session, reduce codebase context via .claudeignore, simplify pipeline goal or break into subtasks, check memory usage with shipwright memory show"
270
+ actionability=75
271
+ ;;
272
+ infra_issue)
273
+ suggestions="Infrastructure problem. Suggested fixes: Check disk space with df -h, check memory with free -h or vm_stat, check network connectivity with ping github.com, restart daemon, check system load with uptime"
274
+ actionability=70
275
+ ;;
276
+ platform_bug)
277
+ suggestions="Shipwright platform bug. Suggested fixes: Check .claude/pipeline-state.md for context, run shipwright doctor to validate setup, review recent changes with git log, check .claude/hooks for interfering hooks, upgrade with shipwright upgrade"
278
+ actionability=80
279
+ ;;
280
+ config_error)
281
+ suggestions="Configuration error. Suggested fixes: Run shipwright doctor to validate setup, check .claude/daemon-config.json for syntax errors, verify environment variables, check pipeline template exists, review .claudeignore and .claude/rules"
282
+ actionability=90
283
+ ;;
284
+ external_dep)
285
+ suggestions="External dependency failure. Suggested fixes: Clear dependency cache, retry install with npm install or pip install, check package registry health, increase timeout for slow networks, try offline mirror or alternative registry"
286
+ actionability=75
287
+ ;;
288
+ code_bug)
289
+ suggestions="Code logic error in user code. Suggested fixes: Review test output in .claude/pipeline-artifacts, check recent commits with git diff, run tests locally, enable debug logging for the stage, use shipwright loop with debug mode"
290
+ actionability=65
291
+ ;;
292
+ *)
293
+ suggestions="Unknown error. Start debugging: Check error logs in .claude/pipeline-artifacts, run shipwright doctor for setup validation, enable verbose logging with DEBUG=1, review pipeline state with shipwright status"
294
+ actionability=50
295
+ ;;
296
+ esac
297
+
298
+ # Use jq to safely create JSON with proper escaping
299
+ jq -n --arg cat "$category" --arg sug "$suggestions" --arg act "$actionability" \
300
+ '{category: $cat, suggestions: $sug, actionability: ($act | tonumber)}'
301
+ }
302
+
303
+ # ═══════════════════════════════════════════════════════════════════════════════
304
+ # Feed classified failures into learning system
305
+ # ═══════════════════════════════════════════════════════════════════════════════
306
+
307
+ rootcause_learn() {
308
+ local category="${1:-unknown}"
309
+ local confidence="${2:-0}"
310
+ local error_message="${3:-}"
311
+
312
+ local learn_file="${HOME}/.shipwright/optimization/root-causes.jsonl"
313
+ mkdir -p "${HOME}/.shipwright/optimization" 2>/dev/null || return 1
314
+
315
+ local entry
316
+ entry=$(jq -c -n \
317
+ --arg cat "$category" \
318
+ --arg conf "$confidence" \
319
+ --arg msg "$(echo "$error_message" | head -c 200)" \
320
+ --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
321
+ '{category: $cat, confidence: ($conf | tonumber), message: $msg, recorded_at: $ts}')
322
+
323
+ # Atomic append
324
+ local tmp_learn
325
+ tmp_learn=$(mktemp) || return 1
326
+ echo "$entry" >> "$tmp_learn"
327
+ cat "$learn_file" >> "$tmp_learn" 2>/dev/null || true
328
+ mv "$tmp_learn" "$learn_file" 2>/dev/null || { rm -f "$tmp_learn"; return 1; }
329
+ chmod 600 "$learn_file" 2>/dev/null || true
330
+
331
+ emit_event "rootcause.learned" "category=$category" "confidence=$confidence"
332
+ }
333
+
334
+ # ═══════════════════════════════════════════════════════════════════════════════
335
+ # Generate root cause report
336
+ # ═══════════════════════════════════════════════════════════════════════════════
337
+
338
+ rootcause_report() {
339
+ local learn_file="${HOME}/.shipwright/optimization/root-causes.jsonl"
340
+ [[ ! -f "$learn_file" ]] && { info "No root cause history yet"; return 0; }
341
+
342
+ local total_entries
343
+ total_entries=$(wc -l < "$learn_file" 2>/dev/null || echo "0")
344
+
345
+ # Category distribution
346
+ local dist
347
+ dist=$(jq -s 'group_by(.category) | map({category: .[0].category, count: length}) | sort_by(-.count)' "$learn_file" 2>/dev/null || echo "[]")
348
+
349
+ # Top 5 most frequent root causes (by message)
350
+ local top_5
351
+ top_5=$(jq -s 'group_by(.message) | map({message: .[0].message, category: .[0].category, occurrences: length}) | sort_by(-.occurrences) | .[0:5]' "$learn_file" 2>/dev/null || echo "[]")
352
+
353
+ # Trend: are platform bugs increasing?
354
+ local platform_bugs_1d platform_bugs_7d
355
+ platform_bugs_1d=$(jq -s --arg cutoff "$(date -u -d '1 day ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-1d +%Y-%m-%dT%H:%M:%SZ)" \
356
+ "[.[] | select(.recorded_at > \$cutoff and .category == \"platform_bug\")] | length" "$learn_file" 2>/dev/null || echo "0")
357
+ platform_bugs_7d=$(jq -s --arg cutoff "$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)" \
358
+ "[.[] | select(.recorded_at > \$cutoff and .category == \"platform_bug\")] | length" "$learn_file" 2>/dev/null || echo "0")
359
+
360
+ # MTTR by category
361
+ local mttr_by_cat
362
+ mttr_by_cat=$(jq -s 'group_by(.category) | map({category: .[0].category, avg_confidence: (map(.confidence) | add / length)}) | sort_by(-.avg_confidence)' "$learn_file" 2>/dev/null || echo "[]")
363
+
364
+ {
365
+ echo "═══════════════════════════════════════════════════════════════════════════"
366
+ echo " Root Cause Analysis Report"
367
+ echo "═══════════════════════════════════════════════════════════════════════════"
368
+ echo ""
369
+ echo "Total analyzed failures: $total_entries"
370
+ echo ""
371
+ echo "─── Category Distribution ───────────────────────────────────────────────────"
372
+ echo "$dist" | jq -r '.[] | " \(.category): \(.count) occurrences"'
373
+ echo ""
374
+ echo "─── Top 5 Most Frequent Root Causes ──────────────────────────────────────"
375
+ echo "$top_5" | jq -r '.[] | " [\(.category)] \(.occurrences)x: \(.message | .[0:70])"'
376
+ echo ""
377
+ echo "─── Platform Bug Trend ───────────────────────────────────────────────────"
378
+ echo " Last 24h: $platform_bugs_1d platform bugs"
379
+ echo " Last 7d: $platform_bugs_7d platform bugs"
380
+ [[ "$platform_bugs_7d" -gt 0 ]] && {
381
+ local trend
382
+ trend=$((platform_bugs_1d * 100 / platform_bugs_7d))
383
+ [[ "$trend" -gt 100 ]] && echo " ⚠️ INCREASING trend!" || echo " ✓ Decreasing or stable"
384
+ }
385
+ echo ""
386
+ echo "─── Average Confidence by Category ───────────────────────────────────────"
387
+ echo "$mttr_by_cat" | jq -r '.[] | " \(.category): \(.avg_confidence | round)% confidence"'
388
+ echo ""
389
+ echo "═══════════════════════════════════════════════════════════════════════════"
390
+ }
391
+ }
392
+
393
+ # ═══════════════════════════════════════════════════════════════════════════════
394
+ # Main entry point: Classify and optionally create issue
395
+ # ═══════════════════════════════════════════════════════════════════════════════
396
+
397
+ rootcause_main() {
398
+ local error_message="${1:-}"
399
+ local stage="${2:-unknown}"
400
+ local exit_code="${3:-1}"
401
+
402
+ [[ -z "$error_message" ]] && { error "Usage: rootcause_main <error_message> [stage] [exit_code]"; return 1; }
403
+
404
+ # Classify the error
405
+ local classification
406
+ classification=$(rootcause_classify "$error_message" "$stage" "$exit_code")
407
+
408
+ # Extract category and confidence
409
+ local category confidence
410
+ category=$(echo "$classification" | jq -r '.category' 2>/dev/null || echo "unknown")
411
+ confidence=$(echo "$classification" | jq -r '.confidence' 2>/dev/null || echo "0")
412
+
413
+ # Suggest fix
414
+ local fix_suggestion
415
+ fix_suggestion=$(rootcause_suggest_fix "$category" "$error_message" "$stage")
416
+
417
+ # Learn from this failure
418
+ rootcause_learn "$category" "$confidence" "$error_message"
419
+
420
+ # Try to create issue for platform bugs
421
+ [[ "$category" =~ ^(platform_bug|config_error)$ ]] && [[ "$confidence" -gt 70 ]] && {
422
+ rootcause_create_platform_issue "$classification" "$error_message" "$stage" || true
423
+ }
424
+
425
+ # Output result
426
+ printf '{"classification":%s,"fix":%s}\n' "$classification" "$fix_suggestion"
427
+ }