spec-gen-cli 1.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 (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1078 -0
  3. package/dist/api/analyze.d.ts +17 -0
  4. package/dist/api/analyze.d.ts.map +1 -0
  5. package/dist/api/analyze.js +109 -0
  6. package/dist/api/analyze.js.map +1 -0
  7. package/dist/api/drift.d.ts +21 -0
  8. package/dist/api/drift.d.ts.map +1 -0
  9. package/dist/api/drift.js +145 -0
  10. package/dist/api/drift.js.map +1 -0
  11. package/dist/api/generate.d.ts +18 -0
  12. package/dist/api/generate.d.ts.map +1 -0
  13. package/dist/api/generate.js +251 -0
  14. package/dist/api/generate.js.map +1 -0
  15. package/dist/api/index.d.ts +39 -0
  16. package/dist/api/index.d.ts.map +1 -0
  17. package/dist/api/index.js +32 -0
  18. package/dist/api/index.js.map +1 -0
  19. package/dist/api/init.d.ts +18 -0
  20. package/dist/api/init.d.ts.map +1 -0
  21. package/dist/api/init.js +82 -0
  22. package/dist/api/init.js.map +1 -0
  23. package/dist/api/run.d.ts +19 -0
  24. package/dist/api/run.d.ts.map +1 -0
  25. package/dist/api/run.js +291 -0
  26. package/dist/api/run.js.map +1 -0
  27. package/dist/api/specs.d.ts +49 -0
  28. package/dist/api/specs.d.ts.map +1 -0
  29. package/dist/api/specs.js +136 -0
  30. package/dist/api/specs.js.map +1 -0
  31. package/dist/api/types.d.ts +176 -0
  32. package/dist/api/types.d.ts.map +1 -0
  33. package/dist/api/types.js +9 -0
  34. package/dist/api/types.js.map +1 -0
  35. package/dist/api/verify.d.ts +20 -0
  36. package/dist/api/verify.d.ts.map +1 -0
  37. package/dist/api/verify.js +117 -0
  38. package/dist/api/verify.js.map +1 -0
  39. package/dist/cli/commands/analyze.d.ts +27 -0
  40. package/dist/cli/commands/analyze.d.ts.map +1 -0
  41. package/dist/cli/commands/analyze.js +485 -0
  42. package/dist/cli/commands/analyze.js.map +1 -0
  43. package/dist/cli/commands/drift.d.ts +9 -0
  44. package/dist/cli/commands/drift.d.ts.map +1 -0
  45. package/dist/cli/commands/drift.js +540 -0
  46. package/dist/cli/commands/drift.js.map +1 -0
  47. package/dist/cli/commands/generate.d.ts +9 -0
  48. package/dist/cli/commands/generate.d.ts.map +1 -0
  49. package/dist/cli/commands/generate.js +633 -0
  50. package/dist/cli/commands/generate.js.map +1 -0
  51. package/dist/cli/commands/init.d.ts +9 -0
  52. package/dist/cli/commands/init.d.ts.map +1 -0
  53. package/dist/cli/commands/init.js +171 -0
  54. package/dist/cli/commands/init.js.map +1 -0
  55. package/dist/cli/commands/mcp.d.ts +638 -0
  56. package/dist/cli/commands/mcp.d.ts.map +1 -0
  57. package/dist/cli/commands/mcp.js +574 -0
  58. package/dist/cli/commands/mcp.js.map +1 -0
  59. package/dist/cli/commands/run.d.ts +24 -0
  60. package/dist/cli/commands/run.d.ts.map +1 -0
  61. package/dist/cli/commands/run.js +546 -0
  62. package/dist/cli/commands/run.js.map +1 -0
  63. package/dist/cli/commands/verify.d.ts +9 -0
  64. package/dist/cli/commands/verify.d.ts.map +1 -0
  65. package/dist/cli/commands/verify.js +417 -0
  66. package/dist/cli/commands/verify.js.map +1 -0
  67. package/dist/cli/commands/view.d.ts +9 -0
  68. package/dist/cli/commands/view.d.ts.map +1 -0
  69. package/dist/cli/commands/view.js +511 -0
  70. package/dist/cli/commands/view.js.map +1 -0
  71. package/dist/cli/index.d.ts +9 -0
  72. package/dist/cli/index.d.ts.map +1 -0
  73. package/dist/cli/index.js +83 -0
  74. package/dist/cli/index.js.map +1 -0
  75. package/dist/core/analyzer/architecture-writer.d.ts +67 -0
  76. package/dist/core/analyzer/architecture-writer.d.ts.map +1 -0
  77. package/dist/core/analyzer/architecture-writer.js +209 -0
  78. package/dist/core/analyzer/architecture-writer.js.map +1 -0
  79. package/dist/core/analyzer/artifact-generator.d.ts +222 -0
  80. package/dist/core/analyzer/artifact-generator.d.ts.map +1 -0
  81. package/dist/core/analyzer/artifact-generator.js +726 -0
  82. package/dist/core/analyzer/artifact-generator.js.map +1 -0
  83. package/dist/core/analyzer/call-graph.d.ts +83 -0
  84. package/dist/core/analyzer/call-graph.d.ts.map +1 -0
  85. package/dist/core/analyzer/call-graph.js +827 -0
  86. package/dist/core/analyzer/call-graph.js.map +1 -0
  87. package/dist/core/analyzer/code-shaper.d.ts +33 -0
  88. package/dist/core/analyzer/code-shaper.d.ts.map +1 -0
  89. package/dist/core/analyzer/code-shaper.js +149 -0
  90. package/dist/core/analyzer/code-shaper.js.map +1 -0
  91. package/dist/core/analyzer/dependency-graph.d.ts +179 -0
  92. package/dist/core/analyzer/dependency-graph.d.ts.map +1 -0
  93. package/dist/core/analyzer/dependency-graph.js +574 -0
  94. package/dist/core/analyzer/dependency-graph.js.map +1 -0
  95. package/dist/core/analyzer/duplicate-detector.d.ts +52 -0
  96. package/dist/core/analyzer/duplicate-detector.d.ts.map +1 -0
  97. package/dist/core/analyzer/duplicate-detector.js +279 -0
  98. package/dist/core/analyzer/duplicate-detector.js.map +1 -0
  99. package/dist/core/analyzer/embedding-service.d.ts +50 -0
  100. package/dist/core/analyzer/embedding-service.d.ts.map +1 -0
  101. package/dist/core/analyzer/embedding-service.js +104 -0
  102. package/dist/core/analyzer/embedding-service.js.map +1 -0
  103. package/dist/core/analyzer/file-walker.d.ts +78 -0
  104. package/dist/core/analyzer/file-walker.d.ts.map +1 -0
  105. package/dist/core/analyzer/file-walker.js +531 -0
  106. package/dist/core/analyzer/file-walker.js.map +1 -0
  107. package/dist/core/analyzer/import-parser.d.ts +91 -0
  108. package/dist/core/analyzer/import-parser.d.ts.map +1 -0
  109. package/dist/core/analyzer/import-parser.js +720 -0
  110. package/dist/core/analyzer/import-parser.js.map +1 -0
  111. package/dist/core/analyzer/index.d.ts +10 -0
  112. package/dist/core/analyzer/index.d.ts.map +1 -0
  113. package/dist/core/analyzer/index.js +10 -0
  114. package/dist/core/analyzer/index.js.map +1 -0
  115. package/dist/core/analyzer/refactor-analyzer.d.ts +80 -0
  116. package/dist/core/analyzer/refactor-analyzer.d.ts.map +1 -0
  117. package/dist/core/analyzer/refactor-analyzer.js +339 -0
  118. package/dist/core/analyzer/refactor-analyzer.js.map +1 -0
  119. package/dist/core/analyzer/repository-mapper.d.ts +150 -0
  120. package/dist/core/analyzer/repository-mapper.d.ts.map +1 -0
  121. package/dist/core/analyzer/repository-mapper.js +731 -0
  122. package/dist/core/analyzer/repository-mapper.js.map +1 -0
  123. package/dist/core/analyzer/signature-extractor.d.ts +31 -0
  124. package/dist/core/analyzer/signature-extractor.d.ts.map +1 -0
  125. package/dist/core/analyzer/signature-extractor.js +387 -0
  126. package/dist/core/analyzer/signature-extractor.js.map +1 -0
  127. package/dist/core/analyzer/significance-scorer.d.ts +79 -0
  128. package/dist/core/analyzer/significance-scorer.d.ts.map +1 -0
  129. package/dist/core/analyzer/significance-scorer.js +407 -0
  130. package/dist/core/analyzer/significance-scorer.js.map +1 -0
  131. package/dist/core/analyzer/subgraph-extractor.d.ts +43 -0
  132. package/dist/core/analyzer/subgraph-extractor.d.ts.map +1 -0
  133. package/dist/core/analyzer/subgraph-extractor.js +129 -0
  134. package/dist/core/analyzer/subgraph-extractor.js.map +1 -0
  135. package/dist/core/analyzer/vector-index.d.ts +63 -0
  136. package/dist/core/analyzer/vector-index.d.ts.map +1 -0
  137. package/dist/core/analyzer/vector-index.js +169 -0
  138. package/dist/core/analyzer/vector-index.js.map +1 -0
  139. package/dist/core/drift/drift-detector.d.ts +102 -0
  140. package/dist/core/drift/drift-detector.d.ts.map +1 -0
  141. package/dist/core/drift/drift-detector.js +597 -0
  142. package/dist/core/drift/drift-detector.js.map +1 -0
  143. package/dist/core/drift/git-diff.d.ts +55 -0
  144. package/dist/core/drift/git-diff.d.ts.map +1 -0
  145. package/dist/core/drift/git-diff.js +356 -0
  146. package/dist/core/drift/git-diff.js.map +1 -0
  147. package/dist/core/drift/index.d.ts +12 -0
  148. package/dist/core/drift/index.d.ts.map +1 -0
  149. package/dist/core/drift/index.js +9 -0
  150. package/dist/core/drift/index.js.map +1 -0
  151. package/dist/core/drift/spec-mapper.d.ts +73 -0
  152. package/dist/core/drift/spec-mapper.d.ts.map +1 -0
  153. package/dist/core/drift/spec-mapper.js +353 -0
  154. package/dist/core/drift/spec-mapper.js.map +1 -0
  155. package/dist/core/generator/adr-generator.d.ts +32 -0
  156. package/dist/core/generator/adr-generator.d.ts.map +1 -0
  157. package/dist/core/generator/adr-generator.js +192 -0
  158. package/dist/core/generator/adr-generator.js.map +1 -0
  159. package/dist/core/generator/index.d.ts +9 -0
  160. package/dist/core/generator/index.d.ts.map +1 -0
  161. package/dist/core/generator/index.js +12 -0
  162. package/dist/core/generator/index.js.map +1 -0
  163. package/dist/core/generator/mapping-generator.d.ts +54 -0
  164. package/dist/core/generator/mapping-generator.d.ts.map +1 -0
  165. package/dist/core/generator/mapping-generator.js +239 -0
  166. package/dist/core/generator/mapping-generator.js.map +1 -0
  167. package/dist/core/generator/openspec-compat.d.ts +160 -0
  168. package/dist/core/generator/openspec-compat.d.ts.map +1 -0
  169. package/dist/core/generator/openspec-compat.js +523 -0
  170. package/dist/core/generator/openspec-compat.js.map +1 -0
  171. package/dist/core/generator/openspec-format-generator.d.ts +111 -0
  172. package/dist/core/generator/openspec-format-generator.d.ts.map +1 -0
  173. package/dist/core/generator/openspec-format-generator.js +817 -0
  174. package/dist/core/generator/openspec-format-generator.js.map +1 -0
  175. package/dist/core/generator/openspec-writer.d.ts +131 -0
  176. package/dist/core/generator/openspec-writer.d.ts.map +1 -0
  177. package/dist/core/generator/openspec-writer.js +379 -0
  178. package/dist/core/generator/openspec-writer.js.map +1 -0
  179. package/dist/core/generator/prompts.d.ts +35 -0
  180. package/dist/core/generator/prompts.d.ts.map +1 -0
  181. package/dist/core/generator/prompts.js +212 -0
  182. package/dist/core/generator/prompts.js.map +1 -0
  183. package/dist/core/generator/spec-pipeline.d.ts +94 -0
  184. package/dist/core/generator/spec-pipeline.d.ts.map +1 -0
  185. package/dist/core/generator/spec-pipeline.js +474 -0
  186. package/dist/core/generator/spec-pipeline.js.map +1 -0
  187. package/dist/core/generator/stages/stage1-survey.d.ts +19 -0
  188. package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -0
  189. package/dist/core/generator/stages/stage1-survey.js +105 -0
  190. package/dist/core/generator/stages/stage1-survey.js.map +1 -0
  191. package/dist/core/generator/stages/stage2-entities.d.ts +11 -0
  192. package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -0
  193. package/dist/core/generator/stages/stage2-entities.js +67 -0
  194. package/dist/core/generator/stages/stage2-entities.js.map +1 -0
  195. package/dist/core/generator/stages/stage3-services.d.ts +11 -0
  196. package/dist/core/generator/stages/stage3-services.d.ts.map +1 -0
  197. package/dist/core/generator/stages/stage3-services.js +75 -0
  198. package/dist/core/generator/stages/stage3-services.js.map +1 -0
  199. package/dist/core/generator/stages/stage4-api.d.ts +11 -0
  200. package/dist/core/generator/stages/stage4-api.d.ts.map +1 -0
  201. package/dist/core/generator/stages/stage4-api.js +65 -0
  202. package/dist/core/generator/stages/stage4-api.js.map +1 -0
  203. package/dist/core/generator/stages/stage5-architecture.d.ts +10 -0
  204. package/dist/core/generator/stages/stage5-architecture.d.ts.map +1 -0
  205. package/dist/core/generator/stages/stage5-architecture.js +62 -0
  206. package/dist/core/generator/stages/stage5-architecture.js.map +1 -0
  207. package/dist/core/generator/stages/stage6-adr.d.ts +8 -0
  208. package/dist/core/generator/stages/stage6-adr.d.ts.map +1 -0
  209. package/dist/core/generator/stages/stage6-adr.js +41 -0
  210. package/dist/core/generator/stages/stage6-adr.js.map +1 -0
  211. package/dist/core/services/chat-agent.d.ts +45 -0
  212. package/dist/core/services/chat-agent.d.ts.map +1 -0
  213. package/dist/core/services/chat-agent.js +310 -0
  214. package/dist/core/services/chat-agent.js.map +1 -0
  215. package/dist/core/services/chat-tools.d.ts +32 -0
  216. package/dist/core/services/chat-tools.d.ts.map +1 -0
  217. package/dist/core/services/chat-tools.js +270 -0
  218. package/dist/core/services/chat-tools.js.map +1 -0
  219. package/dist/core/services/config-manager.d.ts +61 -0
  220. package/dist/core/services/config-manager.d.ts.map +1 -0
  221. package/dist/core/services/config-manager.js +143 -0
  222. package/dist/core/services/config-manager.js.map +1 -0
  223. package/dist/core/services/gitignore-manager.d.ts +29 -0
  224. package/dist/core/services/gitignore-manager.d.ts.map +1 -0
  225. package/dist/core/services/gitignore-manager.js +106 -0
  226. package/dist/core/services/gitignore-manager.js.map +1 -0
  227. package/dist/core/services/index.d.ts +8 -0
  228. package/dist/core/services/index.d.ts.map +1 -0
  229. package/dist/core/services/index.js +8 -0
  230. package/dist/core/services/index.js.map +1 -0
  231. package/dist/core/services/llm-service.d.ts +336 -0
  232. package/dist/core/services/llm-service.d.ts.map +1 -0
  233. package/dist/core/services/llm-service.js +1155 -0
  234. package/dist/core/services/llm-service.js.map +1 -0
  235. package/dist/core/services/mcp-handlers/analysis.d.ts +42 -0
  236. package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -0
  237. package/dist/core/services/mcp-handlers/analysis.js +300 -0
  238. package/dist/core/services/mcp-handlers/analysis.js.map +1 -0
  239. package/dist/core/services/mcp-handlers/graph.d.ts +65 -0
  240. package/dist/core/services/mcp-handlers/graph.d.ts.map +1 -0
  241. package/dist/core/services/mcp-handlers/graph.js +509 -0
  242. package/dist/core/services/mcp-handlers/graph.js.map +1 -0
  243. package/dist/core/services/mcp-handlers/semantic.d.ts +38 -0
  244. package/dist/core/services/mcp-handlers/semantic.d.ts.map +1 -0
  245. package/dist/core/services/mcp-handlers/semantic.js +172 -0
  246. package/dist/core/services/mcp-handlers/semantic.js.map +1 -0
  247. package/dist/core/services/mcp-handlers/utils.d.ts +21 -0
  248. package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -0
  249. package/dist/core/services/mcp-handlers/utils.js +62 -0
  250. package/dist/core/services/mcp-handlers/utils.js.map +1 -0
  251. package/dist/core/services/project-detector.d.ts +32 -0
  252. package/dist/core/services/project-detector.d.ts.map +1 -0
  253. package/dist/core/services/project-detector.js +111 -0
  254. package/dist/core/services/project-detector.js.map +1 -0
  255. package/dist/core/verifier/index.d.ts +5 -0
  256. package/dist/core/verifier/index.d.ts.map +1 -0
  257. package/dist/core/verifier/index.js +5 -0
  258. package/dist/core/verifier/index.js.map +1 -0
  259. package/dist/core/verifier/verification-engine.d.ts +226 -0
  260. package/dist/core/verifier/verification-engine.d.ts.map +1 -0
  261. package/dist/core/verifier/verification-engine.js +681 -0
  262. package/dist/core/verifier/verification-engine.js.map +1 -0
  263. package/dist/types/index.d.ts +252 -0
  264. package/dist/types/index.d.ts.map +1 -0
  265. package/dist/types/index.js +5 -0
  266. package/dist/types/index.js.map +1 -0
  267. package/dist/types/pipeline.d.ts +148 -0
  268. package/dist/types/pipeline.d.ts.map +1 -0
  269. package/dist/types/pipeline.js +5 -0
  270. package/dist/types/pipeline.js.map +1 -0
  271. package/dist/utils/errors.d.ts +51 -0
  272. package/dist/utils/errors.d.ts.map +1 -0
  273. package/dist/utils/errors.js +128 -0
  274. package/dist/utils/errors.js.map +1 -0
  275. package/dist/utils/logger.d.ts +149 -0
  276. package/dist/utils/logger.d.ts.map +1 -0
  277. package/dist/utils/logger.js +331 -0
  278. package/dist/utils/logger.js.map +1 -0
  279. package/dist/utils/progress.d.ts +142 -0
  280. package/dist/utils/progress.d.ts.map +1 -0
  281. package/dist/utils/progress.js +280 -0
  282. package/dist/utils/progress.js.map +1 -0
  283. package/dist/utils/prompts.d.ts +53 -0
  284. package/dist/utils/prompts.d.ts.map +1 -0
  285. package/dist/utils/prompts.js +199 -0
  286. package/dist/utils/prompts.js.map +1 -0
  287. package/dist/utils/shutdown.d.ts +89 -0
  288. package/dist/utils/shutdown.d.ts.map +1 -0
  289. package/dist/utils/shutdown.js +237 -0
  290. package/dist/utils/shutdown.js.map +1 -0
  291. package/package.json +114 -0
  292. package/src/viewer/InteractiveGraphViewer.jsx +1486 -0
  293. package/src/viewer/app/index.html +17 -0
  294. package/src/viewer/app/main.jsx +13 -0
  295. package/src/viewer/components/ArchitectureView.jsx +177 -0
  296. package/src/viewer/components/ChatPanel.jsx +448 -0
  297. package/src/viewer/components/ClusterGraph.jsx +441 -0
  298. package/src/viewer/components/FilterBar.jsx +179 -0
  299. package/src/viewer/components/FlatGraph.jsx +275 -0
  300. package/src/viewer/components/MicroComponents.jsx +83 -0
  301. package/src/viewer/hooks/usePanZoom.js +79 -0
  302. package/src/viewer/utils/constants.js +47 -0
  303. package/src/viewer/utils/graph-helpers.js +291 -0
@@ -0,0 +1,731 @@
1
+ /**
2
+ * Repository Mapper
3
+ *
4
+ * Combines file walking and significance scoring into a comprehensive "map"
5
+ * of the repository that guides all subsequent analysis.
6
+ */
7
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
8
+ import { join, basename } from 'node:path';
9
+ import { FileWalker } from './file-walker.js';
10
+ import { SignificanceScorer } from './significance-scorer.js';
11
+ const FRAMEWORK_DETECTORS = [
12
+ // JavaScript/TypeScript Frameworks
13
+ {
14
+ name: 'React',
15
+ category: 'frontend',
16
+ detect: (files, pkg) => {
17
+ const evidence = [];
18
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
19
+ if (deps['react'])
20
+ evidence.push('react in dependencies');
21
+ if (files.some(f => f.extension === '.jsx' || f.extension === '.tsx')) {
22
+ evidence.push('.jsx/.tsx files found');
23
+ }
24
+ return {
25
+ detected: evidence.length > 0,
26
+ confidence: evidence.length >= 2 ? 'high' : 'medium',
27
+ evidence,
28
+ };
29
+ },
30
+ },
31
+ {
32
+ name: 'Next.js',
33
+ category: 'frontend',
34
+ detect: (files, pkg) => {
35
+ const evidence = [];
36
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
37
+ if (deps['next'])
38
+ evidence.push('next in dependencies');
39
+ if (files.some(f => f.name.startsWith('next.config'))) {
40
+ evidence.push('next.config.* found');
41
+ }
42
+ if (files.some(f => f.directory === 'pages' || f.directory === 'app' || f.directory.startsWith('pages/') || f.directory.startsWith('app/'))) {
43
+ evidence.push('pages/ or app/ directory found');
44
+ }
45
+ return {
46
+ detected: evidence.length > 0,
47
+ confidence: evidence.length >= 2 ? 'high' : 'medium',
48
+ evidence,
49
+ };
50
+ },
51
+ },
52
+ {
53
+ name: 'Express',
54
+ category: 'backend',
55
+ detect: (files, pkg) => {
56
+ const evidence = [];
57
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
58
+ if (deps['express'])
59
+ evidence.push('express in dependencies');
60
+ return {
61
+ detected: evidence.length > 0,
62
+ confidence: 'high',
63
+ evidence,
64
+ };
65
+ },
66
+ },
67
+ {
68
+ name: 'NestJS',
69
+ category: 'backend',
70
+ detect: (files, pkg) => {
71
+ const evidence = [];
72
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
73
+ if (Object.keys(deps).some(d => d.startsWith('@nestjs/'))) {
74
+ evidence.push('@nestjs/* packages in dependencies');
75
+ }
76
+ return {
77
+ detected: evidence.length > 0,
78
+ confidence: 'high',
79
+ evidence,
80
+ };
81
+ },
82
+ },
83
+ {
84
+ name: 'Vue',
85
+ category: 'frontend',
86
+ detect: (files, pkg) => {
87
+ const evidence = [];
88
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
89
+ if (deps['vue'])
90
+ evidence.push('vue in dependencies');
91
+ if (files.some(f => f.extension === '.vue')) {
92
+ evidence.push('.vue files found');
93
+ }
94
+ return {
95
+ detected: evidence.length > 0,
96
+ confidence: evidence.length >= 2 ? 'high' : 'medium',
97
+ evidence,
98
+ };
99
+ },
100
+ },
101
+ {
102
+ name: 'Angular',
103
+ category: 'frontend',
104
+ detect: (files, pkg) => {
105
+ const evidence = [];
106
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
107
+ if (Object.keys(deps).some(d => d.startsWith('@angular/'))) {
108
+ evidence.push('@angular/* packages in dependencies');
109
+ }
110
+ if (files.some(f => f.name === 'angular.json')) {
111
+ evidence.push('angular.json found');
112
+ }
113
+ return {
114
+ detected: evidence.length > 0,
115
+ confidence: evidence.length >= 2 ? 'high' : 'medium',
116
+ evidence,
117
+ };
118
+ },
119
+ },
120
+ // Testing Frameworks
121
+ {
122
+ name: 'Jest',
123
+ category: 'testing',
124
+ detect: (files, pkg) => {
125
+ const evidence = [];
126
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
127
+ if (deps['jest'])
128
+ evidence.push('jest in dependencies');
129
+ if (files.some(f => f.name.startsWith('jest.config'))) {
130
+ evidence.push('jest.config.* found');
131
+ }
132
+ return {
133
+ detected: evidence.length > 0,
134
+ confidence: 'high',
135
+ evidence,
136
+ };
137
+ },
138
+ },
139
+ {
140
+ name: 'Vitest',
141
+ category: 'testing',
142
+ detect: (files, pkg) => {
143
+ const evidence = [];
144
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
145
+ if (deps['vitest'])
146
+ evidence.push('vitest in dependencies');
147
+ if (files.some(f => f.name.startsWith('vitest.config'))) {
148
+ evidence.push('vitest.config.* found');
149
+ }
150
+ return {
151
+ detected: evidence.length > 0,
152
+ confidence: 'high',
153
+ evidence,
154
+ };
155
+ },
156
+ },
157
+ // Database
158
+ {
159
+ name: 'PostgreSQL',
160
+ category: 'database',
161
+ detect: (files, pkg) => {
162
+ const evidence = [];
163
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
164
+ if (deps['pg'] || deps['postgres'] || deps['@prisma/client']) {
165
+ evidence.push('PostgreSQL client in dependencies');
166
+ }
167
+ return {
168
+ detected: evidence.length > 0,
169
+ confidence: 'medium',
170
+ evidence,
171
+ };
172
+ },
173
+ },
174
+ {
175
+ name: 'MongoDB',
176
+ category: 'database',
177
+ detect: (files, pkg) => {
178
+ const evidence = [];
179
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
180
+ if (deps['mongodb'] || deps['mongoose']) {
181
+ evidence.push('MongoDB client in dependencies');
182
+ }
183
+ return {
184
+ detected: evidence.length > 0,
185
+ confidence: 'high',
186
+ evidence,
187
+ };
188
+ },
189
+ },
190
+ // Auth
191
+ {
192
+ name: 'JWT Auth',
193
+ category: 'auth',
194
+ detect: (files, pkg) => {
195
+ const evidence = [];
196
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
197
+ if (deps['jsonwebtoken'] || deps['jose']) {
198
+ evidence.push('JWT library in dependencies');
199
+ }
200
+ return {
201
+ detected: evidence.length > 0,
202
+ confidence: 'high',
203
+ evidence,
204
+ };
205
+ },
206
+ },
207
+ {
208
+ name: 'Passport',
209
+ category: 'auth',
210
+ detect: (files, pkg) => {
211
+ const evidence = [];
212
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
213
+ if (deps['passport']) {
214
+ evidence.push('passport in dependencies');
215
+ }
216
+ return {
217
+ detected: evidence.length > 0,
218
+ confidence: 'high',
219
+ evidence,
220
+ };
221
+ },
222
+ },
223
+ // CI/CD
224
+ {
225
+ name: 'GitHub Actions',
226
+ category: 'ci',
227
+ detect: (files) => {
228
+ const evidence = [];
229
+ if (files.some(f => f.path.includes('.github/workflows'))) {
230
+ evidence.push('.github/workflows directory found');
231
+ }
232
+ return {
233
+ detected: evidence.length > 0,
234
+ confidence: 'high',
235
+ evidence,
236
+ };
237
+ },
238
+ },
239
+ {
240
+ name: 'GitLab CI',
241
+ category: 'ci',
242
+ detect: (files) => {
243
+ const evidence = [];
244
+ if (files.some(f => f.name === '.gitlab-ci.yml')) {
245
+ evidence.push('.gitlab-ci.yml found');
246
+ }
247
+ return {
248
+ detected: evidence.length > 0,
249
+ confidence: 'high',
250
+ evidence,
251
+ };
252
+ },
253
+ },
254
+ ];
255
+ // ============================================================================
256
+ // LAYER DETECTION
257
+ // ============================================================================
258
+ const LAYER_PATTERNS = {
259
+ presentation: [
260
+ /\/(components?|views?|pages?|ui|screens?|layouts?)\//i,
261
+ /\.(jsx|tsx|vue)$/,
262
+ /\.component\./,
263
+ /\.page\./,
264
+ ],
265
+ business: [
266
+ /\/(services?|domain|business|core|logic|usecases?)\//i,
267
+ /\.service\./,
268
+ /\.usecase\./,
269
+ ],
270
+ data: [
271
+ /\/(models?|entities?|repositories?|schemas?|db|database|data)\//i,
272
+ /\.model\./,
273
+ /\.entity\./,
274
+ /\.repository\./,
275
+ /\.schema\./,
276
+ ],
277
+ infrastructure: [
278
+ /\/(config|utils?|helpers?|lib|middleware|infra|infrastructure)\//i,
279
+ /\.config\./,
280
+ /\.util\./,
281
+ /\.helper\./,
282
+ /\.middleware\./,
283
+ ],
284
+ };
285
+ function detectLayer(file) {
286
+ const pathAndName = file.path + '/' + file.name;
287
+ for (const [layer, patterns] of Object.entries(LAYER_PATTERNS)) {
288
+ for (const pattern of patterns) {
289
+ if (pattern.test(pathAndName)) {
290
+ return layer;
291
+ }
292
+ }
293
+ }
294
+ return null;
295
+ }
296
+ // ============================================================================
297
+ // DOMAIN INFERENCE
298
+ // ============================================================================
299
+ /**
300
+ * Infer domains from file paths and names
301
+ */
302
+ function inferDomains(files) {
303
+ const domains = {};
304
+ // Common domain prefixes to look for
305
+ const domainPrefixes = new Map();
306
+ for (const file of files) {
307
+ // Skip test and config files for domain inference
308
+ if (file.isTest || file.isConfig)
309
+ continue;
310
+ // Extract potential domain from path
311
+ const pathParts = file.path.split('/');
312
+ // Check for domain-like directory names (skip common non-domain dirs)
313
+ const skipDirs = new Set(['src', 'lib', 'app', 'core', 'common', 'shared', 'utils', 'helpers', 'config']);
314
+ for (const part of pathParts) {
315
+ if (part && !skipDirs.has(part.toLowerCase()) && !part.startsWith('.')) {
316
+ // This could be a domain
317
+ const domain = part.toLowerCase();
318
+ if (!domains[domain]) {
319
+ domains[domain] = [];
320
+ }
321
+ domains[domain].push(file);
322
+ break; // Only use first domain-like directory
323
+ }
324
+ }
325
+ // Also check file name prefixes (e.g., user-service.ts -> user)
326
+ const nameWithoutExt = file.name.replace(/\.[^.]+$/, '');
327
+ const nameParts = nameWithoutExt.split(/[-_.]/);
328
+ if (nameParts.length > 1) {
329
+ const prefix = nameParts[0].toLowerCase();
330
+ if (prefix.length > 2 && !skipDirs.has(prefix)) {
331
+ if (!domainPrefixes.has(prefix)) {
332
+ domainPrefixes.set(prefix, []);
333
+ }
334
+ domainPrefixes.get(prefix).push(file.path);
335
+ }
336
+ }
337
+ }
338
+ // Add domains from file prefixes if they have multiple files
339
+ for (const [prefix, filePaths] of domainPrefixes) {
340
+ if (filePaths.length >= 2 && !domains[prefix]) {
341
+ domains[prefix] = files.filter(f => filePaths.includes(f.path));
342
+ }
343
+ }
344
+ // Remove domains with only 1 file
345
+ for (const domain of Object.keys(domains)) {
346
+ if (domains[domain].length < 2) {
347
+ delete domains[domain];
348
+ }
349
+ }
350
+ return domains;
351
+ }
352
+ // ============================================================================
353
+ // REPOSITORY MAPPER CLASS
354
+ // ============================================================================
355
+ export class RepositoryMapper {
356
+ rootPath;
357
+ options;
358
+ packageJson = null;
359
+ constructor(rootPath, options = {}) {
360
+ this.rootPath = rootPath;
361
+ this.options = {
362
+ maxFiles: options.maxFiles ?? 500,
363
+ includePatterns: options.includePatterns ?? [],
364
+ excludePatterns: options.excludePatterns ?? [],
365
+ scoringConfig: options.scoringConfig ?? {},
366
+ onProgress: options.onProgress ?? (() => { }),
367
+ outputDir: options.outputDir ?? join(rootPath, '.spec-gen', 'analysis'),
368
+ };
369
+ }
370
+ /**
371
+ * Load package.json if it exists
372
+ */
373
+ async loadPackageJson() {
374
+ try {
375
+ const content = await readFile(join(this.rootPath, 'package.json'), 'utf-8');
376
+ this.packageJson = JSON.parse(content);
377
+ }
378
+ catch {
379
+ this.packageJson = null;
380
+ }
381
+ }
382
+ /**
383
+ * Get project name from package.json or directory name
384
+ */
385
+ getProjectName() {
386
+ if (this.packageJson?.name && typeof this.packageJson.name === 'string') {
387
+ return this.packageJson.name;
388
+ }
389
+ return basename(this.rootPath);
390
+ }
391
+ /**
392
+ * Detect project type
393
+ */
394
+ detectProjectType(files) {
395
+ // Check for language-specific files
396
+ const hasPackageJson = files.some(f => f.name === 'package.json');
397
+ const hasPyproject = files.some(f => f.name === 'pyproject.toml' || f.name === 'setup.py');
398
+ const hasCargoToml = files.some(f => f.name === 'Cargo.toml');
399
+ const hasGoMod = files.some(f => f.name === 'go.mod');
400
+ if (hasPackageJson)
401
+ return 'nodejs';
402
+ if (hasPyproject)
403
+ return 'python';
404
+ if (hasCargoToml)
405
+ return 'rust';
406
+ if (hasGoMod)
407
+ return 'go';
408
+ return 'unknown';
409
+ }
410
+ /**
411
+ * Calculate language breakdown
412
+ */
413
+ calculateLanguages(files) {
414
+ const extCounts = {};
415
+ const extToLang = {
416
+ '.ts': 'TypeScript',
417
+ '.tsx': 'TypeScript (React)',
418
+ '.js': 'JavaScript',
419
+ '.jsx': 'JavaScript (React)',
420
+ '.py': 'Python',
421
+ '.rs': 'Rust',
422
+ '.go': 'Go',
423
+ '.java': 'Java',
424
+ '.rb': 'Ruby',
425
+ '.php': 'PHP',
426
+ '.vue': 'Vue',
427
+ '.svelte': 'Svelte',
428
+ '.css': 'CSS',
429
+ '.scss': 'SCSS',
430
+ '.less': 'LESS',
431
+ '.html': 'HTML',
432
+ '.json': 'JSON',
433
+ '.yaml': 'YAML',
434
+ '.yml': 'YAML',
435
+ '.md': 'Markdown',
436
+ '.sql': 'SQL',
437
+ '.graphql': 'GraphQL',
438
+ '.prisma': 'Prisma',
439
+ };
440
+ for (const file of files) {
441
+ const ext = file.extension.toLowerCase();
442
+ extCounts[ext] = (extCounts[ext] ?? 0) + 1;
443
+ }
444
+ const total = files.length;
445
+ const languages = [];
446
+ for (const [ext, count] of Object.entries(extCounts)) {
447
+ if (count > 0) {
448
+ languages.push({
449
+ language: extToLang[ext] ?? ext.slice(1).toUpperCase(),
450
+ extension: ext,
451
+ fileCount: count,
452
+ percentage: Math.round((count / total) * 100),
453
+ });
454
+ }
455
+ }
456
+ // Sort by file count descending
457
+ languages.sort((a, b) => b.fileCount - a.fileCount);
458
+ return languages;
459
+ }
460
+ /**
461
+ * Detect frameworks
462
+ */
463
+ detectFrameworks(files) {
464
+ const frameworks = [];
465
+ for (const detector of FRAMEWORK_DETECTORS) {
466
+ const result = detector.detect(files, this.packageJson);
467
+ if (result.detected) {
468
+ frameworks.push({
469
+ name: detector.name,
470
+ category: detector.category,
471
+ confidence: result.confidence,
472
+ evidence: result.evidence,
473
+ });
474
+ }
475
+ }
476
+ return frameworks;
477
+ }
478
+ /**
479
+ * Calculate directory statistics
480
+ */
481
+ calculateDirectoryStats(files) {
482
+ const dirStats = {};
483
+ for (const file of files) {
484
+ const dir = file.directory || '(root)';
485
+ if (!dirStats[dir]) {
486
+ dirStats[dir] = { files: [], totalScore: 0 };
487
+ }
488
+ dirStats[dir].files.push(file);
489
+ dirStats[dir].totalScore += file.score;
490
+ }
491
+ const stats = [];
492
+ for (const [path, data] of Object.entries(dirStats)) {
493
+ // Infer purpose from directory name
494
+ let purpose = 'unknown';
495
+ const pathLower = path.toLowerCase();
496
+ if (pathLower.includes('test') || pathLower.includes('spec'))
497
+ purpose = 'tests';
498
+ else if (pathLower.includes('component'))
499
+ purpose = 'components';
500
+ else if (pathLower.includes('service'))
501
+ purpose = 'services';
502
+ else if (pathLower.includes('model') || pathLower.includes('entity'))
503
+ purpose = 'models';
504
+ else if (pathLower.includes('route') || pathLower.includes('api'))
505
+ purpose = 'api';
506
+ else if (pathLower.includes('config'))
507
+ purpose = 'configuration';
508
+ else if (pathLower.includes('util') || pathLower.includes('helper'))
509
+ purpose = 'utilities';
510
+ else if (pathLower.includes('middleware'))
511
+ purpose = 'middleware';
512
+ else if (path === '(root)')
513
+ purpose = 'root';
514
+ else if (pathLower === 'src' || pathLower === 'lib')
515
+ purpose = 'source';
516
+ stats.push({
517
+ path,
518
+ fileCount: data.files.length,
519
+ purpose,
520
+ avgScore: Math.round(data.totalScore / data.files.length),
521
+ });
522
+ }
523
+ // Sort by file count descending
524
+ stats.sort((a, b) => b.fileCount - a.fileCount);
525
+ return stats;
526
+ }
527
+ /**
528
+ * Cluster files by various dimensions
529
+ */
530
+ clusterFiles(files) {
531
+ // By directory
532
+ const byDirectory = {};
533
+ for (const file of files) {
534
+ const dir = file.directory || '(root)';
535
+ if (!byDirectory[dir]) {
536
+ byDirectory[dir] = [];
537
+ }
538
+ byDirectory[dir].push(file);
539
+ }
540
+ // By domain (inferred)
541
+ const byDomain = inferDomains(files);
542
+ // By layer
543
+ const byLayer = {
544
+ presentation: [],
545
+ business: [],
546
+ data: [],
547
+ infrastructure: [],
548
+ };
549
+ for (const file of files) {
550
+ const layer = detectLayer(file);
551
+ if (layer) {
552
+ byLayer[layer].push(file);
553
+ }
554
+ }
555
+ return { byDirectory, byDomain, byLayer };
556
+ }
557
+ /**
558
+ * Generate the repository map
559
+ */
560
+ async map() {
561
+ this.options.onProgress?.('loading', 0);
562
+ // Load package.json
563
+ await this.loadPackageJson();
564
+ this.options.onProgress?.('walking', 10);
565
+ // Walk the directory
566
+ const walkerOptions = {
567
+ maxFiles: this.options.maxFiles,
568
+ includePatterns: this.options.includePatterns,
569
+ excludePatterns: this.options.excludePatterns,
570
+ onProgress: (progress) => {
571
+ const pct = 10 + Math.round((progress.filesFound / (this.options.maxFiles ?? 500)) * 30);
572
+ this.options.onProgress?.('walking', Math.min(pct, 40));
573
+ },
574
+ };
575
+ const walker = new FileWalker(this.rootPath, walkerOptions);
576
+ const walkResult = await walker.walk();
577
+ this.options.onProgress?.('scoring', 40);
578
+ // Score all files
579
+ const scorer = new SignificanceScorer(this.options.scoringConfig);
580
+ const scoredFiles = await scorer.scoreFiles(walkResult.files);
581
+ this.options.onProgress?.('analyzing', 70);
582
+ // Detect project type and frameworks
583
+ const projectType = this.detectProjectType(walkResult.files);
584
+ const languages = this.calculateLanguages(walkResult.files);
585
+ const frameworks = this.detectFrameworks(walkResult.files);
586
+ // Extract special file categories
587
+ const highValueFiles = scoredFiles.slice(0, 50); // Top 50
588
+ const entryPoints = scoredFiles.filter(f => f.isEntryPoint);
589
+ const schemaFiles = scoredFiles.filter(f => f.tags.includes('schema') ||
590
+ f.name.toLowerCase().includes('model') ||
591
+ f.name.toLowerCase().includes('entity') ||
592
+ f.name.toLowerCase().includes('schema'));
593
+ const configFiles = scoredFiles.filter(f => f.isConfig);
594
+ // Calculate directory stats and clusters
595
+ const directories = this.calculateDirectoryStats(scoredFiles);
596
+ const clusters = this.clusterFiles(scoredFiles);
597
+ this.options.onProgress?.('complete', 100);
598
+ // Build the map
599
+ const map = {
600
+ metadata: {
601
+ projectName: this.getProjectName(),
602
+ projectType,
603
+ rootPath: this.rootPath,
604
+ analyzedAt: new Date().toISOString(),
605
+ version: '1.0.0',
606
+ },
607
+ summary: {
608
+ totalFiles: walkResult.summary.totalFiles + walkResult.summary.skippedCount,
609
+ analyzedFiles: walkResult.summary.totalFiles,
610
+ skippedFiles: walkResult.summary.skippedCount,
611
+ languages,
612
+ frameworks,
613
+ directories,
614
+ },
615
+ highValueFiles,
616
+ entryPoints,
617
+ schemaFiles,
618
+ configFiles,
619
+ clusters,
620
+ allFiles: scoredFiles,
621
+ };
622
+ return map;
623
+ }
624
+ /**
625
+ * Write repository map to output directory
626
+ */
627
+ async writeOutput(map) {
628
+ // Ensure output directory exists
629
+ await mkdir(this.options.outputDir, { recursive: true });
630
+ // Write JSON map
631
+ const mapPath = join(this.options.outputDir, 'repository-map.json');
632
+ await writeFile(mapPath, JSON.stringify(map, null, 2), 'utf-8');
633
+ // Write summary markdown
634
+ const summaryPath = join(this.options.outputDir, 'SUMMARY.md');
635
+ const summary = this.generateSummaryMarkdown(map);
636
+ await writeFile(summaryPath, summary, 'utf-8');
637
+ }
638
+ /**
639
+ * Generate human-readable summary
640
+ */
641
+ generateSummaryMarkdown(map) {
642
+ const lines = [];
643
+ lines.push(`# Repository Analysis: ${map.metadata.projectName}`);
644
+ lines.push('');
645
+ lines.push(`> Generated by spec-gen v${map.metadata.version} on ${map.metadata.analyzedAt}`);
646
+ lines.push('');
647
+ // Overview
648
+ lines.push('## Overview');
649
+ lines.push('');
650
+ lines.push(`- **Project Type**: ${map.metadata.projectType}`);
651
+ lines.push(`- **Total Files**: ${map.summary.totalFiles}`);
652
+ lines.push(`- **Analyzed Files**: ${map.summary.analyzedFiles}`);
653
+ lines.push(`- **Skipped Files**: ${map.summary.skippedFiles}`);
654
+ lines.push('');
655
+ // Languages
656
+ lines.push('## Languages');
657
+ lines.push('');
658
+ lines.push('| Language | Files | Percentage |');
659
+ lines.push('|----------|-------|------------|');
660
+ for (const lang of map.summary.languages.slice(0, 10)) {
661
+ lines.push(`| ${lang.language} | ${lang.fileCount} | ${lang.percentage}% |`);
662
+ }
663
+ lines.push('');
664
+ // Frameworks
665
+ if (map.summary.frameworks.length > 0) {
666
+ lines.push('## Detected Frameworks');
667
+ lines.push('');
668
+ for (const fw of map.summary.frameworks) {
669
+ lines.push(`- **${fw.name}** (${fw.category}, ${fw.confidence} confidence)`);
670
+ for (const evidence of fw.evidence) {
671
+ lines.push(` - ${evidence}`);
672
+ }
673
+ }
674
+ lines.push('');
675
+ }
676
+ // High Value Files
677
+ lines.push('## High Value Files (Top 20)');
678
+ lines.push('');
679
+ lines.push('| File | Score | Tags |');
680
+ lines.push('|------|-------|------|');
681
+ for (const file of map.highValueFiles.slice(0, 20)) {
682
+ const tags = file.tags.join(', ') || '-';
683
+ lines.push(`| ${file.path} | ${file.score} | ${tags} |`);
684
+ }
685
+ lines.push('');
686
+ // Entry Points
687
+ if (map.entryPoints.length > 0) {
688
+ lines.push('## Entry Points');
689
+ lines.push('');
690
+ for (const file of map.entryPoints.slice(0, 10)) {
691
+ lines.push(`- ${file.path} (score: ${file.score})`);
692
+ }
693
+ lines.push('');
694
+ }
695
+ // Inferred Domains
696
+ const domains = Object.keys(map.clusters.byDomain);
697
+ if (domains.length > 0) {
698
+ lines.push('## Inferred Domains');
699
+ lines.push('');
700
+ lines.push('These domains may become separate spec files:');
701
+ lines.push('');
702
+ for (const domain of domains) {
703
+ const files = map.clusters.byDomain[domain];
704
+ lines.push(`- **${domain}** (${files.length} files)`);
705
+ }
706
+ lines.push('');
707
+ }
708
+ // Directory Structure
709
+ lines.push('## Directory Structure');
710
+ lines.push('');
711
+ lines.push('| Directory | Files | Purpose | Avg Score |');
712
+ lines.push('|-----------|-------|---------|-----------|');
713
+ for (const dir of map.summary.directories.slice(0, 15)) {
714
+ lines.push(`| ${dir.path} | ${dir.fileCount} | ${dir.purpose} | ${dir.avgScore} |`);
715
+ }
716
+ lines.push('');
717
+ return lines.join('\n');
718
+ }
719
+ }
720
+ /**
721
+ * Convenience function to map a repository
722
+ */
723
+ export async function mapRepository(rootPath, options) {
724
+ const mapper = new RepositoryMapper(rootPath, options);
725
+ const map = await mapper.map();
726
+ if (options?.outputDir !== undefined || options?.outputDir === undefined) {
727
+ await mapper.writeOutput(map);
728
+ }
729
+ return map;
730
+ }
731
+ //# sourceMappingURL=repository-mapper.js.map