rebar-mcp 2.0.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 (248) hide show
  1. package/.claude/agents/template-writer.md +43 -0
  2. package/.claude/agents/test-runner.md +47 -0
  3. package/.claude/mcp.json +9 -0
  4. package/.claude/settings.json +29 -0
  5. package/.claude/skills/ /SKILL.md +21 -0
  6. package/.claude/skills/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/SKILL.md +21 -0
  7. package/.claude/skills/bmmibwetxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  8. package/.claude/skills/bmmibwjgvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  9. package/.claude/skills/bmmibwsesxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  10. package/.claude/skills/bmmibwxufxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  11. package/.claude/skills/bmmibx3r9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  12. package/.claude/skills/bmmji0lrkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  13. package/.claude/skills/bmmjiniphxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  14. package/.claude/skills/bmmjio86zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  15. package/.claude/skills/bmmjiolfbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  16. package/.claude/skills/bmmjit1lvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  17. package/.claude/skills/bmmjita1qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  18. package/.claude/skills/bnd-mmibweu3/SKILL.md +21 -0
  19. package/.claude/skills/bnd-mmibwjh4/SKILL.md +21 -0
  20. package/.claude/skills/bnd-mmibwsey/SKILL.md +21 -0
  21. package/.claude/skills/bnd-mmibwxup/SKILL.md +21 -0
  22. package/.claude/skills/bnd-mmibx3rg/SKILL.md +21 -0
  23. package/.claude/skills/bnd-mmji0lrp/SKILL.md +21 -0
  24. package/.claude/skills/bnd-mmjinipm/SKILL.md +21 -0
  25. package/.claude/skills/bnd-mmjio875/SKILL.md +21 -0
  26. package/.claude/skills/bnd-mmjiolfg/SKILL.md +21 -0
  27. package/.claude/skills/bnd-mmjit1m3/SKILL.md +21 -0
  28. package/.claude/skills/bnd-mmjita1x/SKILL.md +21 -0
  29. package/.claude/skills/coercion-test/SKILL.md +50 -0
  30. package/.claude/skills/large-skill/SKILL.md +21 -0
  31. package/.claude/skills/long-desc-skill/SKILL.md +21 -0
  32. package/.claude/skills/mcp-dev/SKILL.md +61 -0
  33. package/.claude/skills/nl-mmibweus/SKILL.md +25 -0
  34. package/.claude/skills/nl-mmibwjhf/SKILL.md +25 -0
  35. package/.claude/skills/nl-mmibwsf7/SKILL.md +25 -0
  36. package/.claude/skills/nl-mmibwxvq/SKILL.md +25 -0
  37. package/.claude/skills/nl-mmibx3rt/SKILL.md +25 -0
  38. package/.claude/skills/nl-mmji0lrz/SKILL.md +25 -0
  39. package/.claude/skills/nl-mmjinipx/SKILL.md +25 -0
  40. package/.claude/skills/nl-mmjio87f/SKILL.md +25 -0
  41. package/.claude/skills/nl-mmjiolfs/SKILL.md +25 -0
  42. package/.claude/skills/nl-mmjit1mc/SKILL.md +25 -0
  43. package/.claude/skills/nl-mmjita26/SKILL.md +25 -0
  44. package/.claude/skills/rapid-1/SKILL.md +21 -0
  45. package/.claude/skills/rapid-2/SKILL.md +21 -0
  46. package/.claude/skills/rapid-3/SKILL.md +21 -0
  47. package/.claude/skills/rapid-4/SKILL.md +21 -0
  48. package/.claude/skills/rapid-5/SKILL.md +21 -0
  49. package/.claude/skills/test/", /"malicious/": /"true/SKILL.md" +69 -0
  50. package/.claude/skills/test-emoji-/360/237/230/200-skill/SKILL.md +69 -0
  51. package/.claude/skills/test-skill/SKILL.md +69 -0
  52. package/.claude/skills/test; rm -rf /; skill/SKILL.md +69 -0
  53. package/.claude/skills/test<script>alert(1)</script>skill/SKILL.md +69 -0
  54. package/.claudeignore +5 -0
  55. package/.mcp.json +3 -0
  56. package/CHANGELOG.md +29 -0
  57. package/CLAUDE.md +76 -0
  58. package/LICENSE +21 -0
  59. package/README.md +149 -0
  60. package/ROADMAP.md +526 -0
  61. package/ccboot-PRD-v1.0.docx.md +732 -0
  62. package/ccboot-v1.2.0-enforcement-spec.md +1272 -0
  63. package/dist/cli.d.ts +3 -0
  64. package/dist/cli.d.ts.map +1 -0
  65. package/dist/cli.js +674 -0
  66. package/dist/cli.js.map +1 -0
  67. package/dist/constants.d.ts +25 -0
  68. package/dist/constants.d.ts.map +1 -0
  69. package/dist/constants.js +118 -0
  70. package/dist/constants.js.map +1 -0
  71. package/dist/index.d.ts +3 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +47 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/schemas/common.d.ts +62 -0
  76. package/dist/schemas/common.d.ts.map +1 -0
  77. package/dist/schemas/common.js +15 -0
  78. package/dist/schemas/common.js.map +1 -0
  79. package/dist/schemas/scaffolding.d.ts +277 -0
  80. package/dist/schemas/scaffolding.d.ts.map +1 -0
  81. package/dist/schemas/scaffolding.js +133 -0
  82. package/dist/schemas/scaffolding.js.map +1 -0
  83. package/dist/services/claudemd-generator.d.ts +16 -0
  84. package/dist/services/claudemd-generator.d.ts.map +1 -0
  85. package/dist/services/claudemd-generator.js +426 -0
  86. package/dist/services/claudemd-generator.js.map +1 -0
  87. package/dist/services/codex-generator.d.ts +6 -0
  88. package/dist/services/codex-generator.d.ts.map +1 -0
  89. package/dist/services/codex-generator.js +35 -0
  90. package/dist/services/codex-generator.js.map +1 -0
  91. package/dist/services/cursor-generator.d.ts +15 -0
  92. package/dist/services/cursor-generator.d.ts.map +1 -0
  93. package/dist/services/cursor-generator.js +134 -0
  94. package/dist/services/cursor-generator.js.map +1 -0
  95. package/dist/services/file-ops.d.ts +48 -0
  96. package/dist/services/file-ops.d.ts.map +1 -0
  97. package/dist/services/file-ops.js +153 -0
  98. package/dist/services/file-ops.js.map +1 -0
  99. package/dist/services/output-formatter.d.ts +57 -0
  100. package/dist/services/output-formatter.d.ts.map +1 -0
  101. package/dist/services/output-formatter.js +88 -0
  102. package/dist/services/output-formatter.js.map +1 -0
  103. package/dist/services/platform-detect.d.ts +14 -0
  104. package/dist/services/platform-detect.d.ts.map +1 -0
  105. package/dist/services/platform-detect.js +63 -0
  106. package/dist/services/platform-detect.js.map +1 -0
  107. package/dist/services/project-analyzer.d.ts +71 -0
  108. package/dist/services/project-analyzer.d.ts.map +1 -0
  109. package/dist/services/project-analyzer.js +595 -0
  110. package/dist/services/project-analyzer.js.map +1 -0
  111. package/dist/services/rules-engine.d.ts +41 -0
  112. package/dist/services/rules-engine.d.ts.map +1 -0
  113. package/dist/services/rules-engine.js +304 -0
  114. package/dist/services/rules-engine.js.map +1 -0
  115. package/dist/services/strictness.d.ts +37 -0
  116. package/dist/services/strictness.d.ts.map +1 -0
  117. package/dist/services/strictness.js +182 -0
  118. package/dist/services/strictness.js.map +1 -0
  119. package/dist/services/template-engine.d.ts +16 -0
  120. package/dist/services/template-engine.d.ts.map +1 -0
  121. package/dist/services/template-engine.js +85 -0
  122. package/dist/services/template-engine.js.map +1 -0
  123. package/dist/services/validation.d.ts +41 -0
  124. package/dist/services/validation.d.ts.map +1 -0
  125. package/dist/services/validation.js +104 -0
  126. package/dist/services/validation.js.map +1 -0
  127. package/dist/services/windsurf-generator.d.ts +15 -0
  128. package/dist/services/windsurf-generator.d.ts.map +1 -0
  129. package/dist/services/windsurf-generator.js +127 -0
  130. package/dist/services/windsurf-generator.js.map +1 -0
  131. package/dist/tests/enforcement.test.d.ts +2 -0
  132. package/dist/tests/enforcement.test.d.ts.map +1 -0
  133. package/dist/tests/enforcement.test.js +541 -0
  134. package/dist/tests/enforcement.test.js.map +1 -0
  135. package/dist/tests/enterprise.test.d.ts +2 -0
  136. package/dist/tests/enterprise.test.d.ts.map +1 -0
  137. package/dist/tests/enterprise.test.js +353 -0
  138. package/dist/tests/enterprise.test.js.map +1 -0
  139. package/dist/tests/fuzzing.test.d.ts +2 -0
  140. package/dist/tests/fuzzing.test.d.ts.map +1 -0
  141. package/dist/tests/fuzzing.test.js +596 -0
  142. package/dist/tests/fuzzing.test.js.map +1 -0
  143. package/dist/tests/knowledge.test.d.ts +2 -0
  144. package/dist/tests/knowledge.test.d.ts.map +1 -0
  145. package/dist/tests/knowledge.test.js +292 -0
  146. package/dist/tests/knowledge.test.js.map +1 -0
  147. package/dist/tests/management.test.d.ts +2 -0
  148. package/dist/tests/management.test.d.ts.map +1 -0
  149. package/dist/tests/management.test.js +338 -0
  150. package/dist/tests/management.test.js.map +1 -0
  151. package/dist/tests/scaffolding.test.d.ts +2 -0
  152. package/dist/tests/scaffolding.test.d.ts.map +1 -0
  153. package/dist/tests/scaffolding.test.js +419 -0
  154. package/dist/tests/scaffolding.test.js.map +1 -0
  155. package/dist/tests/test-utils.d.ts +76 -0
  156. package/dist/tests/test-utils.d.ts.map +1 -0
  157. package/dist/tests/test-utils.js +171 -0
  158. package/dist/tests/test-utils.js.map +1 -0
  159. package/dist/tests/tool-harness.d.ts +18 -0
  160. package/dist/tests/tool-harness.d.ts.map +1 -0
  161. package/dist/tests/tool-harness.js +51 -0
  162. package/dist/tests/tool-harness.js.map +1 -0
  163. package/dist/tools/enterprise.d.ts +8 -0
  164. package/dist/tools/enterprise.d.ts.map +1 -0
  165. package/dist/tools/enterprise.js +571 -0
  166. package/dist/tools/enterprise.js.map +1 -0
  167. package/dist/tools/knowledge.d.ts +7 -0
  168. package/dist/tools/knowledge.d.ts.map +1 -0
  169. package/dist/tools/knowledge.js +120 -0
  170. package/dist/tools/knowledge.js.map +1 -0
  171. package/dist/tools/management.d.ts +10 -0
  172. package/dist/tools/management.d.ts.map +1 -0
  173. package/dist/tools/management.js +1541 -0
  174. package/dist/tools/management.js.map +1 -0
  175. package/dist/tools/scaffolding.d.ts +8 -0
  176. package/dist/tools/scaffolding.d.ts.map +1 -0
  177. package/dist/tools/scaffolding.js +736 -0
  178. package/dist/tools/scaffolding.js.map +1 -0
  179. package/dist/types.d.ts +54 -0
  180. package/dist/types.d.ts.map +1 -0
  181. package/dist/types.js +5 -0
  182. package/dist/types.js.map +1 -0
  183. package/landing/app/layout.tsx +30 -0
  184. package/landing/app/page.tsx +944 -0
  185. package/landing/next-env.d.ts +6 -0
  186. package/landing/next.config.js +6 -0
  187. package/landing/package-lock.json +896 -0
  188. package/landing/package.json +20 -0
  189. package/landing/tsconfig.json +40 -0
  190. package/package.json +49 -0
  191. package/rebar-v2.0.0-platform-spec.md +1567 -0
  192. package/server.json +20 -0
  193. package/src/cli.ts +735 -0
  194. package/src/constants.ts +131 -0
  195. package/src/index.ts +54 -0
  196. package/src/schemas/common.ts +22 -0
  197. package/src/schemas/scaffolding.ts +161 -0
  198. package/src/services/claudemd-generator.ts +481 -0
  199. package/src/services/codex-generator.ts +44 -0
  200. package/src/services/cursor-generator.ts +153 -0
  201. package/src/services/file-ops.ts +172 -0
  202. package/src/services/platform-detect.ts +80 -0
  203. package/src/services/project-analyzer.ts +690 -0
  204. package/src/services/rules-engine.ts +353 -0
  205. package/src/services/strictness.ts +202 -0
  206. package/src/services/template-engine.ts +119 -0
  207. package/src/services/validation.ts +138 -0
  208. package/src/services/windsurf-generator.ts +145 -0
  209. package/src/tests/enforcement.test.ts +794 -0
  210. package/src/tests/enterprise.test.ts +483 -0
  211. package/src/tests/fuzzing.test.ts +690 -0
  212. package/src/tests/knowledge.test.ts +371 -0
  213. package/src/tests/management.test.ts +451 -0
  214. package/src/tests/scaffolding.test.ts +575 -0
  215. package/src/tests/test-utils.ts +206 -0
  216. package/src/tests/tool-harness.ts +70 -0
  217. package/src/tools/enterprise.ts +666 -0
  218. package/src/tools/knowledge.ts +162 -0
  219. package/src/tools/management.ts +1706 -0
  220. package/src/tools/scaffolding.ts +909 -0
  221. package/src/types.ts +93 -0
  222. package/supabase/.temp/cli-latest +1 -0
  223. package/supabase/.temp/gotrue-version +1 -0
  224. package/supabase/.temp/pooler-url +1 -0
  225. package/supabase/.temp/postgres-version +1 -0
  226. package/supabase/.temp/project-ref +1 -0
  227. package/supabase/.temp/rest-version +1 -0
  228. package/supabase/.temp/storage-migration +1 -0
  229. package/supabase/.temp/storage-version +1 -0
  230. package/templates/agents/explore.md +41 -0
  231. package/templates/agents/plan.md +73 -0
  232. package/templates/agents/security-auditor.md +77 -0
  233. package/templates/agents/test-runner.md +60 -0
  234. package/templates/claudemd/fastapi.md +49 -0
  235. package/templates/claudemd/monorepo.md +48 -0
  236. package/templates/claudemd/nextjs.md +52 -0
  237. package/templates/claudemd/react-spa.md +50 -0
  238. package/templates/claudemd/springboot.md +50 -0
  239. package/templates/hooks/danger-blocker.json +11 -0
  240. package/templates/hooks/format-on-write.json +17 -0
  241. package/templates/hooks/lint-on-write.json +16 -0
  242. package/templates/hooks/secret-detector.json +11 -0
  243. package/templates/skills/code-review.md +68 -0
  244. package/templates/skills/documentation.md +62 -0
  245. package/templates/skills/performance-audit.md +80 -0
  246. package/templates/skills/security-scan.md +66 -0
  247. package/templates/skills/test-writer.md +56 -0
  248. package/tsconfig.json +19 -0
@@ -0,0 +1,71 @@
1
+ import type { TechStack } from "../types.js";
2
+ export interface ProjectAnalysis {
3
+ /** Detected project name */
4
+ name: string;
5
+ /** Detected tech stacks, ordered by confidence */
6
+ stacks: TechStack[];
7
+ /** Primary language */
8
+ language: "typescript" | "javascript" | "python" | "java" | "go" | "rust" | "csharp" | "ruby" | "php" | "unknown";
9
+ /** Actual build commands from project config */
10
+ buildCommands: Record<string, string>;
11
+ /** Actual test commands */
12
+ testCommands: Record<string, string>;
13
+ /** Detected linter/formatter */
14
+ linter: string | null;
15
+ formatter: string | null;
16
+ /** Detected test framework */
17
+ testFramework: string | null;
18
+ /** Key dependencies (frameworks, ORMs, state managers, etc.) */
19
+ keyDependencies: DependencyInfo[];
20
+ /** Detected patterns */
21
+ patterns: ProjectPattern[];
22
+ /** Whether it's a monorepo */
23
+ isMonorepo: boolean;
24
+ /** Monorepo tool if detected */
25
+ monorepoTool: string | null;
26
+ /** Detected package manager */
27
+ packageManager: "npm" | "yarn" | "pnpm" | "bun" | "pip" | "poetry" | "cargo" | "go" | "maven" | "gradle" | "unknown";
28
+ /** Source directories that exist */
29
+ sourceDirs: string[];
30
+ /** Whether TypeScript is used */
31
+ usesTypeScript: boolean;
32
+ /** Detected database/ORM */
33
+ database: string | null;
34
+ /** Detected CSS framework */
35
+ cssFramework: string | null;
36
+ /** Detected API style */
37
+ apiStyle: "rest" | "graphql" | "grpc" | "trpc" | null;
38
+ /** Detected deployment target */
39
+ deployTarget: string | null;
40
+ /** Project description from manifest */
41
+ description: string | null;
42
+ /** Node.js engine requirement */
43
+ nodeVersion: string | null;
44
+ /** Has Docker */
45
+ hasDocker: boolean;
46
+ /** Has CI/CD */
47
+ ciPlatform: string | null;
48
+ /** Environment variables referenced (names only, never values) */
49
+ envVarNames: string[];
50
+ }
51
+ export interface DependencyInfo {
52
+ name: string;
53
+ category: "framework" | "orm" | "testing" | "linting" | "styling" | "state" | "api" | "auth" | "monitoring" | "build" | "utility";
54
+ description: string;
55
+ }
56
+ export interface ProjectPattern {
57
+ name: string;
58
+ description: string;
59
+ confidence: "high" | "medium" | "low";
60
+ }
61
+ /**
62
+ * Performs deep analysis of a project directory.
63
+ * This is the core intelligence that drives all generated artifacts.
64
+ */
65
+ export declare function analyzeProject(projectPath: string): Promise<ProjectAnalysis>;
66
+ /**
67
+ * Generates a human-readable summary of the project analysis.
68
+ * Used for tool output when users want to see what was detected.
69
+ */
70
+ export declare function summarizeAnalysis(analysis: ProjectAnalysis): string;
71
+ //# sourceMappingURL=project-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-analyzer.d.ts","sourceRoot":"","sources":["../../src/services/project-analyzer.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,uBAAuB;IACvB,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IAClH,gDAAgD;IAChD,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,gCAAgC;IAChC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,8BAA8B;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gEAAgE;IAChE,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,wBAAwB;IACxB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,8BAA8B;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,gCAAgC;IAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,+BAA+B;IAC/B,cAAc,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IACrH,oCAAoC;IACpC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,iCAAiC;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,6BAA6B;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,yBAAyB;IACzB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACtD,iCAAiC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wCAAwC;IACxC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iCAAiC;IACjC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kEAAkE;IAClE,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;IAClI,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAyClF;AA+fD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAqDnE"}
@@ -0,0 +1,595 @@
1
+ /**
2
+ * Deep project analysis service.
3
+ *
4
+ * Reads real project files (package.json, Cargo.toml, go.mod, etc.)
5
+ * and extracts meaningful context: actual build commands, real dependencies,
6
+ * detected patterns, testing frameworks, linting tools, and more.
7
+ *
8
+ * This is what makes Rebar output feel "magical" — it generates config
9
+ * that reflects what the project actually is, not what we guess it might be.
10
+ */
11
+ import * as path from "node:path";
12
+ import { readFileSafe, fileExists } from "./file-ops.js";
13
+ /**
14
+ * Performs deep analysis of a project directory.
15
+ * This is the core intelligence that drives all generated artifacts.
16
+ */
17
+ export async function analyzeProject(projectPath) {
18
+ const analysis = {
19
+ name: path.basename(projectPath),
20
+ stacks: [],
21
+ language: "unknown",
22
+ buildCommands: {},
23
+ testCommands: {},
24
+ linter: null,
25
+ formatter: null,
26
+ testFramework: null,
27
+ keyDependencies: [],
28
+ patterns: [],
29
+ isMonorepo: false,
30
+ monorepoTool: null,
31
+ packageManager: "unknown",
32
+ sourceDirs: [],
33
+ usesTypeScript: false,
34
+ database: null,
35
+ cssFramework: null,
36
+ apiStyle: null,
37
+ deployTarget: null,
38
+ description: null,
39
+ nodeVersion: null,
40
+ hasDocker: false,
41
+ ciPlatform: null,
42
+ envVarNames: [],
43
+ };
44
+ // Run all detections in parallel for speed
45
+ await Promise.all([
46
+ analyzeNodeProject(projectPath, analysis),
47
+ analyzePythonProject(projectPath, analysis),
48
+ analyzeGoProject(projectPath, analysis),
49
+ analyzeRustProject(projectPath, analysis),
50
+ analyzeJavaProject(projectPath, analysis),
51
+ analyzeInfrastructure(projectPath, analysis),
52
+ analyzeSourceDirs(projectPath, analysis),
53
+ analyzeEnvVars(projectPath, analysis),
54
+ ]);
55
+ return analysis;
56
+ }
57
+ // ─── Node.js / JavaScript / TypeScript ──────────────────────────────
58
+ async function analyzeNodeProject(projectPath, analysis) {
59
+ const pkgJsonStr = await readFileSafe(path.join(projectPath, "package.json"));
60
+ if (!pkgJsonStr)
61
+ return;
62
+ let pkg;
63
+ try {
64
+ pkg = JSON.parse(pkgJsonStr);
65
+ }
66
+ catch {
67
+ return;
68
+ }
69
+ // Name and description
70
+ if (typeof pkg.name === "string")
71
+ analysis.name = pkg.name;
72
+ if (typeof pkg.description === "string")
73
+ analysis.description = pkg.description;
74
+ // Engine requirements
75
+ if (pkg.engines && typeof pkg.engines === "object") {
76
+ const engines = pkg.engines;
77
+ if (engines.node)
78
+ analysis.nodeVersion = engines.node;
79
+ }
80
+ // Package manager detection
81
+ if (await fileExists(path.join(projectPath, "pnpm-lock.yaml"))) {
82
+ analysis.packageManager = "pnpm";
83
+ }
84
+ else if (await fileExists(path.join(projectPath, "yarn.lock"))) {
85
+ analysis.packageManager = "yarn";
86
+ }
87
+ else if (await fileExists(path.join(projectPath, "bun.lockb"))) {
88
+ analysis.packageManager = "bun";
89
+ }
90
+ else {
91
+ analysis.packageManager = "npm";
92
+ }
93
+ // Scripts — extract ACTUAL build/test/lint commands
94
+ const scripts = (pkg.scripts || {});
95
+ for (const [key, value] of Object.entries(scripts)) {
96
+ if (["build", "compile", "bundle"].some((k) => key.includes(k))) {
97
+ analysis.buildCommands[key] = value;
98
+ }
99
+ if (["test", "spec", "e2e", "cypress", "playwright"].some((k) => key.includes(k))) {
100
+ analysis.testCommands[key] = value;
101
+ }
102
+ }
103
+ // Collect all deps
104
+ const allDeps = {
105
+ ...(pkg.dependencies || {}),
106
+ ...(pkg.devDependencies || {}),
107
+ };
108
+ const depNames = new Set(Object.keys(allDeps));
109
+ // TypeScript
110
+ analysis.usesTypeScript = depNames.has("typescript") ||
111
+ await fileExists(path.join(projectPath, "tsconfig.json"));
112
+ analysis.language = analysis.usesTypeScript ? "typescript" : "javascript";
113
+ // ── Framework Detection (ordered by specificity) ──────────────
114
+ // Next.js
115
+ if (depNames.has("next")) {
116
+ analysis.stacks.push("nextjs");
117
+ analysis.keyDependencies.push({ name: "next", category: "framework", description: "React framework with SSR/SSG" });
118
+ // Detect Next.js patterns
119
+ if (await fileExists(path.join(projectPath, "app"))) {
120
+ analysis.patterns.push({ name: "app-router", description: "Uses Next.js App Router (app/ directory)", confidence: "high" });
121
+ }
122
+ else if (await fileExists(path.join(projectPath, "pages"))) {
123
+ analysis.patterns.push({ name: "pages-router", description: "Uses Next.js Pages Router (pages/ directory)", confidence: "high" });
124
+ }
125
+ }
126
+ // React (standalone)
127
+ if (depNames.has("react") && !depNames.has("next")) {
128
+ analysis.stacks.push("react");
129
+ analysis.keyDependencies.push({ name: "react", category: "framework", description: "UI component library" });
130
+ }
131
+ // Vue / Nuxt
132
+ if (depNames.has("nuxt") || depNames.has("nuxt3")) {
133
+ analysis.stacks.push("vue");
134
+ analysis.keyDependencies.push({ name: "nuxt", category: "framework", description: "Vue meta-framework with SSR" });
135
+ }
136
+ else if (depNames.has("vue")) {
137
+ analysis.stacks.push("vue");
138
+ analysis.keyDependencies.push({ name: "vue", category: "framework", description: "Progressive JavaScript framework" });
139
+ }
140
+ // Angular
141
+ if (depNames.has("@angular/core")) {
142
+ analysis.stacks.push("angular");
143
+ analysis.keyDependencies.push({ name: "@angular/core", category: "framework", description: "Enterprise web framework" });
144
+ }
145
+ // Svelte / SvelteKit
146
+ if (depNames.has("@sveltejs/kit")) {
147
+ analysis.stacks.push("svelte");
148
+ analysis.keyDependencies.push({ name: "@sveltejs/kit", category: "framework", description: "Svelte meta-framework" });
149
+ }
150
+ else if (depNames.has("svelte")) {
151
+ analysis.stacks.push("svelte");
152
+ analysis.keyDependencies.push({ name: "svelte", category: "framework", description: "Compiled UI framework" });
153
+ }
154
+ // Express
155
+ if (depNames.has("express")) {
156
+ analysis.stacks.push("express");
157
+ analysis.keyDependencies.push({ name: "express", category: "framework", description: "Node.js web framework" });
158
+ }
159
+ // Monorepo detection
160
+ if (pkg.workspaces) {
161
+ analysis.isMonorepo = true;
162
+ if (depNames.has("turbo")) {
163
+ analysis.monorepoTool = "Turborepo";
164
+ }
165
+ else if (depNames.has("nx")) {
166
+ analysis.monorepoTool = "Nx";
167
+ }
168
+ else if (depNames.has("lerna")) {
169
+ analysis.monorepoTool = "Lerna";
170
+ }
171
+ else {
172
+ analysis.monorepoTool = "npm workspaces";
173
+ }
174
+ }
175
+ // ── ORM / Database ────────────────────────────────────────────
176
+ if (depNames.has("prisma") || depNames.has("@prisma/client")) {
177
+ analysis.database = "Prisma";
178
+ analysis.keyDependencies.push({ name: "prisma", category: "orm", description: "Type-safe ORM with auto-generated client" });
179
+ }
180
+ else if (depNames.has("drizzle-orm")) {
181
+ analysis.database = "Drizzle";
182
+ analysis.keyDependencies.push({ name: "drizzle-orm", category: "orm", description: "Lightweight TypeScript ORM" });
183
+ }
184
+ else if (depNames.has("typeorm")) {
185
+ analysis.database = "TypeORM";
186
+ analysis.keyDependencies.push({ name: "typeorm", category: "orm", description: "TypeScript ORM for SQL databases" });
187
+ }
188
+ else if (depNames.has("sequelize")) {
189
+ analysis.database = "Sequelize";
190
+ analysis.keyDependencies.push({ name: "sequelize", category: "orm", description: "Promise-based ORM" });
191
+ }
192
+ else if (depNames.has("mongoose")) {
193
+ analysis.database = "Mongoose (MongoDB)";
194
+ analysis.keyDependencies.push({ name: "mongoose", category: "orm", description: "MongoDB ODM" });
195
+ }
196
+ else if (depNames.has("knex")) {
197
+ analysis.database = "Knex.js";
198
+ analysis.keyDependencies.push({ name: "knex", category: "orm", description: "SQL query builder" });
199
+ }
200
+ // ── Testing ───────────────────────────────────────────────────
201
+ if (depNames.has("vitest")) {
202
+ analysis.testFramework = "Vitest";
203
+ analysis.keyDependencies.push({ name: "vitest", category: "testing", description: "Vite-native testing framework" });
204
+ }
205
+ else if (depNames.has("jest")) {
206
+ analysis.testFramework = "Jest";
207
+ analysis.keyDependencies.push({ name: "jest", category: "testing", description: "JavaScript testing framework" });
208
+ }
209
+ else if (depNames.has("mocha")) {
210
+ analysis.testFramework = "Mocha";
211
+ analysis.keyDependencies.push({ name: "mocha", category: "testing", description: "Flexible test framework" });
212
+ }
213
+ if (depNames.has("@testing-library/react")) {
214
+ analysis.keyDependencies.push({ name: "@testing-library/react", category: "testing", description: "React component testing utilities" });
215
+ }
216
+ if (depNames.has("playwright") || depNames.has("@playwright/test")) {
217
+ analysis.keyDependencies.push({ name: "playwright", category: "testing", description: "End-to-end browser testing" });
218
+ }
219
+ if (depNames.has("cypress")) {
220
+ analysis.keyDependencies.push({ name: "cypress", category: "testing", description: "End-to-end testing framework" });
221
+ }
222
+ // ── Linting / Formatting ──────────────────────────────────────
223
+ if (depNames.has("@biomejs/biome") || depNames.has("biome")) {
224
+ analysis.linter = "Biome";
225
+ analysis.formatter = "Biome";
226
+ }
227
+ else {
228
+ if (depNames.has("eslint")) {
229
+ analysis.linter = "ESLint";
230
+ analysis.keyDependencies.push({ name: "eslint", category: "linting", description: "JavaScript/TypeScript linter" });
231
+ }
232
+ if (depNames.has("prettier")) {
233
+ analysis.formatter = "Prettier";
234
+ analysis.keyDependencies.push({ name: "prettier", category: "linting", description: "Opinionated code formatter" });
235
+ }
236
+ }
237
+ if (depNames.has("oxlint")) {
238
+ analysis.linter = "oxlint";
239
+ }
240
+ // ── CSS / Styling ─────────────────────────────────────────────
241
+ if (depNames.has("tailwindcss")) {
242
+ analysis.cssFramework = "Tailwind CSS";
243
+ analysis.keyDependencies.push({ name: "tailwindcss", category: "styling", description: "Utility-first CSS framework" });
244
+ }
245
+ else if (depNames.has("styled-components")) {
246
+ analysis.cssFramework = "styled-components";
247
+ }
248
+ else if (depNames.has("@emotion/react")) {
249
+ analysis.cssFramework = "Emotion";
250
+ }
251
+ else if (depNames.has("sass") || depNames.has("node-sass")) {
252
+ analysis.cssFramework = "Sass";
253
+ }
254
+ // ── State Management ──────────────────────────────────────────
255
+ if (depNames.has("zustand")) {
256
+ analysis.keyDependencies.push({ name: "zustand", category: "state", description: "Lightweight state management" });
257
+ }
258
+ if (depNames.has("@reduxjs/toolkit") || depNames.has("redux")) {
259
+ analysis.keyDependencies.push({ name: "redux", category: "state", description: "Predictable state container" });
260
+ }
261
+ if (depNames.has("@tanstack/react-query")) {
262
+ analysis.keyDependencies.push({ name: "@tanstack/react-query", category: "state", description: "Server state management" });
263
+ }
264
+ if (depNames.has("jotai")) {
265
+ analysis.keyDependencies.push({ name: "jotai", category: "state", description: "Primitive atomic state management" });
266
+ }
267
+ // ── API Style ─────────────────────────────────────────────────
268
+ if (depNames.has("@trpc/server") || depNames.has("@trpc/client")) {
269
+ analysis.apiStyle = "trpc";
270
+ analysis.keyDependencies.push({ name: "trpc", category: "api", description: "End-to-end typesafe API" });
271
+ }
272
+ else if (depNames.has("graphql") || depNames.has("@apollo/server") || depNames.has("graphql-yoga")) {
273
+ analysis.apiStyle = "graphql";
274
+ analysis.keyDependencies.push({ name: "graphql", category: "api", description: "GraphQL API layer" });
275
+ }
276
+ else if (depNames.has("@grpc/grpc-js")) {
277
+ analysis.apiStyle = "grpc";
278
+ }
279
+ else {
280
+ analysis.apiStyle = "rest";
281
+ }
282
+ // ── Auth ──────────────────────────────────────────────────────
283
+ if (depNames.has("next-auth") || depNames.has("@auth/core")) {
284
+ analysis.keyDependencies.push({ name: "next-auth", category: "auth", description: "Authentication for Next.js" });
285
+ }
286
+ if (depNames.has("passport")) {
287
+ analysis.keyDependencies.push({ name: "passport", category: "auth", description: "Node.js authentication middleware" });
288
+ }
289
+ if (depNames.has("@clerk/nextjs") || depNames.has("@clerk/clerk-js")) {
290
+ analysis.keyDependencies.push({ name: "clerk", category: "auth", description: "Drop-in authentication and user management" });
291
+ }
292
+ if (depNames.has("@supabase/supabase-js")) {
293
+ analysis.keyDependencies.push({ name: "supabase", category: "auth", description: "Backend-as-a-service with auth" });
294
+ }
295
+ // ── Deploy Target ─────────────────────────────────────────────
296
+ const vercelConfig = await fileExists(path.join(projectPath, "vercel.json"));
297
+ const netlifyConfig = await fileExists(path.join(projectPath, "netlify.toml"));
298
+ if (vercelConfig || depNames.has("vercel")) {
299
+ analysis.deployTarget = "Vercel";
300
+ }
301
+ else if (netlifyConfig) {
302
+ analysis.deployTarget = "Netlify";
303
+ }
304
+ else if (depNames.has("@aws-cdk/core") || depNames.has("aws-cdk-lib")) {
305
+ analysis.deployTarget = "AWS CDK";
306
+ }
307
+ else if (depNames.has("serverless")) {
308
+ analysis.deployTarget = "Serverless Framework";
309
+ }
310
+ // ── Monitoring ────────────────────────────────────────────────
311
+ if (depNames.has("@sentry/nextjs") || depNames.has("@sentry/node") || depNames.has("@sentry/react")) {
312
+ analysis.keyDependencies.push({ name: "sentry", category: "monitoring", description: "Error tracking and performance monitoring" });
313
+ }
314
+ if (depNames.has("datadog-metrics") || depNames.has("dd-trace")) {
315
+ analysis.keyDependencies.push({ name: "datadog", category: "monitoring", description: "APM and infrastructure monitoring" });
316
+ }
317
+ }
318
+ // ─── Python ─────────────────────────────────────────────────────────
319
+ async function analyzePythonProject(projectPath, analysis) {
320
+ const pyprojectStr = await readFileSafe(path.join(projectPath, "pyproject.toml"));
321
+ const requirementsStr = await readFileSafe(path.join(projectPath, "requirements.txt"));
322
+ const setupPy = await fileExists(path.join(projectPath, "setup.py"));
323
+ if (!pyprojectStr && !requirementsStr && !setupPy)
324
+ return;
325
+ analysis.language = "python";
326
+ // Package manager
327
+ if (pyprojectStr?.includes("[tool.poetry]")) {
328
+ analysis.packageManager = "poetry";
329
+ }
330
+ else {
331
+ analysis.packageManager = "pip";
332
+ }
333
+ // Combine all dependency strings for scanning
334
+ const allContent = (pyprojectStr || "") + "\n" + (requirementsStr || "");
335
+ // Framework detection
336
+ if (allContent.includes("fastapi")) {
337
+ analysis.stacks.push("fastapi");
338
+ analysis.keyDependencies.push({ name: "fastapi", category: "framework", description: "High-performance async web framework" });
339
+ analysis.buildCommands.dev = "uvicorn app.main:app --reload";
340
+ }
341
+ if (allContent.includes("django")) {
342
+ analysis.stacks.push("django");
343
+ analysis.keyDependencies.push({ name: "django", category: "framework", description: "Full-featured web framework" });
344
+ analysis.buildCommands.dev = "python manage.py runserver";
345
+ }
346
+ if (allContent.includes("flask")) {
347
+ analysis.stacks.push("flask");
348
+ analysis.keyDependencies.push({ name: "flask", category: "framework", description: "Lightweight web framework" });
349
+ }
350
+ // Testing
351
+ if (allContent.includes("pytest")) {
352
+ analysis.testFramework = "pytest";
353
+ analysis.testCommands.test = "pytest";
354
+ analysis.keyDependencies.push({ name: "pytest", category: "testing", description: "Python testing framework" });
355
+ }
356
+ // Linting
357
+ if (allContent.includes("ruff")) {
358
+ analysis.linter = "Ruff";
359
+ analysis.formatter = "Ruff";
360
+ }
361
+ else if (allContent.includes("flake8")) {
362
+ analysis.linter = "Flake8";
363
+ }
364
+ if (allContent.includes("black")) {
365
+ analysis.formatter = "Black";
366
+ }
367
+ // ORM
368
+ if (allContent.includes("sqlalchemy")) {
369
+ analysis.database = "SQLAlchemy";
370
+ analysis.keyDependencies.push({ name: "sqlalchemy", category: "orm", description: "Python SQL toolkit and ORM" });
371
+ }
372
+ if (allContent.includes("alembic")) {
373
+ analysis.keyDependencies.push({ name: "alembic", category: "orm", description: "Database migration tool for SQLAlchemy" });
374
+ }
375
+ if (allContent.includes("tortoise-orm")) {
376
+ analysis.database = "Tortoise ORM";
377
+ }
378
+ // Type checking
379
+ if (allContent.includes("mypy")) {
380
+ analysis.patterns.push({ name: "type-checked", description: "Uses mypy for static type checking", confidence: "high" });
381
+ }
382
+ }
383
+ // ─── Go ─────────────────────────────────────────────────────────────
384
+ async function analyzeGoProject(projectPath, analysis) {
385
+ const goMod = await readFileSafe(path.join(projectPath, "go.mod"));
386
+ if (!goMod)
387
+ return;
388
+ analysis.language = "go";
389
+ analysis.stacks.push("go");
390
+ analysis.packageManager = "go";
391
+ analysis.buildCommands.build = "go build ./...";
392
+ analysis.testCommands.test = "go test ./...";
393
+ analysis.linter = "golangci-lint";
394
+ analysis.formatter = "gofmt";
395
+ // Extract module name
396
+ const moduleMatch = goMod.match(/module\s+(\S+)/);
397
+ if (moduleMatch) {
398
+ analysis.name = moduleMatch[1].split("/").pop() || analysis.name;
399
+ }
400
+ // Framework detection
401
+ if (goMod.includes("github.com/gin-gonic/gin")) {
402
+ analysis.keyDependencies.push({ name: "gin", category: "framework", description: "HTTP web framework" });
403
+ }
404
+ if (goMod.includes("github.com/gofiber/fiber")) {
405
+ analysis.keyDependencies.push({ name: "fiber", category: "framework", description: "Express-inspired web framework" });
406
+ }
407
+ if (goMod.includes("google.golang.org/grpc")) {
408
+ analysis.apiStyle = "grpc";
409
+ }
410
+ if (goMod.includes("gorm.io/gorm")) {
411
+ analysis.database = "GORM";
412
+ analysis.keyDependencies.push({ name: "gorm", category: "orm", description: "Go ORM library" });
413
+ }
414
+ }
415
+ // ─── Rust ───────────────────────────────────────────────────────────
416
+ async function analyzeRustProject(projectPath, analysis) {
417
+ const cargoToml = await readFileSafe(path.join(projectPath, "Cargo.toml"));
418
+ if (!cargoToml)
419
+ return;
420
+ analysis.language = "rust";
421
+ analysis.stacks.push("rust");
422
+ analysis.packageManager = "cargo";
423
+ analysis.buildCommands.build = "cargo build";
424
+ analysis.testCommands.test = "cargo test";
425
+ analysis.linter = "Clippy";
426
+ analysis.formatter = "rustfmt";
427
+ // Extract crate name
428
+ const nameMatch = cargoToml.match(/name\s*=\s*"([^"]+)"/);
429
+ if (nameMatch)
430
+ analysis.name = nameMatch[1];
431
+ if (cargoToml.includes("actix-web")) {
432
+ analysis.keyDependencies.push({ name: "actix-web", category: "framework", description: "Powerful actor-based web framework" });
433
+ }
434
+ if (cargoToml.includes("axum")) {
435
+ analysis.keyDependencies.push({ name: "axum", category: "framework", description: "Ergonomic web framework built on Tokio" });
436
+ }
437
+ if (cargoToml.includes("diesel")) {
438
+ analysis.database = "Diesel";
439
+ analysis.keyDependencies.push({ name: "diesel", category: "orm", description: "Type-safe SQL query builder" });
440
+ }
441
+ if (cargoToml.includes("sqlx")) {
442
+ analysis.database = "SQLx";
443
+ analysis.keyDependencies.push({ name: "sqlx", category: "orm", description: "Async SQL toolkit with compile-time checking" });
444
+ }
445
+ }
446
+ // ─── Java / Spring Boot ─────────────────────────────────────────────
447
+ async function analyzeJavaProject(projectPath, analysis) {
448
+ const pomXml = await readFileSafe(path.join(projectPath, "pom.xml"));
449
+ const buildGradle = await readFileSafe(path.join(projectPath, "build.gradle"));
450
+ const buildGradleKts = await readFileSafe(path.join(projectPath, "build.gradle.kts"));
451
+ const buildFile = pomXml || buildGradle || buildGradleKts;
452
+ if (!buildFile)
453
+ return;
454
+ analysis.language = "java";
455
+ analysis.packageManager = pomXml ? "maven" : "gradle";
456
+ if (pomXml) {
457
+ analysis.buildCommands.build = "./mvnw clean package";
458
+ analysis.testCommands.test = "./mvnw test";
459
+ }
460
+ else {
461
+ analysis.buildCommands.build = "./gradlew build";
462
+ analysis.testCommands.test = "./gradlew test";
463
+ }
464
+ if (buildFile.includes("spring-boot")) {
465
+ analysis.stacks.push("springboot");
466
+ analysis.keyDependencies.push({ name: "spring-boot", category: "framework", description: "Enterprise Java framework" });
467
+ analysis.buildCommands.dev = pomXml ? "./mvnw spring-boot:run" : "./gradlew bootRun";
468
+ }
469
+ if (buildFile.includes("spring-data-jpa")) {
470
+ analysis.database = "Spring Data JPA";
471
+ analysis.keyDependencies.push({ name: "spring-data-jpa", category: "orm", description: "JPA-based data access" });
472
+ }
473
+ if (buildFile.includes("flyway")) {
474
+ analysis.keyDependencies.push({ name: "flyway", category: "orm", description: "Database migration tool" });
475
+ }
476
+ if (buildFile.includes("spring-security")) {
477
+ analysis.keyDependencies.push({ name: "spring-security", category: "auth", description: "Authentication and authorization framework" });
478
+ }
479
+ analysis.testFramework = "JUnit";
480
+ }
481
+ // ─── Infrastructure ─────────────────────────────────────────────────
482
+ async function analyzeInfrastructure(projectPath, analysis) {
483
+ // Docker
484
+ if (await fileExists(path.join(projectPath, "Dockerfile")) ||
485
+ await fileExists(path.join(projectPath, "docker-compose.yml")) ||
486
+ await fileExists(path.join(projectPath, "docker-compose.yaml"))) {
487
+ analysis.hasDocker = true;
488
+ }
489
+ // CI/CD
490
+ if (await fileExists(path.join(projectPath, ".github/workflows"))) {
491
+ analysis.ciPlatform = "GitHub Actions";
492
+ }
493
+ else if (await fileExists(path.join(projectPath, ".gitlab-ci.yml"))) {
494
+ analysis.ciPlatform = "GitLab CI";
495
+ }
496
+ else if (await fileExists(path.join(projectPath, ".circleci"))) {
497
+ analysis.ciPlatform = "CircleCI";
498
+ }
499
+ else if (await fileExists(path.join(projectPath, "Jenkinsfile"))) {
500
+ analysis.ciPlatform = "Jenkins";
501
+ }
502
+ }
503
+ // ─── Source Directories ─────────────────────────────────────────────
504
+ async function analyzeSourceDirs(projectPath, analysis) {
505
+ const candidates = [
506
+ "src", "app", "lib", "pages", "components", "api",
507
+ "server", "client", "packages", "apps",
508
+ "tests", "test", "__tests__", "spec",
509
+ ];
510
+ for (const dir of candidates) {
511
+ if (await fileExists(path.join(projectPath, dir))) {
512
+ analysis.sourceDirs.push(dir);
513
+ }
514
+ }
515
+ }
516
+ // ─── Environment Variables ──────────────────────────────────────────
517
+ async function analyzeEnvVars(projectPath, analysis) {
518
+ // Read .env.example or .env.sample (never .env itself!)
519
+ const envExample = (await readFileSafe(path.join(projectPath, ".env.example"))) ||
520
+ (await readFileSafe(path.join(projectPath, ".env.sample"))) ||
521
+ (await readFileSafe(path.join(projectPath, ".env.local.example")));
522
+ if (envExample) {
523
+ const names = envExample
524
+ .split("\n")
525
+ .filter((line) => line.includes("=") && !line.startsWith("#"))
526
+ .map((line) => line.split("=")[0].trim())
527
+ .filter((name) => name.length > 0);
528
+ analysis.envVarNames = names;
529
+ }
530
+ }
531
+ /**
532
+ * Generates a human-readable summary of the project analysis.
533
+ * Used for tool output when users want to see what was detected.
534
+ */
535
+ export function summarizeAnalysis(analysis) {
536
+ const lines = [
537
+ `Project: ${analysis.name}`,
538
+ `Language: ${analysis.language}`,
539
+ `Stacks: ${analysis.stacks.length > 0 ? analysis.stacks.join(", ") : "(none detected)"}`,
540
+ `Package manager: ${analysis.packageManager}`,
541
+ ];
542
+ if (analysis.description)
543
+ lines.push(`Description: ${analysis.description}`);
544
+ if (analysis.usesTypeScript)
545
+ lines.push("TypeScript: yes");
546
+ if (analysis.isMonorepo)
547
+ lines.push(`Monorepo: ${analysis.monorepoTool || "yes"}`);
548
+ if (analysis.database)
549
+ lines.push(`Database: ${analysis.database}`);
550
+ if (analysis.testFramework)
551
+ lines.push(`Testing: ${analysis.testFramework}`);
552
+ if (analysis.linter)
553
+ lines.push(`Linter: ${analysis.linter}`);
554
+ if (analysis.formatter)
555
+ lines.push(`Formatter: ${analysis.formatter}`);
556
+ if (analysis.cssFramework)
557
+ lines.push(`CSS: ${analysis.cssFramework}`);
558
+ if (analysis.apiStyle)
559
+ lines.push(`API: ${analysis.apiStyle}`);
560
+ if (analysis.deployTarget)
561
+ lines.push(`Deploy: ${analysis.deployTarget}`);
562
+ if (analysis.hasDocker)
563
+ lines.push("Docker: yes");
564
+ if (analysis.ciPlatform)
565
+ lines.push(`CI/CD: ${analysis.ciPlatform}`);
566
+ if (Object.keys(analysis.buildCommands).length > 0) {
567
+ lines.push("Build commands:");
568
+ for (const [key, value] of Object.entries(analysis.buildCommands)) {
569
+ lines.push(` ${key}: ${value}`);
570
+ }
571
+ }
572
+ if (Object.keys(analysis.testCommands).length > 0) {
573
+ lines.push("Test commands:");
574
+ for (const [key, value] of Object.entries(analysis.testCommands)) {
575
+ lines.push(` ${key}: ${value}`);
576
+ }
577
+ }
578
+ if (analysis.keyDependencies.length > 0) {
579
+ lines.push("Key dependencies:");
580
+ for (const dep of analysis.keyDependencies) {
581
+ lines.push(` ${dep.name} (${dep.category}) — ${dep.description}`);
582
+ }
583
+ }
584
+ if (analysis.patterns.length > 0) {
585
+ lines.push("Detected patterns:");
586
+ for (const p of analysis.patterns) {
587
+ lines.push(` ${p.name} — ${p.description} [${p.confidence}]`);
588
+ }
589
+ }
590
+ if (analysis.envVarNames.length > 0) {
591
+ lines.push(`Environment variables: ${analysis.envVarNames.join(", ")}`);
592
+ }
593
+ return lines.join("\n");
594
+ }
595
+ //# sourceMappingURL=project-analyzer.js.map