@girardelli/architect-agents 8.1.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 (258) hide show
  1. package/dist/src/core/agent-generator/context-enricher.d.ts +17 -0
  2. package/dist/src/core/agent-generator/context-enricher.js +51 -0
  3. package/dist/src/core/agent-generator/context-enricher.js.map +1 -0
  4. package/dist/src/core/agent-generator/detectors/base-detector.d.ts +8 -0
  5. package/dist/src/core/agent-generator/detectors/base-detector.js +12 -0
  6. package/dist/src/core/agent-generator/detectors/base-detector.js.map +1 -0
  7. package/dist/src/core/agent-generator/detectors/dart-detector.d.ts +5 -0
  8. package/dist/src/core/agent-generator/detectors/dart-detector.js +16 -0
  9. package/dist/src/core/agent-generator/detectors/dart-detector.js.map +1 -0
  10. package/dist/src/core/agent-generator/detectors/framework-registry.d.ts +5 -0
  11. package/dist/src/core/agent-generator/detectors/framework-registry.js +81 -0
  12. package/dist/src/core/agent-generator/detectors/framework-registry.js.map +1 -0
  13. package/dist/src/core/agent-generator/detectors/go-detector.d.ts +5 -0
  14. package/dist/src/core/agent-generator/detectors/go-detector.js +25 -0
  15. package/dist/src/core/agent-generator/detectors/go-detector.js.map +1 -0
  16. package/dist/src/core/agent-generator/detectors/java-detector.d.ts +5 -0
  17. package/dist/src/core/agent-generator/detectors/java-detector.js +44 -0
  18. package/dist/src/core/agent-generator/detectors/java-detector.js.map +1 -0
  19. package/dist/src/core/agent-generator/detectors/node-detector.d.ts +5 -0
  20. package/dist/src/core/agent-generator/detectors/node-detector.js +28 -0
  21. package/dist/src/core/agent-generator/detectors/node-detector.js.map +1 -0
  22. package/dist/src/core/agent-generator/detectors/php-detector.d.ts +5 -0
  23. package/dist/src/core/agent-generator/detectors/php-detector.js +28 -0
  24. package/dist/src/core/agent-generator/detectors/php-detector.js.map +1 -0
  25. package/dist/src/core/agent-generator/detectors/python-detector.d.ts +7 -0
  26. package/dist/src/core/agent-generator/detectors/python-detector.js +116 -0
  27. package/dist/src/core/agent-generator/detectors/python-detector.js.map +1 -0
  28. package/dist/src/core/agent-generator/detectors/ruby-detector.d.ts +5 -0
  29. package/dist/src/core/agent-generator/detectors/ruby-detector.js +23 -0
  30. package/dist/src/core/agent-generator/detectors/ruby-detector.js.map +1 -0
  31. package/dist/src/core/agent-generator/detectors/rust-detector.d.ts +5 -0
  32. package/dist/src/core/agent-generator/detectors/rust-detector.js +18 -0
  33. package/dist/src/core/agent-generator/detectors/rust-detector.js.map +1 -0
  34. package/dist/src/core/agent-generator/detectors/structure-detector.d.ts +4 -0
  35. package/dist/src/core/agent-generator/detectors/structure-detector.js +35 -0
  36. package/dist/src/core/agent-generator/detectors/structure-detector.js.map +1 -0
  37. package/dist/src/core/agent-generator/detectors/toolchain-detector.d.ts +5 -0
  38. package/dist/src/core/agent-generator/detectors/toolchain-detector.js +164 -0
  39. package/dist/src/core/agent-generator/detectors/toolchain-detector.js.map +1 -0
  40. package/dist/src/core/agent-generator/domain-inferrer.d.ts +51 -0
  41. package/dist/src/core/agent-generator/domain-inferrer.js +585 -0
  42. package/dist/src/core/agent-generator/domain-inferrer.js.map +1 -0
  43. package/dist/src/core/agent-generator/engines/audit-engine.d.ts +8 -0
  44. package/dist/src/core/agent-generator/engines/audit-engine.js +84 -0
  45. package/dist/src/core/agent-generator/engines/audit-engine.js.map +1 -0
  46. package/dist/src/core/agent-generator/engines/context-builder.d.ts +12 -0
  47. package/dist/src/core/agent-generator/engines/context-builder.js +84 -0
  48. package/dist/src/core/agent-generator/engines/context-builder.js.map +1 -0
  49. package/dist/src/core/agent-generator/engines/generation-engine.d.ts +7 -0
  50. package/dist/src/core/agent-generator/engines/generation-engine.js +160 -0
  51. package/dist/src/core/agent-generator/engines/generation-engine.js.map +1 -0
  52. package/dist/src/core/agent-generator/engines/generation-engine_deps.d.ts +21 -0
  53. package/dist/src/core/agent-generator/engines/generation-engine_deps.js +17 -0
  54. package/dist/src/core/agent-generator/engines/generation-engine_deps.js.map +1 -0
  55. package/dist/src/core/agent-generator/engines/suggestion-engine.d.ts +13 -0
  56. package/dist/src/core/agent-generator/engines/suggestion-engine.js +171 -0
  57. package/dist/src/core/agent-generator/engines/suggestion-engine.js.map +1 -0
  58. package/dist/src/core/agent-generator/engines/suggestion-engine_deps.d.ts +8 -0
  59. package/dist/src/core/agent-generator/engines/suggestion-engine_deps.js +5 -0
  60. package/dist/src/core/agent-generator/engines/suggestion-engine_deps.js.map +1 -0
  61. package/dist/src/core/agent-generator/enrichers/analysis-helpers.d.ts +9 -0
  62. package/dist/src/core/agent-generator/enrichers/analysis-helpers.js +51 -0
  63. package/dist/src/core/agent-generator/enrichers/analysis-helpers.js.map +1 -0
  64. package/dist/src/core/agent-generator/enrichers/description-generator.d.ts +4 -0
  65. package/dist/src/core/agent-generator/enrichers/description-generator.js +82 -0
  66. package/dist/src/core/agent-generator/enrichers/description-generator.js.map +1 -0
  67. package/dist/src/core/agent-generator/enrichers/endpoint-extractor.d.ts +7 -0
  68. package/dist/src/core/agent-generator/enrichers/endpoint-extractor.js +90 -0
  69. package/dist/src/core/agent-generator/enrichers/endpoint-extractor.js.map +1 -0
  70. package/dist/src/core/agent-generator/enrichers/layer-classifier.d.ts +12 -0
  71. package/dist/src/core/agent-generator/enrichers/layer-classifier.js +152 -0
  72. package/dist/src/core/agent-generator/enrichers/layer-classifier.js.map +1 -0
  73. package/dist/src/core/agent-generator/enrichers/module-extractor.d.ts +10 -0
  74. package/dist/src/core/agent-generator/enrichers/module-extractor.js +173 -0
  75. package/dist/src/core/agent-generator/enrichers/module-extractor.js.map +1 -0
  76. package/dist/src/core/agent-generator/framework-detector.d.ts +17 -0
  77. package/dist/src/core/agent-generator/framework-detector.js +56 -0
  78. package/dist/src/core/agent-generator/framework-detector.js.map +1 -0
  79. package/dist/src/core/agent-generator/index.d.ts +25 -0
  80. package/dist/src/core/agent-generator/index.js +37 -0
  81. package/dist/src/core/agent-generator/index.js.map +1 -0
  82. package/dist/src/core/agent-generator/stack-detector.d.ts +13 -0
  83. package/dist/src/core/agent-generator/stack-detector.js +124 -0
  84. package/dist/src/core/agent-generator/stack-detector.js.map +1 -0
  85. package/dist/src/core/agent-generator/templates/core/agents.d.ts +9 -0
  86. package/dist/src/core/agent-generator/templates/core/agents.js +1127 -0
  87. package/dist/src/core/agent-generator/templates/core/agents.js.map +1 -0
  88. package/dist/src/core/agent-generator/templates/core/architecture-rules.d.ts +6 -0
  89. package/dist/src/core/agent-generator/templates/core/architecture-rules.js +275 -0
  90. package/dist/src/core/agent-generator/templates/core/architecture-rules.js.map +1 -0
  91. package/dist/src/core/agent-generator/templates/core/general-rules.d.ts +7 -0
  92. package/dist/src/core/agent-generator/templates/core/general-rules.js +301 -0
  93. package/dist/src/core/agent-generator/templates/core/general-rules.js.map +1 -0
  94. package/dist/src/core/agent-generator/templates/core/hooks-generator.d.ts +20 -0
  95. package/dist/src/core/agent-generator/templates/core/hooks-generator.js +235 -0
  96. package/dist/src/core/agent-generator/templates/core/hooks-generator.js.map +1 -0
  97. package/dist/src/core/agent-generator/templates/core/index-md.d.ts +6 -0
  98. package/dist/src/core/agent-generator/templates/core/index-md.js +247 -0
  99. package/dist/src/core/agent-generator/templates/core/index-md.js.map +1 -0
  100. package/dist/src/core/agent-generator/templates/core/orchestrator.d.ts +7 -0
  101. package/dist/src/core/agent-generator/templates/core/orchestrator.js +423 -0
  102. package/dist/src/core/agent-generator/templates/core/orchestrator.js.map +1 -0
  103. package/dist/src/core/agent-generator/templates/core/preflight.d.ts +7 -0
  104. package/dist/src/core/agent-generator/templates/core/preflight.js +213 -0
  105. package/dist/src/core/agent-generator/templates/core/preflight.js.map +1 -0
  106. package/dist/src/core/agent-generator/templates/core/quality-gates.d.ts +10 -0
  107. package/dist/src/core/agent-generator/templates/core/quality-gates.js +255 -0
  108. package/dist/src/core/agent-generator/templates/core/quality-gates.js.map +1 -0
  109. package/dist/src/core/agent-generator/templates/core/security-rules.d.ts +6 -0
  110. package/dist/src/core/agent-generator/templates/core/security-rules.js +529 -0
  111. package/dist/src/core/agent-generator/templates/core/security-rules.js.map +1 -0
  112. package/dist/src/core/agent-generator/templates/core/skills-generator.d.ts +18 -0
  113. package/dist/src/core/agent-generator/templates/core/skills-generator.js +547 -0
  114. package/dist/src/core/agent-generator/templates/core/skills-generator.js.map +1 -0
  115. package/dist/src/core/agent-generator/templates/core/workflow-fix-bug.d.ts +6 -0
  116. package/dist/src/core/agent-generator/templates/core/workflow-fix-bug.js +238 -0
  117. package/dist/src/core/agent-generator/templates/core/workflow-fix-bug.js.map +1 -0
  118. package/dist/src/core/agent-generator/templates/core/workflow-new-feature.d.ts +7 -0
  119. package/dist/src/core/agent-generator/templates/core/workflow-new-feature.js +321 -0
  120. package/dist/src/core/agent-generator/templates/core/workflow-new-feature.js.map +1 -0
  121. package/dist/src/core/agent-generator/templates/core/workflow-review.d.ts +6 -0
  122. package/dist/src/core/agent-generator/templates/core/workflow-review.js +105 -0
  123. package/dist/src/core/agent-generator/templates/core/workflow-review.js.map +1 -0
  124. package/dist/src/core/agent-generator/templates/domain/index.d.ts +21 -0
  125. package/dist/src/core/agent-generator/templates/domain/index.js +1179 -0
  126. package/dist/src/core/agent-generator/templates/domain/index.js.map +1 -0
  127. package/dist/src/core/agent-generator/templates/helpers/base-helpers.d.ts +10 -0
  128. package/dist/src/core/agent-generator/templates/helpers/base-helpers.js +20 -0
  129. package/dist/src/core/agent-generator/templates/helpers/base-helpers.js.map +1 -0
  130. package/dist/src/core/agent-generator/templates/helpers/cross-ref-helpers.d.ts +2 -0
  131. package/dist/src/core/agent-generator/templates/helpers/cross-ref-helpers.js +77 -0
  132. package/dist/src/core/agent-generator/templates/helpers/cross-ref-helpers.js.map +1 -0
  133. package/dist/src/core/agent-generator/templates/helpers/security-helpers.d.ts +2 -0
  134. package/dist/src/core/agent-generator/templates/helpers/security-helpers.js +182 -0
  135. package/dist/src/core/agent-generator/templates/helpers/security-helpers.js.map +1 -0
  136. package/dist/src/core/agent-generator/templates/helpers/stack-helpers.d.ts +4 -0
  137. package/dist/src/core/agent-generator/templates/helpers/stack-helpers.js +69 -0
  138. package/dist/src/core/agent-generator/templates/helpers/stack-helpers.js.map +1 -0
  139. package/dist/src/core/agent-generator/templates/helpers/structure-helpers.d.ts +2 -0
  140. package/dist/src/core/agent-generator/templates/helpers/structure-helpers.js +275 -0
  141. package/dist/src/core/agent-generator/templates/helpers/structure-helpers.js.map +1 -0
  142. package/dist/src/core/agent-generator/templates/helpers/summary-helpers.d.ts +6 -0
  143. package/dist/src/core/agent-generator/templates/helpers/summary-helpers.js +56 -0
  144. package/dist/src/core/agent-generator/templates/helpers/summary-helpers.js.map +1 -0
  145. package/dist/src/core/agent-generator/templates/stack/index.d.ts +7 -0
  146. package/dist/src/core/agent-generator/templates/stack/index.js +695 -0
  147. package/dist/src/core/agent-generator/templates/stack/index.js.map +1 -0
  148. package/dist/src/core/agent-generator/templates/template-helpers.d.ts +11 -0
  149. package/dist/src/core/agent-generator/templates/template-helpers.js +12 -0
  150. package/dist/src/core/agent-generator/templates/template-helpers.js.map +1 -0
  151. package/dist/src/core/agent-generator/types/agent.d.ts +39 -0
  152. package/dist/src/core/agent-generator/types/agent.js +27 -0
  153. package/dist/src/core/agent-generator/types/agent.js.map +1 -0
  154. package/dist/src/core/agent-generator/types/domain.d.ts +58 -0
  155. package/dist/src/core/agent-generator/types/domain.js +2 -0
  156. package/dist/src/core/agent-generator/types/domain.js.map +1 -0
  157. package/dist/src/core/agent-generator/types/stack.d.ts +36 -0
  158. package/dist/src/core/agent-generator/types/stack.js +2 -0
  159. package/dist/src/core/agent-generator/types/stack.js.map +1 -0
  160. package/dist/src/core/agent-generator/types/template.d.ts +29 -0
  161. package/dist/src/core/agent-generator/types/template.js +2 -0
  162. package/dist/src/core/agent-generator/types/template.js.map +1 -0
  163. package/dist/src/core/agent-runtime/ai-provider.d.ts +33 -0
  164. package/dist/src/core/agent-runtime/ai-provider.js +146 -0
  165. package/dist/src/core/agent-runtime/ai-provider.js.map +1 -0
  166. package/dist/src/core/agent-runtime/executor.d.ts +13 -0
  167. package/dist/src/core/agent-runtime/executor.js +138 -0
  168. package/dist/src/core/agent-runtime/executor.js.map +1 -0
  169. package/dist/src/core/agent-runtime/human-gate.d.ts +16 -0
  170. package/dist/src/core/agent-runtime/human-gate.js +70 -0
  171. package/dist/src/core/agent-runtime/human-gate.js.map +1 -0
  172. package/dist/tests/agent-generator.test.d.ts +1 -0
  173. package/dist/tests/agent-generator.test.js +349 -0
  174. package/dist/tests/agent-generator.test.js.map +1 -0
  175. package/dist/tests/agent-runtime.test.d.ts +1 -0
  176. package/dist/tests/agent-runtime.test.js +107 -0
  177. package/dist/tests/agent-runtime.test.js.map +1 -0
  178. package/dist/tests/context-enricher.test.d.ts +1 -0
  179. package/dist/tests/context-enricher.test.js +875 -0
  180. package/dist/tests/context-enricher.test.js.map +1 -0
  181. package/dist/tests/framework-detector.test.d.ts +1 -0
  182. package/dist/tests/framework-detector.test.js +882 -0
  183. package/dist/tests/framework-detector.test.js.map +1 -0
  184. package/dist/tests/stack-detector.test.d.ts +1 -0
  185. package/dist/tests/stack-detector.test.js +183 -0
  186. package/dist/tests/stack-detector.test.js.map +1 -0
  187. package/dist/tests/template-generation.test.d.ts +1 -0
  188. package/dist/tests/template-generation.test.js +571 -0
  189. package/dist/tests/template-generation.test.js.map +1 -0
  190. package/dist/tests/template-helpers.test.d.ts +1 -0
  191. package/dist/tests/template-helpers.test.js +967 -0
  192. package/dist/tests/template-helpers.test.js.map +1 -0
  193. package/package.json +24 -0
  194. package/src/core/agent-generator/context-enricher.ts +67 -0
  195. package/src/core/agent-generator/detectors/base-detector.ts +18 -0
  196. package/src/core/agent-generator/detectors/dart-detector.ts +17 -0
  197. package/src/core/agent-generator/detectors/framework-registry.ts +82 -0
  198. package/src/core/agent-generator/detectors/go-detector.ts +26 -0
  199. package/src/core/agent-generator/detectors/java-detector.ts +46 -0
  200. package/src/core/agent-generator/detectors/node-detector.ts +28 -0
  201. package/src/core/agent-generator/detectors/php-detector.ts +28 -0
  202. package/src/core/agent-generator/detectors/python-detector.ts +125 -0
  203. package/src/core/agent-generator/detectors/ruby-detector.ts +24 -0
  204. package/src/core/agent-generator/detectors/rust-detector.ts +19 -0
  205. package/src/core/agent-generator/detectors/structure-detector.ts +38 -0
  206. package/src/core/agent-generator/detectors/toolchain-detector.ts +181 -0
  207. package/src/core/agent-generator/domain-inferrer.ts +630 -0
  208. package/src/core/agent-generator/engines/audit-engine.ts +98 -0
  209. package/src/core/agent-generator/engines/context-builder.ts +96 -0
  210. package/src/core/agent-generator/engines/generation-engine.ts +184 -0
  211. package/src/core/agent-generator/engines/generation-engine_deps.ts +21 -0
  212. package/src/core/agent-generator/engines/suggestion-engine.ts +202 -0
  213. package/src/core/agent-generator/engines/suggestion-engine_deps.ts +8 -0
  214. package/src/core/agent-generator/enrichers/analysis-helpers.ts +58 -0
  215. package/src/core/agent-generator/enrichers/description-generator.ts +91 -0
  216. package/src/core/agent-generator/enrichers/endpoint-extractor.ts +114 -0
  217. package/src/core/agent-generator/enrichers/layer-classifier.ts +156 -0
  218. package/src/core/agent-generator/enrichers/module-extractor.ts +203 -0
  219. package/src/core/agent-generator/framework-detector.ts +66 -0
  220. package/src/core/agent-generator/index.ts +55 -0
  221. package/src/core/agent-generator/stack-detector.ts +115 -0
  222. package/src/core/agent-generator/templates/core/agents.ts +1168 -0
  223. package/src/core/agent-generator/templates/core/architecture-rules.ts +288 -0
  224. package/src/core/agent-generator/templates/core/general-rules.ts +306 -0
  225. package/src/core/agent-generator/templates/core/hooks-generator.ts +244 -0
  226. package/src/core/agent-generator/templates/core/index-md.ts +261 -0
  227. package/src/core/agent-generator/templates/core/orchestrator.ts +462 -0
  228. package/src/core/agent-generator/templates/core/preflight.ts +216 -0
  229. package/src/core/agent-generator/templates/core/quality-gates.ts +257 -0
  230. package/src/core/agent-generator/templates/core/security-rules.ts +544 -0
  231. package/src/core/agent-generator/templates/core/skills-generator.ts +586 -0
  232. package/src/core/agent-generator/templates/core/workflow-fix-bug.ts +240 -0
  233. package/src/core/agent-generator/templates/core/workflow-new-feature.ts +323 -0
  234. package/src/core/agent-generator/templates/core/workflow-review.ts +107 -0
  235. package/src/core/agent-generator/templates/domain/index.ts +1204 -0
  236. package/src/core/agent-generator/templates/helpers/base-helpers.ts +33 -0
  237. package/src/core/agent-generator/templates/helpers/cross-ref-helpers.ts +79 -0
  238. package/src/core/agent-generator/templates/helpers/security-helpers.ts +198 -0
  239. package/src/core/agent-generator/templates/helpers/stack-helpers.ts +80 -0
  240. package/src/core/agent-generator/templates/helpers/structure-helpers.ts +293 -0
  241. package/src/core/agent-generator/templates/helpers/summary-helpers.ts +67 -0
  242. package/src/core/agent-generator/templates/stack/index.ts +705 -0
  243. package/src/core/agent-generator/templates/template-helpers.ts +12 -0
  244. package/src/core/agent-generator/types/agent.ts +65 -0
  245. package/src/core/agent-generator/types/domain.ts +63 -0
  246. package/src/core/agent-generator/types/stack.ts +38 -0
  247. package/src/core/agent-generator/types/template.ts +31 -0
  248. package/src/core/agent-runtime/ai-provider.ts +178 -0
  249. package/src/core/agent-runtime/executor.ts +148 -0
  250. package/src/core/agent-runtime/human-gate.ts +69 -0
  251. package/tests/agent-generator.test.ts +428 -0
  252. package/tests/agent-runtime.test.ts +125 -0
  253. package/tests/context-enricher.test.ts +972 -0
  254. package/tests/framework-detector.test.ts +1172 -0
  255. package/tests/stack-detector.test.ts +241 -0
  256. package/tests/template-generation.test.ts +709 -0
  257. package/tests/template-helpers.test.ts +1130 -0
  258. package/tsconfig.json +14 -0
@@ -0,0 +1,972 @@
1
+ import { ContextEnricher } from '../src/core/agent-generator/context-enricher.js';
2
+ import { AnalysisReport } from '@girardelli/architect-core/src/core/types/core.js';
3
+ import { RefactoringPlan } from '@girardelli/architect-core/src/core/types/rules.js';
4
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'fs';
5
+ import { join } from 'path';
6
+
7
+ // ── Test Data Factories ──
8
+
9
+ function makeReport(overrides: Partial<AnalysisReport> = {}): AnalysisReport {
10
+ return {
11
+ timestamp: new Date().toISOString(),
12
+ projectInfo: {
13
+ path: '/test',
14
+ name: 'test-project',
15
+ frameworks: ['NestJS'],
16
+ totalFiles: 50,
17
+ totalLines: 5000,
18
+ primaryLanguages: ['TypeScript'],
19
+ },
20
+ score: {
21
+ overall: 72,
22
+ components: [],
23
+ breakdown: { modularity: 80, coupling: 65, cohesion: 70, layering: 75 },
24
+ },
25
+ antiPatterns: [
26
+ {
27
+ name: 'God Class',
28
+ severity: 'CRITICAL',
29
+ location: 'src/AppService.ts',
30
+ description: 'Class with 800 lines',
31
+ suggestion: 'Split into smaller services',
32
+ affectedFiles: ['src/AppService.ts'],
33
+ },
34
+ ],
35
+ layers: [
36
+ { name: 'API', files: ['src/controller.ts'], description: 'API layer' },
37
+ { name: 'Service', files: ['src/service.ts'], description: 'Service layer' },
38
+ ],
39
+ dependencyGraph: {
40
+ nodes: ['src/app.module.ts', 'src/app.controller.ts', 'src/app.service.ts', 'src/entity/user.entity.ts'],
41
+ edges: [
42
+ { from: 'src/app.controller.ts', to: 'src/app.service.ts', type: 'import', weight: 1 },
43
+ { from: 'src/app.service.ts', to: 'src/entity/user.entity.ts', type: 'import', weight: 1 },
44
+ ],
45
+ },
46
+ suggestions: [],
47
+ diagram: { mermaid: '', type: 'layer' },
48
+ ...overrides,
49
+ };
50
+ }
51
+
52
+ function makePlan(overrides: Partial<RefactoringPlan> = {}): RefactoringPlan {
53
+ return {
54
+ timestamp: new Date().toISOString(),
55
+ projectPath: '/test',
56
+ currentScore: {
57
+ overall: 72,
58
+ components: [],
59
+ breakdown: { modularity: 80, coupling: 65, cohesion: 70, layering: 75 },
60
+ },
61
+ estimatedScoreAfter: { overall: 82, breakdown: { modularity: 85, coupling: 75, cohesion: 80, layering: 80 } },
62
+ steps: [
63
+ {
64
+ id: 1,
65
+ tier: 1,
66
+ rule: 'hub-splitter',
67
+ priority: 'HIGH',
68
+ title: 'Split AppService',
69
+ description: 'Split monolith service',
70
+ rationale: 'Reduce coupling',
71
+ operations: [],
72
+ scoreImpact: [{ metric: 'modularity', before: 80, after: 85 }],
73
+ },
74
+ ],
75
+ totalOperations: 1,
76
+ tier1Steps: 1,
77
+ tier2Steps: 0,
78
+ ...overrides,
79
+ };
80
+ }
81
+
82
+ // ── Test Suite ──
83
+
84
+ describe('ContextEnricher', () => {
85
+ const enricher = new ContextEnricher();
86
+ let tempDir: string;
87
+
88
+ beforeEach(() => {
89
+ tempDir = mkdtempSync(join(process.cwd(), '__test_context_'));
90
+ });
91
+
92
+ afterEach(() => {
93
+ if (tempDir) {
94
+ rmSync(tempDir, { recursive: true, force: true });
95
+ }
96
+ });
97
+
98
+ describe('enrich()', () => {
99
+ it('should return a valid EnrichedTemplateContext', () => {
100
+ const report = makeReport();
101
+ const plan = makePlan();
102
+
103
+ const result = enricher.enrich(report, plan, {
104
+ primary: 'TypeScript',
105
+ languages: ['TypeScript'],
106
+ frameworks: ['NestJS'],
107
+ hasBackend: true,
108
+ hasFrontend: false,
109
+ hasMobile: false,
110
+ hasDatabase: true,
111
+ testFramework: 'Jest',
112
+ packageManager: 'npm',
113
+ }, tempDir);
114
+
115
+ expect(result).toBeDefined();
116
+ expect(result.report).toBe(report);
117
+ expect(result.plan).toBe(plan);
118
+ expect(result.projectName).toBe('test-project');
119
+ expect(result.modules).toBeDefined();
120
+ expect(result.endpoints).toBeDefined();
121
+ expect(result.untestedModules).toBeDefined();
122
+ expect(result.criticalPaths).toBeDefined();
123
+ expect(result.projectDepth).toBeDefined();
124
+ });
125
+
126
+ it('should detect modules from dependency graph nodes', () => {
127
+ const report = makeReport({
128
+ dependencyGraph: {
129
+ nodes: [
130
+ 'src/modules/users/users.controller.ts',
131
+ 'src/modules/users/users.service.ts',
132
+ 'src/modules/users/user.entity.ts',
133
+ 'src/modules/auth/auth.controller.ts',
134
+ 'src/modules/auth/auth.service.ts',
135
+ ],
136
+ edges: [],
137
+ },
138
+ });
139
+ const plan = makePlan();
140
+
141
+ const result = enricher.enrich(report, plan, {
142
+ primary: 'TypeScript',
143
+ languages: ['TypeScript'],
144
+ frameworks: ['NestJS'],
145
+ hasBackend: true,
146
+ hasFrontend: false,
147
+ hasMobile: false,
148
+ hasDatabase: true,
149
+ testFramework: 'Jest',
150
+ packageManager: 'npm',
151
+ }, tempDir);
152
+
153
+ expect(result.modules.length).toBeGreaterThan(0);
154
+ const moduleNames = result.modules.map(m => m.name);
155
+ expect(moduleNames).toContain('users');
156
+ expect(moduleNames).toContain('auth');
157
+ });
158
+
159
+ it('should extract modules sorted by file count descending', () => {
160
+ const report = makeReport({
161
+ dependencyGraph: {
162
+ nodes: [
163
+ 'src/modules/users/users.controller.ts',
164
+ 'src/modules/users/users.service.ts',
165
+ 'src/modules/users/user.entity.ts',
166
+ 'src/modules/auth/auth.controller.ts',
167
+ ],
168
+ edges: [],
169
+ },
170
+ });
171
+ const plan = makePlan();
172
+
173
+ const result = enricher.enrich(report, plan, {
174
+ primary: 'TypeScript',
175
+ languages: ['TypeScript'],
176
+ frameworks: ['NestJS'],
177
+ hasBackend: true,
178
+ hasFrontend: false,
179
+ hasMobile: false,
180
+ hasDatabase: true,
181
+ testFramework: 'Jest',
182
+ packageManager: 'npm',
183
+ }, tempDir);
184
+
185
+ // Users has 3 files, auth has 1 file → users should come first
186
+ expect(result.modules[0].name).toBe('users');
187
+ expect(result.modules[0].fileCount).toBe(3);
188
+ });
189
+
190
+ it('should generate smart descriptions for known patterns', () => {
191
+ const report = makeReport({
192
+ dependencyGraph: {
193
+ nodes: [
194
+ 'src/modules/extractors/pdf.extractor.ts',
195
+ 'src/modules/extractors/image.extractor.ts',
196
+ 'src/modules/ocr/ocr.service.ts',
197
+ 'src/modules/guards/auth.guard.ts',
198
+ ],
199
+ edges: [],
200
+ },
201
+ });
202
+ const plan = makePlan();
203
+
204
+ const result = enricher.enrich(report, plan, {
205
+ primary: 'TypeScript',
206
+ languages: ['TypeScript'],
207
+ frameworks: ['NestJS'],
208
+ hasBackend: true,
209
+ hasFrontend: false,
210
+ hasMobile: false,
211
+ hasDatabase: true,
212
+ testFramework: 'Jest',
213
+ packageManager: 'npm',
214
+ }, tempDir);
215
+
216
+ const extractorsModule = result.modules.find(m => m.name === 'extractors');
217
+ expect(extractorsModule).toBeDefined();
218
+ expect(extractorsModule!.description).toContain('Extração');
219
+
220
+ const ocrModule = result.modules.find(m => m.name === 'ocr');
221
+ expect(ocrModule).toBeDefined();
222
+ expect(ocrModule!.description).toContain('OCR');
223
+
224
+ const guardsModule = result.modules.find(m => m.name === 'guards');
225
+ expect(guardsModule).toBeDefined();
226
+ expect(guardsModule!.description).toContain('Validação');
227
+ });
228
+
229
+ it('should count lines for real files', () => {
230
+ // Create a temp file with 10 lines
231
+ const subdir = join(tempDir, 'src', 'modules', 'test');
232
+ mkdirSync(subdir, { recursive: true });
233
+ const filePath = join(subdir, 'test.ts');
234
+ const content = Array(10).fill('console.log("test");').join('\n');
235
+ writeFileSync(filePath, content);
236
+
237
+ const report = makeReport({
238
+ dependencyGraph: {
239
+ nodes: ['src/modules/test/test.ts'],
240
+ edges: [],
241
+ },
242
+ });
243
+ const plan = makePlan();
244
+
245
+ const result = enricher.enrich(report, plan, {
246
+ primary: 'TypeScript',
247
+ languages: ['TypeScript'],
248
+ frameworks: ['NestJS'],
249
+ hasBackend: true,
250
+ hasFrontend: false,
251
+ hasMobile: false,
252
+ hasDatabase: true,
253
+ testFramework: 'Jest',
254
+ packageManager: 'npm',
255
+ }, tempDir);
256
+
257
+ const testModule = result.modules.find(m => m.name === 'test');
258
+ expect(testModule).toBeDefined();
259
+ expect(testModule!.lineCount).toBeGreaterThan(0);
260
+ });
261
+
262
+ it('should detect test files in modules', () => {
263
+ const report = makeReport({
264
+ dependencyGraph: {
265
+ nodes: [
266
+ 'src/modules/users/users.service.ts',
267
+ 'src/modules/users/users.service.test.ts',
268
+ 'src/modules/users/__tests__/users.spec.ts',
269
+ ],
270
+ edges: [],
271
+ },
272
+ });
273
+ const plan = makePlan();
274
+
275
+ const result = enricher.enrich(report, plan, {
276
+ primary: 'TypeScript',
277
+ languages: ['TypeScript'],
278
+ frameworks: ['NestJS'],
279
+ hasBackend: true,
280
+ hasFrontend: false,
281
+ hasMobile: false,
282
+ hasDatabase: true,
283
+ testFramework: 'Jest',
284
+ packageManager: 'npm',
285
+ }, tempDir);
286
+
287
+ const usersModule = result.modules.find(m => m.name === 'users');
288
+ expect(usersModule).toBeDefined();
289
+ expect(usersModule!.hasTests).toBe(true);
290
+ expect(usersModule!.testFiles.length).toBe(2);
291
+ });
292
+
293
+ it('should extract endpoints from route/controller files', () => {
294
+ const report = makeReport({
295
+ dependencyGraph: {
296
+ nodes: [
297
+ 'src/modules/users/users.controller.ts',
298
+ 'src/modules/users/users.service.ts',
299
+ 'src/auth/auth.controller.ts',
300
+ 'src/health/health.controller.ts',
301
+ ],
302
+ edges: [
303
+ { from: 'src/modules/users/users.controller.ts', to: 'src/modules/users/users.service.ts', type: 'import', weight: 1 },
304
+ { from: 'src/auth/auth.controller.ts', to: 'src/dependencies/auth.guard.ts', type: 'import', weight: 1 },
305
+ ],
306
+ },
307
+ });
308
+ const plan = makePlan();
309
+
310
+ const result = enricher.enrich(report, plan, {
311
+ primary: 'TypeScript',
312
+ languages: ['TypeScript'],
313
+ frameworks: ['NestJS'],
314
+ hasBackend: true,
315
+ hasFrontend: false,
316
+ hasMobile: false,
317
+ hasDatabase: true,
318
+ testFramework: 'Jest',
319
+ packageManager: 'npm',
320
+ }, tempDir);
321
+
322
+ expect(result.endpoints.length).toBeGreaterThan(0);
323
+ // Should detect users endpoints
324
+ const userEndpoints = result.endpoints.filter(e => e.path.includes('users'));
325
+ expect(userEndpoints.length).toBeGreaterThan(0);
326
+ });
327
+
328
+ it('should detect endpoints with authentication', () => {
329
+ const report = makeReport({
330
+ dependencyGraph: {
331
+ nodes: [
332
+ 'src/auth/auth.controller.ts',
333
+ 'src/dependencies/auth.guard.ts',
334
+ ],
335
+ edges: [
336
+ { from: 'src/auth/auth.controller.ts', to: 'src/dependencies/auth.guard.ts', type: 'import', weight: 1 },
337
+ ],
338
+ },
339
+ });
340
+ const plan = makePlan();
341
+
342
+ const result = enricher.enrich(report, plan, {
343
+ primary: 'TypeScript',
344
+ languages: ['TypeScript'],
345
+ frameworks: ['NestJS'],
346
+ hasBackend: true,
347
+ hasFrontend: false,
348
+ hasMobile: false,
349
+ hasDatabase: true,
350
+ testFramework: 'Jest',
351
+ packageManager: 'npm',
352
+ }, tempDir);
353
+
354
+ const authEndpoints = result.endpoints.filter(e => e.path.includes('auth'));
355
+ expect(authEndpoints.length).toBeGreaterThan(0);
356
+ // Auth endpoints should be marked as no auth (login/register are public)
357
+ const loginEndpoint = authEndpoints.find(e => e.path === '/auth/login');
358
+ expect(loginEndpoint).toBeDefined();
359
+ expect(loginEndpoint!.hasAuth).toBe(false);
360
+ });
361
+
362
+ it('should detect untested modules', () => {
363
+ const report = makeReport({
364
+ dependencyGraph: {
365
+ nodes: [
366
+ 'src/modules/users/users.service.ts',
367
+ 'src/modules/users/users.controller.ts',
368
+ 'src/modules/notested/service.ts',
369
+ 'src/modules/notested/handler.ts',
370
+ ],
371
+ edges: [],
372
+ },
373
+ });
374
+ const plan = makePlan();
375
+
376
+ const result = enricher.enrich(report, plan, {
377
+ primary: 'TypeScript',
378
+ languages: ['TypeScript'],
379
+ frameworks: ['NestJS'],
380
+ hasBackend: true,
381
+ hasFrontend: false,
382
+ hasMobile: false,
383
+ hasDatabase: true,
384
+ testFramework: 'Jest',
385
+ packageManager: 'npm',
386
+ }, tempDir);
387
+
388
+ expect(result.untestedModules).toContain('notested');
389
+ });
390
+
391
+ it('should identify critical paths (files with high coupling)', () => {
392
+ const report = makeReport({
393
+ dependencyGraph: {
394
+ nodes: [
395
+ 'src/app.module.ts',
396
+ 'src/app.controller.ts',
397
+ 'src/app.service.ts',
398
+ 'src/users/user.service.ts',
399
+ 'src/auth/auth.service.ts',
400
+ ],
401
+ edges: [
402
+ { from: 'src/app.module.ts', to: 'src/app.controller.ts', type: 'import', weight: 1 },
403
+ { from: 'src/app.module.ts', to: 'src/app.service.ts', type: 'import', weight: 1 },
404
+ { from: 'src/app.module.ts', to: 'src/users/user.service.ts', type: 'import', weight: 1 },
405
+ { from: 'src/app.module.ts', to: 'src/auth/auth.service.ts', type: 'import', weight: 1 },
406
+ { from: 'src/app.controller.ts', to: 'src/app.service.ts', type: 'import', weight: 1 },
407
+ ],
408
+ },
409
+ });
410
+ const plan = makePlan();
411
+
412
+ const result = enricher.enrich(report, plan, {
413
+ primary: 'TypeScript',
414
+ languages: ['TypeScript'],
415
+ frameworks: ['NestJS'],
416
+ hasBackend: true,
417
+ hasFrontend: false,
418
+ hasMobile: false,
419
+ hasDatabase: true,
420
+ testFramework: 'Jest',
421
+ packageManager: 'npm',
422
+ }, tempDir);
423
+
424
+ expect(result.criticalPaths.length).toBeGreaterThan(0);
425
+ // app.module.ts should be in critical paths (4 edges)
426
+ expect(result.criticalPaths).toContain('src/app.module.ts');
427
+ });
428
+
429
+ it('should classify project depth as small', () => {
430
+ const report = makeReport({
431
+ projectInfo: {
432
+ path: '/test',
433
+ name: 'small-project',
434
+ frameworks: ['NestJS'],
435
+ totalFiles: 10,
436
+ totalLines: 1000,
437
+ primaryLanguages: ['TypeScript'],
438
+ },
439
+ dependencyGraph: {
440
+ nodes: [],
441
+ edges: [],
442
+ },
443
+ });
444
+ const plan = makePlan();
445
+
446
+ const result = enricher.enrich(report, plan, {
447
+ primary: 'TypeScript',
448
+ languages: ['TypeScript'],
449
+ frameworks: ['NestJS'],
450
+ hasBackend: true,
451
+ hasFrontend: false,
452
+ hasMobile: false,
453
+ hasDatabase: true,
454
+ testFramework: 'Jest',
455
+ packageManager: 'npm',
456
+ }, tempDir);
457
+
458
+ expect(result.projectDepth).toBe('small');
459
+ });
460
+
461
+ it('should classify project depth as medium', () => {
462
+ const report = makeReport({
463
+ projectInfo: {
464
+ path: '/test',
465
+ name: 'medium-project',
466
+ frameworks: ['NestJS'],
467
+ totalFiles: 150,
468
+ totalLines: 30000,
469
+ primaryLanguages: ['TypeScript'],
470
+ },
471
+ dependencyGraph: {
472
+ nodes: [],
473
+ edges: [],
474
+ },
475
+ });
476
+ const plan = makePlan();
477
+
478
+ const result = enricher.enrich(report, plan, {
479
+ primary: 'TypeScript',
480
+ languages: ['TypeScript'],
481
+ frameworks: ['NestJS'],
482
+ hasBackend: true,
483
+ hasFrontend: false,
484
+ hasMobile: false,
485
+ hasDatabase: true,
486
+ testFramework: 'Jest',
487
+ packageManager: 'npm',
488
+ }, tempDir);
489
+
490
+ expect(result.projectDepth).toBe('medium');
491
+ });
492
+
493
+ it('should classify project depth as large', () => {
494
+ const report = makeReport({
495
+ projectInfo: {
496
+ path: '/test',
497
+ name: 'large-project',
498
+ frameworks: ['NestJS'],
499
+ totalFiles: 300,
500
+ totalLines: 70000,
501
+ primaryLanguages: ['TypeScript'],
502
+ },
503
+ dependencyGraph: {
504
+ nodes: [],
505
+ edges: [],
506
+ },
507
+ });
508
+ const plan = makePlan();
509
+
510
+ const result = enricher.enrich(report, plan, {
511
+ primary: 'TypeScript',
512
+ languages: ['TypeScript'],
513
+ frameworks: ['NestJS'],
514
+ hasBackend: true,
515
+ hasFrontend: false,
516
+ hasMobile: false,
517
+ hasDatabase: true,
518
+ testFramework: 'Jest',
519
+ packageManager: 'npm',
520
+ }, tempDir);
521
+
522
+ expect(result.projectDepth).toBe('large');
523
+ });
524
+
525
+ it('should classify project depth as enterprise', () => {
526
+ const report = makeReport({
527
+ projectInfo: {
528
+ path: '/test',
529
+ name: 'enterprise-project',
530
+ frameworks: ['NestJS'],
531
+ totalFiles: 1000,
532
+ totalLines: 150000,
533
+ primaryLanguages: ['TypeScript'],
534
+ },
535
+ dependencyGraph: {
536
+ nodes: [],
537
+ edges: [],
538
+ },
539
+ });
540
+ const plan = makePlan();
541
+
542
+ const result = enricher.enrich(report, plan, {
543
+ primary: 'TypeScript',
544
+ languages: ['TypeScript'],
545
+ frameworks: ['NestJS'],
546
+ hasBackend: true,
547
+ hasFrontend: false,
548
+ hasMobile: false,
549
+ hasDatabase: true,
550
+ testFramework: 'Jest',
551
+ packageManager: 'npm',
552
+ }, tempDir);
553
+
554
+ expect(result.projectDepth).toBe('enterprise');
555
+ });
556
+ });
557
+
558
+ describe('Module inference strategies', () => {
559
+ it('should infer module name from explicit module markers', () => {
560
+ const report = makeReport({
561
+ dependencyGraph: {
562
+ nodes: [
563
+ 'src/modules/users/users.service.ts',
564
+ 'src/modules/auth/auth.service.ts',
565
+ 'src/features/notifications/notifier.ts',
566
+ ],
567
+ edges: [],
568
+ },
569
+ });
570
+ const plan = makePlan();
571
+
572
+ const result = enricher.enrich(report, plan, {
573
+ primary: 'TypeScript',
574
+ languages: ['TypeScript'],
575
+ frameworks: ['NestJS'],
576
+ hasBackend: true,
577
+ hasFrontend: false,
578
+ hasMobile: false,
579
+ hasDatabase: true,
580
+ testFramework: 'Jest',
581
+ packageManager: 'npm',
582
+ }, tempDir);
583
+
584
+ const moduleNames = result.modules.map(m => m.name);
585
+ expect(moduleNames).toContain('users');
586
+ expect(moduleNames).toContain('auth');
587
+ expect(moduleNames).toContain('notifications');
588
+ });
589
+
590
+ it('should infer module name from Django app pattern', () => {
591
+ const report = makeReport({
592
+ dependencyGraph: {
593
+ nodes: [
594
+ 'apps/users/views.py',
595
+ 'apps/users/models.py',
596
+ 'apps/posts/views.py',
597
+ ],
598
+ edges: [],
599
+ },
600
+ });
601
+ const plan = makePlan();
602
+
603
+ const result = enricher.enrich(report, plan, {
604
+ primary: 'Python',
605
+ languages: ['Python'],
606
+ frameworks: ['Django'],
607
+ hasBackend: true,
608
+ hasFrontend: false,
609
+ hasMobile: false,
610
+ hasDatabase: true,
611
+ testFramework: 'pytest',
612
+ packageManager: 'pip',
613
+ }, tempDir);
614
+
615
+ const moduleNames = result.modules.map(m => m.name);
616
+ expect(moduleNames).toContain('users');
617
+ expect(moduleNames).toContain('posts');
618
+ });
619
+
620
+ it('should infer module name from clean architecture layers', () => {
621
+ const report = makeReport({
622
+ dependencyGraph: {
623
+ nodes: [
624
+ 'src/domain/entities/user.entity.ts',
625
+ 'src/application/services/user.service.ts',
626
+ 'src/infrastructure/persistence/user.repository.ts',
627
+ ],
628
+ edges: [],
629
+ },
630
+ });
631
+ const plan = makePlan();
632
+
633
+ const result = enricher.enrich(report, plan, {
634
+ primary: 'TypeScript',
635
+ languages: ['TypeScript'],
636
+ frameworks: ['NestJS'],
637
+ hasBackend: true,
638
+ hasFrontend: false,
639
+ hasMobile: false,
640
+ hasDatabase: true,
641
+ testFramework: 'Jest',
642
+ packageManager: 'npm',
643
+ }, tempDir);
644
+
645
+ // Should infer modules related to user entity
646
+ expect(result.modules.length).toBeGreaterThan(0);
647
+ });
648
+
649
+ it('should handle Java package structure', () => {
650
+ const report = makeReport({
651
+ dependencyGraph: {
652
+ nodes: [
653
+ 'src/main/java/com/example/users/User.java',
654
+ 'src/main/java/com/example/users/UserService.java',
655
+ 'src/main/java/com/example/auth/AuthService.java',
656
+ ],
657
+ edges: [],
658
+ },
659
+ });
660
+ const plan = makePlan();
661
+
662
+ const result = enricher.enrich(report, plan, {
663
+ primary: 'Java',
664
+ languages: ['Java'],
665
+ frameworks: ['Spring Boot'],
666
+ hasBackend: true,
667
+ hasFrontend: false,
668
+ hasMobile: false,
669
+ hasDatabase: true,
670
+ testFramework: 'JUnit',
671
+ packageManager: 'maven',
672
+ }, tempDir);
673
+
674
+ const moduleNames = result.modules.map(m => m.name);
675
+ expect(moduleNames.length).toBeGreaterThan(0);
676
+ });
677
+ });
678
+
679
+ describe('Entity and controller detection', () => {
680
+ it('should detect entity files', () => {
681
+ const report = makeReport({
682
+ dependencyGraph: {
683
+ nodes: [
684
+ 'src/modules/users/entities/user.entity.ts',
685
+ 'src/modules/users/models/user.model.ts',
686
+ 'src/modules/users/user.service.ts',
687
+ ],
688
+ edges: [],
689
+ },
690
+ });
691
+ const plan = makePlan();
692
+
693
+ const result = enricher.enrich(report, plan, {
694
+ primary: 'TypeScript',
695
+ languages: ['TypeScript'],
696
+ frameworks: ['NestJS'],
697
+ hasBackend: true,
698
+ hasFrontend: false,
699
+ hasMobile: false,
700
+ hasDatabase: true,
701
+ testFramework: 'Jest',
702
+ packageManager: 'npm',
703
+ }, tempDir);
704
+
705
+ const usersModule = result.modules.find(m => m.name === 'users');
706
+ expect(usersModule).toBeDefined();
707
+ expect(usersModule!.entities.length).toBeGreaterThan(0);
708
+ expect(usersModule!.entities.some(e => e.includes('User'))).toBe(true);
709
+ });
710
+
711
+ it('should detect controller files', () => {
712
+ const report = makeReport({
713
+ dependencyGraph: {
714
+ nodes: [
715
+ 'src/modules/users/users.controller.ts',
716
+ 'src/modules/auth/auth.controller.ts',
717
+ 'src/modules/users/users.service.ts',
718
+ ],
719
+ edges: [],
720
+ },
721
+ });
722
+ const plan = makePlan();
723
+
724
+ const result = enricher.enrich(report, plan, {
725
+ primary: 'TypeScript',
726
+ languages: ['TypeScript'],
727
+ frameworks: ['NestJS'],
728
+ hasBackend: true,
729
+ hasFrontend: false,
730
+ hasMobile: false,
731
+ hasDatabase: true,
732
+ testFramework: 'Jest',
733
+ packageManager: 'npm',
734
+ }, tempDir);
735
+
736
+ const usersModule = result.modules.find(m => m.name === 'users');
737
+ expect(usersModule).toBeDefined();
738
+ expect(usersModule!.controllers.length).toBeGreaterThan(0);
739
+ });
740
+
741
+ it('should detect service files', () => {
742
+ const report = makeReport({
743
+ dependencyGraph: {
744
+ nodes: [
745
+ 'src/modules/users/users.service.ts',
746
+ 'src/modules/auth/auth.service.ts',
747
+ 'src/modules/users/users.controller.ts',
748
+ ],
749
+ edges: [],
750
+ },
751
+ });
752
+ const plan = makePlan();
753
+
754
+ const result = enricher.enrich(report, plan, {
755
+ primary: 'TypeScript',
756
+ languages: ['TypeScript'],
757
+ frameworks: ['NestJS'],
758
+ hasBackend: true,
759
+ hasFrontend: false,
760
+ hasMobile: false,
761
+ hasDatabase: true,
762
+ testFramework: 'Jest',
763
+ packageManager: 'npm',
764
+ }, tempDir);
765
+
766
+ const usersModule = result.modules.find(m => m.name === 'users');
767
+ expect(usersModule).toBeDefined();
768
+ expect(usersModule!.services.length).toBeGreaterThan(0);
769
+ });
770
+ });
771
+
772
+ describe('Smart descriptions for patterns', () => {
773
+ it('should generate description for routes/controllers', () => {
774
+ const report = makeReport({
775
+ dependencyGraph: {
776
+ nodes: ['src/modules/routes/app.routes.ts'],
777
+ edges: [],
778
+ },
779
+ });
780
+ const plan = makePlan();
781
+
782
+ const result = enricher.enrich(report, plan, {
783
+ primary: 'TypeScript',
784
+ languages: ['TypeScript'],
785
+ frameworks: ['NestJS'],
786
+ hasBackend: true,
787
+ hasFrontend: false,
788
+ hasMobile: false,
789
+ hasDatabase: true,
790
+ testFramework: 'Jest',
791
+ packageManager: 'npm',
792
+ }, tempDir);
793
+
794
+ const routesModule = result.modules.find(m => m.name === 'routes');
795
+ expect(routesModule).toBeDefined();
796
+ expect(routesModule!.description).toContain('rotas');
797
+ });
798
+
799
+ it('should generate description for services', () => {
800
+ const report = makeReport({
801
+ dependencyGraph: {
802
+ nodes: ['src/modules/services/payment.service.ts'],
803
+ edges: [],
804
+ },
805
+ });
806
+ const plan = makePlan();
807
+
808
+ const result = enricher.enrich(report, plan, {
809
+ primary: 'TypeScript',
810
+ languages: ['TypeScript'],
811
+ frameworks: ['NestJS'],
812
+ hasBackend: true,
813
+ hasFrontend: false,
814
+ hasMobile: false,
815
+ hasDatabase: true,
816
+ testFramework: 'Jest',
817
+ packageManager: 'npm',
818
+ }, tempDir);
819
+
820
+ const servicesModule = result.modules.find(m => m.name === 'services');
821
+ expect(servicesModule).toBeDefined();
822
+ expect(servicesModule!.description).toContain('Serviços');
823
+ });
824
+
825
+ it('should generate description for auth modules', () => {
826
+ const report = makeReport({
827
+ dependencyGraph: {
828
+ nodes: ['src/modules/auth/auth.service.ts'],
829
+ edges: [],
830
+ },
831
+ });
832
+ const plan = makePlan();
833
+
834
+ const result = enricher.enrich(report, plan, {
835
+ primary: 'TypeScript',
836
+ languages: ['TypeScript'],
837
+ frameworks: ['NestJS'],
838
+ hasBackend: true,
839
+ hasFrontend: false,
840
+ hasMobile: false,
841
+ hasDatabase: true,
842
+ testFramework: 'Jest',
843
+ packageManager: 'npm',
844
+ }, tempDir);
845
+
846
+ const authModule = result.modules.find(m => m.name === 'auth');
847
+ expect(authModule).toBeDefined();
848
+ expect(authModule!.description.toLowerCase()).toContain('autenticação');
849
+ });
850
+
851
+ it('should include composition info in descriptions', () => {
852
+ const report = makeReport({
853
+ dependencyGraph: {
854
+ nodes: [
855
+ 'src/modules/users/users.controller.ts',
856
+ 'src/modules/users/users.service.ts',
857
+ 'src/modules/users/entities/user.entity.ts',
858
+ ],
859
+ edges: [],
860
+ },
861
+ });
862
+ const plan = makePlan();
863
+
864
+ const result = enricher.enrich(report, plan, {
865
+ primary: 'TypeScript',
866
+ languages: ['TypeScript'],
867
+ frameworks: ['NestJS'],
868
+ hasBackend: true,
869
+ hasFrontend: false,
870
+ hasMobile: false,
871
+ hasDatabase: true,
872
+ testFramework: 'Jest',
873
+ packageManager: 'npm',
874
+ }, tempDir);
875
+
876
+ const usersModule = result.modules.find(m => m.name === 'users');
877
+ expect(usersModule).toBeDefined();
878
+ // Should include composition info (endpoints, services, entities)
879
+ expect(usersModule!.description).toMatch(/endpoint|service|entit/i);
880
+ });
881
+ });
882
+
883
+ describe('Line counting edge cases', () => {
884
+ it('should handle missing files gracefully', () => {
885
+ const report = makeReport({
886
+ dependencyGraph: {
887
+ nodes: ['src/nonexistent/file.ts'],
888
+ edges: [],
889
+ },
890
+ });
891
+ const plan = makePlan();
892
+
893
+ const result = enricher.enrich(report, plan, {
894
+ primary: 'TypeScript',
895
+ languages: ['TypeScript'],
896
+ frameworks: ['NestJS'],
897
+ hasBackend: true,
898
+ hasFrontend: false,
899
+ hasMobile: false,
900
+ hasDatabase: true,
901
+ testFramework: 'Jest',
902
+ packageManager: 'npm',
903
+ }, tempDir);
904
+
905
+ // Should not crash, modules should exist
906
+ expect(result.modules).toBeDefined();
907
+ });
908
+
909
+ it('should handle empty files', () => {
910
+ const subdir = join(tempDir, 'src', 'modules', 'empty');
911
+ mkdirSync(subdir, { recursive: true });
912
+ const filePath = join(subdir, 'empty.ts');
913
+ writeFileSync(filePath, '');
914
+
915
+ const report = makeReport({
916
+ dependencyGraph: {
917
+ nodes: ['src/modules/empty/empty.ts'],
918
+ edges: [],
919
+ },
920
+ });
921
+ const plan = makePlan();
922
+
923
+ const result = enricher.enrich(report, plan, {
924
+ primary: 'TypeScript',
925
+ languages: ['TypeScript'],
926
+ frameworks: ['NestJS'],
927
+ hasBackend: true,
928
+ hasFrontend: false,
929
+ hasMobile: false,
930
+ hasDatabase: true,
931
+ testFramework: 'Jest',
932
+ packageManager: 'npm',
933
+ }, tempDir);
934
+
935
+ const emptyModule = result.modules.find(m => m.name === 'empty');
936
+ expect(emptyModule).toBeDefined();
937
+ expect(emptyModule!.lineCount).toBe(0);
938
+ });
939
+
940
+ it('should count lines in files with various line endings', () => {
941
+ const subdir = join(tempDir, 'src', 'modules', 'mixed');
942
+ mkdirSync(subdir, { recursive: true });
943
+ const filePath = join(subdir, 'mixed.ts');
944
+ // 5 lines
945
+ writeFileSync(filePath, 'line1\nline2\nline3\nline4\nline5');
946
+
947
+ const report = makeReport({
948
+ dependencyGraph: {
949
+ nodes: ['src/modules/mixed/mixed.ts'],
950
+ edges: [],
951
+ },
952
+ });
953
+ const plan = makePlan();
954
+
955
+ const result = enricher.enrich(report, plan, {
956
+ primary: 'TypeScript',
957
+ languages: ['TypeScript'],
958
+ frameworks: ['NestJS'],
959
+ hasBackend: true,
960
+ hasFrontend: false,
961
+ hasMobile: false,
962
+ hasDatabase: true,
963
+ testFramework: 'Jest',
964
+ packageManager: 'npm',
965
+ }, tempDir);
966
+
967
+ const mixedModule = result.modules.find(m => m.name === 'mixed');
968
+ expect(mixedModule).toBeDefined();
969
+ expect(mixedModule!.lineCount).toBeGreaterThan(0);
970
+ });
971
+ });
972
+ });