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,649 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ shipwright lib/project-detect — Project type detection & template rec ║
4
+ # ║ Auto-detect project language, framework, test command, and pipeline ║
5
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
6
+ #
7
+ # Usage:
8
+ # source "$SCRIPT_DIR/lib/project-detect.sh"
9
+ # project_detect_type "/path/to/project" # Returns JSON with type/framework/build/test
10
+ # project_detect_all "/path/to/project" # Full detection report
11
+ # project_recommend_template "/path/to/project" # Returns JSON with template recommendation
12
+ #
13
+ # Provides:
14
+ # - project_detect_type(root) — Detect language + framework + package manager
15
+ # - project_detect_framework(root, type) — Detect specific framework
16
+ # - project_detect_test_cmd(root, type) — Detect test command
17
+ # - project_detect_build_cmd(root, type) — Detect build command
18
+ # - project_recommend_template(root) — Recommend pipeline template
19
+ # - project_detect_all(root) — Full detection report (cached)
20
+
21
+ [[ -n "${_PROJECT_DETECT_LOADED:-}" ]] && return 0
22
+ _PROJECT_DETECT_LOADED=1
23
+
24
+ # ─── Helper: Read JSON field safely ────────────────────────────────────────
25
+ _json_field() {
26
+ local json="$1" field="$2"
27
+ echo "$json" | jq -r ".${field} // empty" 2>/dev/null || echo ""
28
+ }
29
+
30
+ # ─── Helper: Count lines matching pattern ──────────────────────────────────
31
+ _count_pattern() {
32
+ local pattern="$1" path="$2"
33
+ grep -r "$pattern" "$path" 2>/dev/null | wc -l | tr -d ' '
34
+ }
35
+
36
+ # ─── Helper: Check file exists (safe for symlinks) ──────────────────────────
37
+ _has_file() {
38
+ local root="$1" file="$2"
39
+ [[ -f "$root/$file" ]]
40
+ }
41
+
42
+ # ─── Helper: Check any file matches glob ──────────────────────────────────
43
+ _has_glob() {
44
+ local root="$1" pattern="$2"
45
+ find "$root" -maxdepth 1 -name "$pattern" -type f 2>/dev/null | grep -q .
46
+ }
47
+
48
+ # ═══════════════════════════════════════════════════════════════════════════
49
+ # project_detect_type(root)
50
+ # ─────────────────────────────────────────────────────────────────────────────
51
+ # Detect primary language/type by checking for marker files in order
52
+ #
53
+ # Returns JSON: {
54
+ # "type": "nodejs|python|rust|golang|ruby|java|dotnet|c|bash",
55
+ # "framework": "react|next|express|django|actix|...|unknown",
56
+ # "build_tool": "npm|yarn|cargo|go|...",
57
+ # "test_runner": "jest|pytest|cargo test|..."
58
+ # }
59
+ project_detect_type() {
60
+ local root="${1:-.}"
61
+ [[ -d "$root" ]] || return 1
62
+
63
+ local type="" framework="" build_tool="" test_runner=""
64
+
65
+ # ── Node.js / JavaScript / TypeScript ──
66
+ if _has_file "$root" "package.json"; then
67
+ type="nodejs"
68
+
69
+ # Detect package manager first
70
+ if _has_file "$root" "pnpm-lock.yaml"; then
71
+ build_tool="pnpm"
72
+ elif _has_file "$root" "yarn.lock"; then
73
+ build_tool="yarn"
74
+ elif _has_file "$root" "bun.lockb"; then
75
+ build_tool="bun"
76
+ else
77
+ build_tool="npm"
78
+ fi
79
+
80
+ # Detect framework and test runner from package.json
81
+ local pkg
82
+ pkg=$(cat "$root/package.json" 2>/dev/null)
83
+
84
+ # Framework detection
85
+ if echo "$pkg" | grep -q '"next"'; then
86
+ framework="next"
87
+ elif echo "$pkg" | grep -q '"react"'; then
88
+ framework="react"
89
+ elif echo "$pkg" | grep -q '"vue"'; then
90
+ framework="vue"
91
+ elif echo "$pkg" | grep -q '"@angular/core"'; then
92
+ framework="angular"
93
+ elif echo "$pkg" | grep -q '"@nestjs/core"'; then
94
+ framework="nestjs"
95
+ elif echo "$pkg" | grep -q '"express"'; then
96
+ framework="express"
97
+ elif echo "$pkg" | grep -q '"fastify"'; then
98
+ framework="fastify"
99
+ elif echo "$pkg" | grep -q '"hono"'; then
100
+ framework="hono"
101
+ else
102
+ framework="unknown"
103
+ fi
104
+
105
+ # Test runner detection
106
+ if echo "$pkg" | grep -q '"vitest"'; then
107
+ test_runner="vitest"
108
+ elif echo "$pkg" | grep -q '"jest"'; then
109
+ test_runner="jest"
110
+ elif echo "$pkg" | grep -q '"mocha"'; then
111
+ test_runner="mocha"
112
+ elif echo "$pkg" | grep -q '"ava"'; then
113
+ test_runner="ava"
114
+ else
115
+ test_runner="unknown"
116
+ fi
117
+
118
+ # ── Rust ──
119
+ elif _has_file "$root" "Cargo.toml"; then
120
+ type="rust"
121
+ build_tool="cargo"
122
+ test_runner="cargo"
123
+
124
+ local cargo_content
125
+ cargo_content=$(cat "$root/Cargo.toml" 2>/dev/null)
126
+
127
+ if echo "$cargo_content" | grep -q "actix-web"; then
128
+ framework="actix-web"
129
+ elif echo "$cargo_content" | grep -q "axum"; then
130
+ framework="axum"
131
+ elif echo "$cargo_content" | grep -q "rocket"; then
132
+ framework="rocket"
133
+ else
134
+ framework="unknown"
135
+ fi
136
+
137
+ # ── Go ──
138
+ elif _has_file "$root" "go.mod"; then
139
+ type="golang"
140
+ build_tool="go"
141
+ test_runner="go test"
142
+
143
+ local go_content
144
+ go_content=$(cat "$root/go.mod" 2>/dev/null)
145
+
146
+ if echo "$go_content" | grep -q "gin-gonic/gin"; then
147
+ framework="gin"
148
+ elif echo "$go_content" | grep -q "labstack/echo"; then
149
+ framework="echo"
150
+ elif echo "$go_content" | grep -q "go-chi/chi"; then
151
+ framework="chi"
152
+ elif echo "$go_content" | grep -q "gofiber/fiber"; then
153
+ framework="fiber"
154
+ else
155
+ framework="unknown"
156
+ fi
157
+
158
+ # ── Python ──
159
+ elif _has_file "$root" "pyproject.toml" || _has_file "$root" "setup.py" || _has_file "$root" "requirements.txt"; then
160
+ type="python"
161
+ test_runner="pytest"
162
+
163
+ # Detect package manager
164
+ if _has_file "$root" "pyproject.toml"; then
165
+ local pyproject
166
+ pyproject=$(cat "$root/pyproject.toml" 2>/dev/null)
167
+ if echo "$pyproject" | grep -q "poetry"; then
168
+ build_tool="poetry"
169
+ elif echo "$pyproject" | grep -q "pdm"; then
170
+ build_tool="pdm"
171
+ else
172
+ build_tool="pip"
173
+ fi
174
+ else
175
+ build_tool="pip"
176
+ fi
177
+
178
+ # Framework detection
179
+ local py_deps=""
180
+ _has_file "$root" "requirements.txt" && py_deps=$(cat "$root/requirements.txt" 2>/dev/null)
181
+ _has_file "$root" "pyproject.toml" && py_deps="$py_deps$(cat "$root/pyproject.toml" 2>/dev/null)"
182
+
183
+ if echo "$py_deps" | grep -qi "django"; then
184
+ framework="django"
185
+ elif echo "$py_deps" | grep -qi "fastapi"; then
186
+ framework="fastapi"
187
+ elif echo "$py_deps" | grep -qi "flask"; then
188
+ framework="flask"
189
+ else
190
+ framework="unknown"
191
+ fi
192
+
193
+ # ── Ruby ──
194
+ elif _has_file "$root" "Gemfile"; then
195
+ type="ruby"
196
+ build_tool="bundler"
197
+
198
+ local gemfile
199
+ gemfile=$(cat "$root/Gemfile" 2>/dev/null)
200
+
201
+ if echo "$gemfile" | grep -q "rails"; then
202
+ framework="rails"
203
+ test_runner="rails test"
204
+ elif echo "$gemfile" | grep -q "rspec"; then
205
+ framework="unknown"
206
+ test_runner="rspec"
207
+ else
208
+ framework="unknown"
209
+ test_runner="minitest"
210
+ fi
211
+
212
+ # ── Java ──
213
+ elif _has_file "$root" "pom.xml"; then
214
+ type="java"
215
+ build_tool="maven"
216
+ test_runner="maven"
217
+
218
+ local pom
219
+ pom=$(cat "$root/pom.xml" 2>/dev/null)
220
+
221
+ if echo "$pom" | grep -q "spring-boot"; then
222
+ framework="spring-boot"
223
+ else
224
+ framework="unknown"
225
+ fi
226
+
227
+ elif _has_file "$root" "build.gradle" || _has_file "$root" "build.gradle.kts"; then
228
+ type="java"
229
+ build_tool="gradle"
230
+ test_runner="gradle"
231
+
232
+ local gradle_content
233
+ gradle_content=""
234
+ _has_file "$root" "build.gradle" && gradle_content=$(cat "$root/build.gradle" 2>/dev/null)
235
+ _has_file "$root" "build.gradle.kts" && gradle_content=$(cat "$root/build.gradle.kts" 2>/dev/null)
236
+
237
+ if echo "$gradle_content" | grep -q "spring-boot"; then
238
+ framework="spring-boot"
239
+ else
240
+ framework="unknown"
241
+ fi
242
+
243
+ # ── .NET ──
244
+ elif _has_glob "$root" "*.sln" || _has_glob "$root" "*.csproj"; then
245
+ type="dotnet"
246
+ build_tool="dotnet"
247
+ test_runner="dotnet test"
248
+ framework="unknown"
249
+
250
+ # ── C/C++ (Makefile only) ──
251
+ elif _has_file "$root" "Makefile"; then
252
+ type="c"
253
+ build_tool="make"
254
+ test_runner="make"
255
+ framework="unknown"
256
+
257
+ # ── Bash (shell scripts) ──
258
+ else
259
+ # Check if directory contains shell scripts
260
+ local shell_count
261
+ shell_count=$(find "$root" -maxdepth 2 -name "*.sh" -type f 2>/dev/null | wc -l | tr -d ' ')
262
+ if [[ "$shell_count" -gt 0 ]]; then
263
+ type="bash"
264
+ build_tool="bash"
265
+ test_runner="bash"
266
+ framework="unknown"
267
+ fi
268
+ fi
269
+
270
+ # Output JSON
271
+ if [[ -n "$type" ]]; then
272
+ jq -n \
273
+ --arg type "$type" \
274
+ --arg framework "${framework:-unknown}" \
275
+ --arg build_tool "${build_tool:-unknown}" \
276
+ --arg test_runner "${test_runner:-unknown}" \
277
+ '{type: $type, framework: $framework, build_tool: $build_tool, test_runner: $test_runner}'
278
+ else
279
+ return 1
280
+ fi
281
+ }
282
+
283
+ # ═══════════════════════════════════════════════════════════════════════════
284
+ # project_detect_test_cmd(root, type)
285
+ # ─────────────────────────────────────────────────────────────────────────────
286
+ # Detect the test command to run based on project type
287
+ #
288
+ # Returns string like "npm test" or "pytest" or "cargo test"
289
+ project_detect_test_cmd() {
290
+ local root="${1:-.}"
291
+ local type="${2:-}"
292
+ [[ -d "$root" ]] || return 1
293
+
294
+ # If type not provided, detect it
295
+ if [[ -z "$type" ]]; then
296
+ local detection
297
+ detection=$(project_detect_type "$root") || return 1
298
+ type=$(_json_field "$detection" "type")
299
+ fi
300
+
301
+ local test_cmd=""
302
+
303
+ case "$type" in
304
+ nodejs)
305
+ # Check package.json for test script
306
+ if [[ -f "$root/package.json" ]]; then
307
+ local has_test
308
+ has_test=$(jq -r '.scripts.test // ""' "$root/package.json" 2>/dev/null || echo "")
309
+ if [[ -n "$has_test" && "$has_test" != "null" && ! "$has_test" =~ "no test" ]]; then
310
+ # Determine package manager
311
+ if [[ -f "$root/pnpm-lock.yaml" ]]; then
312
+ test_cmd="pnpm test"
313
+ elif [[ -f "$root/yarn.lock" ]]; then
314
+ test_cmd="yarn test"
315
+ elif [[ -f "$root/bun.lockb" ]]; then
316
+ test_cmd="bun test"
317
+ else
318
+ test_cmd="npm test"
319
+ fi
320
+ fi
321
+ fi
322
+ ;;
323
+
324
+ python)
325
+ if [[ -f "$root/pyproject.toml" ]] && grep -q "pytest" "$root/pyproject.toml" 2>/dev/null; then
326
+ test_cmd="pytest"
327
+ elif [[ -d "$root/tests" ]]; then
328
+ test_cmd="pytest"
329
+ elif [[ -f "$root/setup.cfg" ]] && grep -q "test_suite" "$root/setup.cfg" 2>/dev/null; then
330
+ test_cmd="python -m unittest"
331
+ fi
332
+ ;;
333
+
334
+ rust)
335
+ test_cmd="cargo test"
336
+ ;;
337
+
338
+ golang)
339
+ test_cmd="go test ./..."
340
+ ;;
341
+
342
+ ruby)
343
+ if [[ -f "$root/Gemfile" ]]; then
344
+ local gemfile
345
+ gemfile=$(cat "$root/Gemfile" 2>/dev/null)
346
+ if echo "$gemfile" | grep -q "rails"; then
347
+ test_cmd="bundle exec rails test"
348
+ elif echo "$gemfile" | grep -q "rspec"; then
349
+ test_cmd="bundle exec rspec"
350
+ else
351
+ test_cmd="bundle exec rake test"
352
+ fi
353
+ fi
354
+ ;;
355
+
356
+ java)
357
+ if [[ -f "$root/pom.xml" ]]; then
358
+ test_cmd="mvn test"
359
+ elif [[ -f "$root/build.gradle" || -f "$root/build.gradle.kts" ]]; then
360
+ test_cmd="./gradlew test"
361
+ fi
362
+ ;;
363
+
364
+ dotnet)
365
+ test_cmd="dotnet test"
366
+ ;;
367
+
368
+ c)
369
+ if [[ -f "$root/Makefile" ]] && grep -q "^test:" "$root/Makefile" 2>/dev/null; then
370
+ test_cmd="make test"
371
+ fi
372
+ ;;
373
+
374
+ bash)
375
+ # Look for test runner scripts
376
+ if [[ -f "$root/package.json" ]]; then
377
+ test_cmd="npm test"
378
+ elif [[ -f "$root/scripts/run-tests.sh" ]]; then
379
+ test_cmd="bash scripts/run-tests.sh"
380
+ elif [[ -f "$root/Makefile" ]] && grep -q "^test:" "$root/Makefile" 2>/dev/null; then
381
+ test_cmd="make test"
382
+ fi
383
+ ;;
384
+ esac
385
+
386
+ [[ -n "$test_cmd" ]] && echo "$test_cmd"
387
+ }
388
+
389
+ # ═══════════════════════════════════════════════════════════════════════════
390
+ # project_detect_build_cmd(root, type)
391
+ # ─────────────────────────────────────────────────────────────────────────────
392
+ # Detect the build command for the project
393
+ project_detect_build_cmd() {
394
+ local root="${1:-.}"
395
+ local type="${2:-}"
396
+ [[ -d "$root" ]] || return 1
397
+
398
+ # If type not provided, detect it
399
+ if [[ -z "$type" ]]; then
400
+ local detection
401
+ detection=$(project_detect_type "$root") || return 1
402
+ type=$(_json_field "$detection" "type")
403
+ fi
404
+
405
+ local build_cmd=""
406
+
407
+ case "$type" in
408
+ nodejs)
409
+ if [[ -f "$root/package.json" ]]; then
410
+ local has_build
411
+ has_build=$(jq -r '.scripts.build // ""' "$root/package.json" 2>/dev/null || echo "")
412
+ if [[ -n "$has_build" && "$has_build" != "null" ]]; then
413
+ if [[ -f "$root/pnpm-lock.yaml" ]]; then
414
+ build_cmd="pnpm run build"
415
+ elif [[ -f "$root/yarn.lock" ]]; then
416
+ build_cmd="yarn build"
417
+ elif [[ -f "$root/bun.lockb" ]]; then
418
+ build_cmd="bun run build"
419
+ else
420
+ build_cmd="npm run build"
421
+ fi
422
+ fi
423
+ fi
424
+ ;;
425
+
426
+ python)
427
+ # Most Python projects don't need explicit build, just deps install
428
+ build_cmd=""
429
+ ;;
430
+
431
+ rust)
432
+ build_cmd="cargo build"
433
+ ;;
434
+
435
+ golang)
436
+ build_cmd="go build ./..."
437
+ ;;
438
+
439
+ ruby)
440
+ build_cmd=""
441
+ ;;
442
+
443
+ java)
444
+ if [[ -f "$root/pom.xml" ]]; then
445
+ build_cmd="mvn package"
446
+ elif [[ -f "$root/build.gradle" || -f "$root/build.gradle.kts" ]]; then
447
+ build_cmd="./gradlew build"
448
+ fi
449
+ ;;
450
+
451
+ dotnet)
452
+ build_cmd="dotnet build"
453
+ ;;
454
+
455
+ c)
456
+ if [[ -f "$root/Makefile" ]]; then
457
+ build_cmd="make build"
458
+ fi
459
+ ;;
460
+
461
+ bash)
462
+ build_cmd=""
463
+ ;;
464
+ esac
465
+
466
+ [[ -n "$build_cmd" ]] && echo "$build_cmd"
467
+ }
468
+
469
+ # ═══════════════════════════════════════════════════════════════════════════
470
+ # project_recommend_template(root)
471
+ # ─────────────────────────────────────────────────────────────────────────────
472
+ # Recommend a pipeline template based on project analysis
473
+ #
474
+ # Returns JSON: {
475
+ # "template": "fast|standard|full|deployed|cost-aware|hotfix",
476
+ # "confidence": 0-100,
477
+ # "reason": "explanation"
478
+ # }
479
+ project_recommend_template() {
480
+ local root="${1:-.}"
481
+ [[ -d "$root" ]] || return 1
482
+
483
+ local template="" confidence=0 reason=""
484
+
485
+ # Analyze project characteristics
486
+ local src_file_count test_file_count has_docker has_compose has_ci has_k8s
487
+ local has_deploy src_lines test_lines
488
+
489
+ # Count source files
490
+ src_file_count=$(find "$root" \
491
+ \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
492
+ -o -name "*.py" -o -name "*.rb" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \) \
493
+ -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/vendor/*" \
494
+ -not -path "*/target/*" 2>/dev/null | wc -l | tr -d ' ')
495
+
496
+ # Count test files
497
+ test_file_count=$(find "$root" \
498
+ \( -name "*.test.*" -o -name "*.spec.*" -o -name "*_test.*" -o -name "test_*" \) \
499
+ -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null | wc -l | tr -d ' ')
500
+
501
+ # Check infrastructure
502
+ has_docker=$([[ -f "$root/Dockerfile" ]] && echo "true" || echo "false")
503
+ has_compose=$([[ -f "$root/docker-compose.yml" || -f "$root/docker-compose.yaml" || -f "$root/compose.yml" ]] && echo "true" || echo "false")
504
+ has_k8s=$([[ -f "$root/k8s.yaml" || -d "$root/k8s" || -d "$root/helm" ]] && echo "true" || echo "false")
505
+ has_ci=$([[ -d "$root/.github/workflows" || -f "$root/.gitlab-ci.yml" || -f "$root/Jenkinsfile" ]] && echo "true" || echo "false")
506
+ has_deploy=$([[ "$has_docker" == "true" || "$has_k8s" == "true" || "$has_compose" == "true" ]] && echo "true" || echo "false")
507
+
508
+ # Count lines (rough estimate)
509
+ src_lines=$(find "$root" \
510
+ \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
511
+ -o -name "*.py" -o -name "*.rb" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \) \
512
+ -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/vendor/*" \
513
+ -not -path "*/target/*" 2>/dev/null -exec cat {} + 2>/dev/null | wc -l | tr -d ' ')
514
+
515
+ # Heuristics for template recommendation
516
+ if [[ "$src_file_count" -lt 20 && "$test_file_count" -lt 5 && "$has_deploy" == "false" ]]; then
517
+ # Small project, no tests, no deploy
518
+ template="fast"
519
+ confidence=85
520
+ reason="Small project with minimal complexity"
521
+
522
+ elif [[ "$src_file_count" -lt 50 && "$has_deploy" == "false" && "$test_file_count" -gt 0 ]]; then
523
+ # Small-to-medium with some tests
524
+ template="standard"
525
+ confidence=80
526
+ reason="Medium project with test coverage, no deployment"
527
+
528
+ elif [[ "$src_file_count" -ge 50 && "$test_file_count" -gt 10 && "$has_ci" == "true" && "$has_deploy" == "false" ]]; then
529
+ # Larger with good tests and CI
530
+ template="full"
531
+ confidence=75
532
+ reason="Larger codebase with comprehensive testing and CI"
533
+
534
+ elif [[ "$has_deploy" == "true" ]]; then
535
+ # Has deployment infrastructure (Dockerfile, Docker Compose, or Kubernetes)
536
+ template="deployed"
537
+ confidence=90
538
+ reason="Project with containerization and deployment config"
539
+
540
+ elif [[ "$src_file_count" -lt 30 && "$test_file_count" == "0" ]]; then
541
+ # Small, no tests — risky
542
+ template="standard"
543
+ confidence=65
544
+ reason="Small project without test coverage — recommend adding tests"
545
+
546
+ elif [[ "$src_lines" -gt 5000 ]]; then
547
+ # Large codebase
548
+ template="full"
549
+ confidence=80
550
+ reason="Large codebase with significant complexity"
551
+
552
+ elif [[ "$test_file_count" -eq "0" ]]; then
553
+ # No tests detected
554
+ template="standard"
555
+ confidence=60
556
+ reason="No test suite detected — recommend adding tests"
557
+
558
+ else
559
+ # Default middle ground
560
+ template="standard"
561
+ confidence=70
562
+ reason="Medium complexity project"
563
+ fi
564
+
565
+ # Output JSON
566
+ jq -n \
567
+ --arg template "$template" \
568
+ --argjson confidence "$confidence" \
569
+ --arg reason "$reason" \
570
+ '{template: $template, confidence: $confidence, reason: $reason}'
571
+ }
572
+
573
+ # ═══════════════════════════════════════════════════════════════════════════
574
+ # project_detect_all(root)
575
+ # ─────────────────────────────────────────────────────────────────────────────
576
+ # Run full detection and cache results to .claude/project-detection.json
577
+ #
578
+ # Returns JSON: {
579
+ # "type": "...",
580
+ # "framework": "...",
581
+ # "build_tool": "...",
582
+ # "test_runner": "...",
583
+ # "test_cmd": "...",
584
+ # "build_cmd": "...",
585
+ # "recommended_template": {...},
586
+ # "cached_at": "2026-03-07T...",
587
+ # "cache_ttl_seconds": 3600
588
+ # }
589
+ project_detect_all() {
590
+ local root="${1:-.}"
591
+ [[ -d "$root" ]] || return 1
592
+
593
+ local cache_file="${root}/.claude/project-detection.json"
594
+ local cache_ttl=3600
595
+
596
+ # Check cache validity
597
+ if [[ -f "$cache_file" ]]; then
598
+ local cached_at
599
+ cached_at=$(jq -r '.cached_at // ""' "$cache_file" 2>/dev/null || echo "")
600
+
601
+ if [[ -n "$cached_at" ]]; then
602
+ local cache_age
603
+ cache_age=$(($(date +%s) - $(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$cached_at" +%s 2>/dev/null || echo 0)))
604
+
605
+ if [[ "$cache_age" -lt "$cache_ttl" ]]; then
606
+ cat "$cache_file"
607
+ return 0
608
+ fi
609
+ fi
610
+ fi
611
+
612
+ # Perform detection
613
+ local type_info test_cmd build_cmd template_rec
614
+
615
+ type_info=$(project_detect_type "$root") || return 1
616
+ test_cmd=$(project_detect_test_cmd "$root" "$(_json_field "$type_info" "type")")
617
+ build_cmd=$(project_detect_build_cmd "$root" "$(_json_field "$type_info" "type")")
618
+ template_rec=$(project_recommend_template "$root")
619
+
620
+ local now_iso
621
+ now_iso=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
622
+
623
+ # Merge all data into single JSON
624
+ local result
625
+ result=$(jq -n \
626
+ --argjson type_info "$type_info" \
627
+ --arg test_cmd "${test_cmd:-}" \
628
+ --arg build_cmd "${build_cmd:-}" \
629
+ --argjson template_rec "$template_rec" \
630
+ --arg cached_at "$now_iso" \
631
+ --argjson cache_ttl 3600 \
632
+ '{
633
+ type: $type_info.type,
634
+ framework: $type_info.framework,
635
+ build_tool: $type_info.build_tool,
636
+ test_runner: $type_info.test_runner,
637
+ test_cmd: $test_cmd,
638
+ build_cmd: $build_cmd,
639
+ recommended_template: $template_rec,
640
+ cached_at: $cached_at,
641
+ cache_ttl_seconds: $cache_ttl
642
+ }')
643
+
644
+ # Cache result
645
+ mkdir -p "${root}/.claude"
646
+ echo "$result" > "$cache_file"
647
+
648
+ echo "$result"
649
+ }