@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,1130 @@
1
+ import { getEnriched, isEnriched, depthScale, depthAtLeast, crossRef, domainBadge, complianceBadges, depthIndicator, modulesSummaryTable, integrationsSummary, frameworkBadge, projectStructureBadge, toolchainCommands, frameworkModuleStructure, frameworkSecurityChecklist } from '../src/core/agent-generator/templates/template-helpers.js';
2
+ import { TemplateContext, EnrichedTemplateContext } from '../src/core/agent-generator/types/template.js';
3
+ import { StackInfo, FrameworkInfo, DetectedToolchain } from '../src/core/agent-generator/types/stack.js';
4
+ import { DomainInsights, ModuleDetail, DetectedEndpoint } from '../src/core/agent-generator/types/domain.js';
5
+ import { AnalysisReport } from '@girardelli/architect-core/src/core/types/core.js';
6
+ import { RefactoringPlan } from '@girardelli/architect-core/src/core/types/rules.js';
7
+
8
+ // ───────────────────────────────────────────────────────────────
9
+ // MOCK BUILDERS
10
+ // ───────────────────────────────────────────────────────────────
11
+
12
+ /**
13
+ * Build a minimal AnalysisReport for testing.
14
+ */
15
+ function makeReport(overrides: Partial<AnalysisReport> = {}): AnalysisReport {
16
+ return {
17
+ timestamp: new Date().toISOString(),
18
+ projectInfo: {
19
+ path: '/test-project',
20
+ name: 'test-project',
21
+ frameworks: ['NestJS'],
22
+ totalFiles: 100,
23
+ totalLines: 10000,
24
+ primaryLanguages: ['TypeScript'],
25
+ },
26
+ score: {
27
+ overall: 75,
28
+ components: [],
29
+ breakdown: { modularity: 80, coupling: 70, cohesion: 75, layering: 80 },
30
+ },
31
+ antiPatterns: [],
32
+ layers: [],
33
+ dependencyGraph: { nodes: [], edges: [] },
34
+ suggestions: [],
35
+ diagram: { mermaid: '', type: 'layer' },
36
+ ...overrides,
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Build a minimal RefactoringPlan for testing.
42
+ */
43
+ function makePlan(overrides: Partial<RefactoringPlan> = {}): RefactoringPlan {
44
+ return {
45
+ timestamp: new Date().toISOString(),
46
+ projectPath: '/test-project',
47
+ currentScore: { overall: 75, components: [], breakdown: { modularity: 80, coupling: 70, cohesion: 75, layering: 80 } },
48
+ estimatedScoreAfter: { overall: 85, breakdown: { modularity: 85, coupling: 80, cohesion: 85, layering: 85 } },
49
+ steps: [],
50
+ totalOperations: 0,
51
+ tier1Steps: 0,
52
+ tier2Steps: 0,
53
+ ...overrides,
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Build a minimal StackInfo for testing.
59
+ */
60
+ function makeStack(overrides: Partial<StackInfo> = {}): StackInfo {
61
+ return {
62
+ primary: 'TypeScript',
63
+ languages: ['TypeScript'],
64
+ frameworks: ['NestJS'],
65
+ hasBackend: true,
66
+ hasFrontend: false,
67
+ hasMobile: false,
68
+ hasDatabase: true,
69
+ testFramework: 'Jest',
70
+ packageManager: 'npm',
71
+ ...overrides,
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Build a basic TemplateContext (non-enriched).
77
+ */
78
+ function makeContext(overrides: Partial<TemplateContext> = {}): TemplateContext {
79
+ return {
80
+ report: makeReport(),
81
+ plan: makePlan(),
82
+ stack: makeStack(),
83
+ projectName: 'test-project',
84
+ stackLabel: 'NestJS + TypeScript',
85
+ config: {
86
+ coverageMinimum: 80,
87
+ scoreThreshold: 70,
88
+ language: 'pt-BR',
89
+ goldenRules: [],
90
+ blockers: [],
91
+ },
92
+ ...overrides,
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Build an EnrichedTemplateContext with all enrichment fields.
98
+ */
99
+ function makeEnrichedContext(
100
+ overrides: Partial<EnrichedTemplateContext> = {},
101
+ ): EnrichedTemplateContext {
102
+ const domain: DomainInsights = {
103
+ domain: 'fintech',
104
+ subDomain: 'payment-processing',
105
+ description: 'Payment processing platform',
106
+ businessEntities: [
107
+ {
108
+ name: 'User',
109
+ source: 'src/entities/user.entity.ts',
110
+ fields: ['id', 'email', 'name'],
111
+ relationships: ['accounts', 'transactions'],
112
+ layer: 'entity',
113
+ },
114
+ {
115
+ name: 'Transaction',
116
+ source: 'src/entities/transaction.entity.ts',
117
+ fields: ['id', 'amount', 'userId'],
118
+ relationships: ['user', 'account'],
119
+ layer: 'entity',
120
+ },
121
+ ],
122
+ compliance: [
123
+ {
124
+ name: 'PCI-DSS',
125
+ reason: 'Processes payment card data',
126
+ mandatoryChecks: ['encryption', 'access-control', 'audit-logging'],
127
+ },
128
+ {
129
+ name: 'LGPD',
130
+ reason: 'Processes Brazilian personal data',
131
+ mandatoryChecks: ['consent', 'right-to-be-forgotten', 'data-portability'],
132
+ },
133
+ ],
134
+ integrations: [
135
+ { name: 'Stripe', type: 'payment', detectedFrom: 'src/services/payment.ts' },
136
+ { name: 'PostgreSQL', type: 'database', detectedFrom: 'package.json' },
137
+ { name: 'Redis', type: 'storage', detectedFrom: 'src/cache/redis.service.ts' },
138
+ ],
139
+ keywords: ['payment', 'transaction', 'user', 'account'],
140
+ confidence: 0.92,
141
+ };
142
+
143
+ const modules: ModuleDetail[] = [
144
+ {
145
+ name: 'Users Module',
146
+ path: 'src/users',
147
+ files: ['user.controller.ts', 'user.service.ts', 'user.entity.ts'],
148
+ fileCount: 3,
149
+ lineCount: 350,
150
+ description: 'User management',
151
+ hasTests: true,
152
+ testFiles: ['user.service.spec.ts'],
153
+ entities: ['User'],
154
+ controllers: ['UserController'],
155
+ services: ['UserService'],
156
+ layer: 'feature',
157
+ },
158
+ {
159
+ name: 'Transactions Module',
160
+ path: 'src/transactions',
161
+ files: ['transaction.controller.ts', 'transaction.service.ts', 'transaction.entity.ts'],
162
+ fileCount: 3,
163
+ lineCount: 420,
164
+ description: 'Transaction processing',
165
+ hasTests: true,
166
+ testFiles: ['transaction.service.spec.ts'],
167
+ entities: ['Transaction'],
168
+ controllers: ['TransactionController'],
169
+ services: ['TransactionService'],
170
+ layer: 'feature',
171
+ },
172
+ {
173
+ name: 'Payment Module',
174
+ path: 'src/payment',
175
+ files: ['payment.service.ts', 'payment.controller.ts'],
176
+ fileCount: 2,
177
+ lineCount: 280,
178
+ description: 'Payment processing',
179
+ hasTests: true,
180
+ testFiles: ['payment.service.spec.ts'],
181
+ entities: [],
182
+ controllers: ['PaymentController'],
183
+ services: ['PaymentService'],
184
+ layer: 'feature',
185
+ },
186
+ ];
187
+
188
+ const endpoints: DetectedEndpoint[] = [
189
+ {
190
+ method: 'GET',
191
+ path: '/users',
192
+ file: 'src/users/user.controller.ts',
193
+ handler: 'getUsers',
194
+ hasAuth: true,
195
+ hasValidation: true,
196
+ },
197
+ {
198
+ method: 'POST',
199
+ path: '/transactions',
200
+ file: 'src/transactions/transaction.controller.ts',
201
+ handler: 'createTransaction',
202
+ hasAuth: true,
203
+ hasValidation: true,
204
+ },
205
+ ];
206
+
207
+ const detectedFrameworks: FrameworkInfo[] = [
208
+ { name: 'NestJS', version: '10.2.8', category: 'web', confidence: 0.99 },
209
+ { name: 'TypeORM', version: '0.3.17', category: 'orm', confidence: 0.98 },
210
+ { name: 'Jest', version: '29.7.0', category: 'test', confidence: 0.99 },
211
+ { name: 'ESLint', version: '8.50.0', category: 'lint', confidence: 0.95 },
212
+ ];
213
+
214
+ const toolchain: DetectedToolchain = {
215
+ buildCmd: 'npm run build',
216
+ testCmd: 'npm test',
217
+ lintCmd: 'npm run lint',
218
+ runCmd: 'npm run start:dev',
219
+ coverageCmd: 'npm run test:cov',
220
+ installCmd: 'npm install',
221
+ migrateCmd: 'npm run migration:run',
222
+ depsFile: 'package.json',
223
+ };
224
+
225
+ return {
226
+ ...makeContext(),
227
+ domain,
228
+ modules,
229
+ endpoints,
230
+ untestedModules: [],
231
+ criticalPaths: ['src/payment/payment.service.ts'],
232
+ projectDepth: 'large',
233
+ detectedFrameworks,
234
+ primaryFramework: detectedFrameworks[0],
235
+ toolchain,
236
+ projectStructure: 'modular',
237
+ ...overrides,
238
+ };
239
+ }
240
+
241
+ // ───────────────────────────────────────────────────────────────
242
+ // TEST SUITE
243
+ // ───────────────────────────────────────────────────────────────
244
+
245
+ describe('template-helpers', () => {
246
+ // ─ 1. getEnriched ─
247
+ describe('getEnriched', () => {
248
+ it('should return enriched context when context is enriched', () => {
249
+ const enriched = makeEnrichedContext();
250
+ const result = getEnriched(enriched);
251
+
252
+ expect(result).toBeDefined();
253
+ expect(result.domain).toBeDefined();
254
+ expect(result.domain?.domain).toBe('fintech');
255
+ expect(result.modules).toBeDefined();
256
+ expect(result.modules?.length).toBe(3);
257
+ });
258
+
259
+ it('should return empty object when context is not enriched', () => {
260
+ const basic = makeContext();
261
+ const result = getEnriched(basic);
262
+
263
+ expect(result).toEqual({});
264
+ expect(result.domain).toBeUndefined();
265
+ });
266
+ });
267
+
268
+ // ─ 2. isEnriched ─
269
+ describe('isEnriched', () => {
270
+ it('should return true for enriched context', () => {
271
+ const enriched = makeEnrichedContext();
272
+ expect(isEnriched(enriched)).toBe(true);
273
+ });
274
+
275
+ it('should return false for non-enriched context', () => {
276
+ const basic = makeContext();
277
+ expect(isEnriched(basic)).toBe(false);
278
+ });
279
+
280
+ it('should narrow type correctly', () => {
281
+ const ctx: TemplateContext = makeEnrichedContext();
282
+ if (isEnriched(ctx)) {
283
+ // Should be able to access domain safely
284
+ expect(ctx.domain.domain).toBe('fintech');
285
+ }
286
+ });
287
+ });
288
+
289
+ // ─ 3. depthScale ─
290
+ describe('depthScale', () => {
291
+ it('should return small value for small projects', () => {
292
+ const ctx = makeEnrichedContext({ projectDepth: 'small' });
293
+ const result = depthScale(ctx, {
294
+ small: 5,
295
+ medium: 10,
296
+ large: 20,
297
+ enterprise: 50,
298
+ });
299
+ expect(result).toBe(5);
300
+ });
301
+
302
+ it('should return medium value for medium projects', () => {
303
+ const ctx = makeEnrichedContext({ projectDepth: 'medium' });
304
+ const result = depthScale(ctx, {
305
+ small: 5,
306
+ medium: 10,
307
+ large: 20,
308
+ enterprise: 50,
309
+ });
310
+ expect(result).toBe(10);
311
+ });
312
+
313
+ it('should return large value for large projects', () => {
314
+ const ctx = makeEnrichedContext({ projectDepth: 'large' });
315
+ const result = depthScale(ctx, {
316
+ small: 5,
317
+ medium: 10,
318
+ large: 20,
319
+ enterprise: 50,
320
+ });
321
+ expect(result).toBe(20);
322
+ });
323
+
324
+ it('should return enterprise value for enterprise projects', () => {
325
+ const ctx = makeEnrichedContext({ projectDepth: 'enterprise' });
326
+ const result = depthScale(ctx, {
327
+ small: 5,
328
+ medium: 10,
329
+ large: 20,
330
+ enterprise: 50,
331
+ });
332
+ expect(result).toBe(50);
333
+ });
334
+
335
+ it('should default to medium when projectDepth is missing', () => {
336
+ const ctx = makeContext(); // Non-enriched
337
+ const result = depthScale(ctx, {
338
+ small: 5,
339
+ medium: 10,
340
+ large: 20,
341
+ enterprise: 50,
342
+ });
343
+ expect(result).toBe(10);
344
+ });
345
+
346
+ it('should work with string values', () => {
347
+ const ctx = makeEnrichedContext({ projectDepth: 'large' });
348
+ const result = depthScale(ctx, {
349
+ small: 'tiny',
350
+ medium: 'regular',
351
+ large: 'huge',
352
+ enterprise: 'massive',
353
+ });
354
+ expect(result).toBe('huge');
355
+ });
356
+ });
357
+
358
+ // ─ 4. depthAtLeast ─
359
+ describe('depthAtLeast', () => {
360
+ it('should return true when project depth >= minimum', () => {
361
+ const ctx = makeEnrichedContext({ projectDepth: 'large' });
362
+ expect(depthAtLeast(ctx, 'medium')).toBe(true);
363
+ expect(depthAtLeast(ctx, 'large')).toBe(true);
364
+ });
365
+
366
+ it('should return false when project depth < minimum', () => {
367
+ const ctx = makeEnrichedContext({ projectDepth: 'small' });
368
+ expect(depthAtLeast(ctx, 'medium')).toBe(false);
369
+ expect(depthAtLeast(ctx, 'large')).toBe(false);
370
+ });
371
+
372
+ it('should work with enterprise depth', () => {
373
+ const ctx = makeEnrichedContext({ projectDepth: 'enterprise' });
374
+ expect(depthAtLeast(ctx, 'small')).toBe(true);
375
+ expect(depthAtLeast(ctx, 'medium')).toBe(true);
376
+ expect(depthAtLeast(ctx, 'large')).toBe(true);
377
+ expect(depthAtLeast(ctx, 'enterprise')).toBe(true);
378
+ });
379
+
380
+ it('should default to medium when projectDepth missing', () => {
381
+ const ctx = makeContext(); // Non-enriched
382
+ expect(depthAtLeast(ctx, 'small')).toBe(true);
383
+ expect(depthAtLeast(ctx, 'medium')).toBe(true);
384
+ expect(depthAtLeast(ctx, 'large')).toBe(false);
385
+ });
386
+ });
387
+
388
+ // ─ 5. crossRef ─
389
+ describe('crossRef', () => {
390
+ it('should generate cross-reference table for backend agent', () => {
391
+ const ctx = makeContext({
392
+ stack: makeStack({
393
+ hasBackend: true,
394
+ hasFrontend: true,
395
+ hasMobile: true,
396
+ hasDatabase: true,
397
+ }),
398
+ });
399
+
400
+ const result = crossRef('backend', ctx);
401
+
402
+ expect(result).toContain('🔗 Cross-References');
403
+ expect(result).toContain('Database Engineer');
404
+ expect(result).toContain('Security Auditor');
405
+ expect(result).toContain('QA Test Engineer');
406
+ expect(result).toContain('Tech Debt Controller');
407
+ });
408
+
409
+ it('should filter out missing stack components', () => {
410
+ const ctx = makeContext({
411
+ stack: makeStack({
412
+ hasFrontend: false,
413
+ hasMobile: false,
414
+ hasDatabase: false,
415
+ }),
416
+ });
417
+
418
+ const result = crossRef('backend', ctx);
419
+
420
+ // Should not mention frontend or mobile when missing
421
+ expect(result).not.toContain('Frontend Developer');
422
+ expect(result).not.toContain('Flutter');
423
+ });
424
+
425
+ it('should return empty string for unknown agent', () => {
426
+ const ctx = makeContext();
427
+ const result = crossRef('unknown-agent', ctx);
428
+ expect(result).toBe('');
429
+ });
430
+
431
+ it('should include cross-references for frontend agent', () => {
432
+ const ctx = makeContext({
433
+ stack: makeStack({ hasBackend: true, hasFrontend: true }),
434
+ });
435
+
436
+ const result = crossRef('frontend', ctx);
437
+
438
+ expect(result).toContain('Backend Developer');
439
+ expect(result).toContain('QA Test Engineer');
440
+ });
441
+
442
+ it('should include cross-references for orchestrator agent', () => {
443
+ const ctx = makeContext({
444
+ stack: makeStack({
445
+ hasBackend: true,
446
+ hasFrontend: true,
447
+ hasMobile: true,
448
+ hasDatabase: true,
449
+ }),
450
+ });
451
+
452
+ const result = crossRef('orchestrator', ctx);
453
+
454
+ expect(result).toContain('Backend Developer');
455
+ expect(result).toContain('Frontend Developer');
456
+ expect(result).toContain('Flutter UI Developer');
457
+ expect(result).toContain('Database Engineer');
458
+ expect(result).toContain('Security Auditor');
459
+ });
460
+ });
461
+
462
+ // ─ 6. domainBadge ─
463
+ describe('domainBadge', () => {
464
+ it('should generate domain badge for enriched context', () => {
465
+ const ctx = makeEnrichedContext();
466
+ const result = domainBadge(ctx);
467
+
468
+ expect(result).toContain('📌 **Domínio:**');
469
+ expect(result).toContain('fintech');
470
+ expect(result).toContain('payment-processing');
471
+ expect(result).toContain('**Confiança:** 92%');
472
+ });
473
+
474
+ it('should return empty string for non-enriched context', () => {
475
+ const ctx = makeContext();
476
+ const result = domainBadge(ctx);
477
+ expect(result).toBe('');
478
+ });
479
+
480
+ it('should format confidence as percentage', () => {
481
+ const ctx = makeEnrichedContext({
482
+ domain: {
483
+ ...makeEnrichedContext().domain,
484
+ confidence: 0.85,
485
+ },
486
+ });
487
+
488
+ const result = domainBadge(ctx);
489
+ expect(result).toContain('85%');
490
+ });
491
+ });
492
+
493
+ // ─ 7. complianceBadges ─
494
+ describe('complianceBadges', () => {
495
+ it('should generate compliance badges when present', () => {
496
+ const ctx = makeEnrichedContext();
497
+ const result = complianceBadges(ctx);
498
+
499
+ expect(result).toContain('⚖️ Compliance Obrigatório');
500
+ expect(result).toContain('PCI-DSS');
501
+ expect(result).toContain('LGPD');
502
+ expect(result).toContain('encryption');
503
+ expect(result).toContain('consent');
504
+ });
505
+
506
+ it('should return empty string when no compliance', () => {
507
+ const ctx = makeEnrichedContext({
508
+ domain: {
509
+ ...makeEnrichedContext().domain,
510
+ compliance: [],
511
+ },
512
+ });
513
+
514
+ const result = complianceBadges(ctx);
515
+ expect(result).toBe('');
516
+ });
517
+
518
+ it('should list all mandatory checks', () => {
519
+ const ctx = makeEnrichedContext();
520
+ const result = complianceBadges(ctx);
521
+
522
+ expect(result).toContain('access-control');
523
+ expect(result).toContain('audit-logging');
524
+ expect(result).toContain('right-to-be-forgotten');
525
+ });
526
+ });
527
+
528
+ // ─ 8. depthIndicator ─
529
+ describe('depthIndicator', () => {
530
+ it('should return green indicator for small projects', () => {
531
+ const ctx = makeEnrichedContext({ projectDepth: 'small' });
532
+ const result = depthIndicator(ctx);
533
+ expect(result).toBe('🟢 Projeto Pequeno (< 50 arquivos)');
534
+ });
535
+
536
+ it('should return yellow indicator for medium projects', () => {
537
+ const ctx = makeEnrichedContext({ projectDepth: 'medium' });
538
+ const result = depthIndicator(ctx);
539
+ expect(result).toBe('🟡 Projeto Médio (50-200 arquivos)');
540
+ });
541
+
542
+ it('should return orange indicator for large projects', () => {
543
+ const ctx = makeEnrichedContext({ projectDepth: 'large' });
544
+ const result = depthIndicator(ctx);
545
+ expect(result).toBe('🟠 Projeto Grande (200-500 arquivos)');
546
+ });
547
+
548
+ it('should return red indicator for enterprise projects', () => {
549
+ const ctx = makeEnrichedContext({ projectDepth: 'enterprise' });
550
+ const result = depthIndicator(ctx);
551
+ expect(result).toBe('🔴 Enterprise (500+ arquivos)');
552
+ });
553
+
554
+ it('should default to medium when projectDepth missing', () => {
555
+ const ctx = makeContext();
556
+ const result = depthIndicator(ctx);
557
+ expect(result).toBe('🟡 Projeto Médio (50-200 arquivos)');
558
+ });
559
+ });
560
+
561
+ // ─ 9. modulesSummaryTable ─
562
+ describe('modulesSummaryTable', () => {
563
+ it('should generate markdown table for modules', () => {
564
+ const ctx = makeEnrichedContext();
565
+ const result = modulesSummaryTable(ctx);
566
+
567
+ expect(result).toContain('| Módulo | Arquivos | Linhas | Testes | Camada |');
568
+ expect(result).toContain('Users Module');
569
+ expect(result).toContain('Transactions Module');
570
+ expect(result).toContain('✅'); // hasTests = true
571
+ });
572
+
573
+ it('should return empty string when no modules', () => {
574
+ const ctx = makeEnrichedContext({ modules: [] });
575
+ const result = modulesSummaryTable(ctx);
576
+ expect(result).toBe('');
577
+ });
578
+
579
+ it('should respect depth scaling for max modules', () => {
580
+ const modules = Array.from({ length: 30 }, (_, i) => ({
581
+ name: `Module ${i + 1}`,
582
+ path: `src/module-${i + 1}`,
583
+ files: ['index.ts'],
584
+ fileCount: 1,
585
+ lineCount: 100,
586
+ description: `Module ${i + 1}`,
587
+ hasTests: true,
588
+ testFiles: ['index.spec.ts'],
589
+ entities: [],
590
+ controllers: [],
591
+ services: [],
592
+ layer: 'feature',
593
+ }));
594
+
595
+ const smallCtx = makeEnrichedContext({ projectDepth: 'small', modules });
596
+ const smallResult = modulesSummaryTable(smallCtx);
597
+ const smallLines = smallResult.split('\n').length;
598
+
599
+ const largeCtx = makeEnrichedContext({ projectDepth: 'large', modules });
600
+ const largeResult = modulesSummaryTable(largeCtx);
601
+ const largeLines = largeResult.split('\n').length;
602
+
603
+ expect(smallLines).toBeLessThan(largeLines); // Small project shows fewer modules
604
+ });
605
+
606
+ it('should show line count with locale formatting', () => {
607
+ const ctx = makeEnrichedContext();
608
+ const result = modulesSummaryTable(ctx);
609
+ expect(result).toContain('350');
610
+ expect(result).toContain('420');
611
+ });
612
+
613
+ it('should show "—" for zero line count', () => {
614
+ const ctx = makeEnrichedContext({
615
+ modules: [
616
+ {
617
+ name: 'Empty Module',
618
+ path: 'src/empty',
619
+ files: [],
620
+ fileCount: 0,
621
+ lineCount: 0,
622
+ description: 'Empty',
623
+ hasTests: false,
624
+ testFiles: [],
625
+ entities: [],
626
+ controllers: [],
627
+ services: [],
628
+ layer: 'feature',
629
+ },
630
+ ],
631
+ });
632
+
633
+ const result = modulesSummaryTable(ctx);
634
+ expect(result).toContain('—');
635
+ });
636
+ });
637
+
638
+ // ─ 10. integrationsSummary ─
639
+ describe('integrationsSummary', () => {
640
+ it('should generate integrations summary', () => {
641
+ const ctx = makeEnrichedContext();
642
+ const result = integrationsSummary(ctx);
643
+
644
+ expect(result).toContain('Integrações Externas Detectadas');
645
+ expect(result).toContain('Stripe');
646
+ expect(result).toContain('payment');
647
+ expect(result).toContain('PostgreSQL');
648
+ expect(result).toContain('Redis');
649
+ });
650
+
651
+ it('should return empty string when no integrations', () => {
652
+ const ctx = makeEnrichedContext({
653
+ domain: {
654
+ ...makeEnrichedContext().domain,
655
+ integrations: [],
656
+ },
657
+ });
658
+
659
+ const result = integrationsSummary(ctx);
660
+ expect(result).toBe('');
661
+ });
662
+
663
+ it('should show detected location for each integration', () => {
664
+ const ctx = makeEnrichedContext();
665
+ const result = integrationsSummary(ctx);
666
+
667
+ expect(result).toContain('src/services/payment.ts');
668
+ expect(result).toContain('package.json');
669
+ expect(result).toContain('src/cache/redis.service.ts');
670
+ });
671
+ });
672
+
673
+ // ─ 11. frameworkBadge ─
674
+ describe('frameworkBadge', () => {
675
+ it('should generate framework badge with versions', () => {
676
+ const ctx = makeEnrichedContext();
677
+ const result = frameworkBadge(ctx);
678
+
679
+ expect(result).toContain('🚀 **Stack Detectada:**');
680
+ expect(result).toContain('NestJS');
681
+ expect(result).toContain('10.2.8');
682
+ expect(result).toContain('TypeORM');
683
+ expect(result).toContain('0.3.17');
684
+ });
685
+
686
+ it('should include test frameworks', () => {
687
+ const ctx = makeEnrichedContext();
688
+ const result = frameworkBadge(ctx);
689
+
690
+ expect(result).toContain('Testes: Jest');
691
+ });
692
+
693
+ it('should include lint frameworks', () => {
694
+ const ctx = makeEnrichedContext();
695
+ const result = frameworkBadge(ctx);
696
+
697
+ expect(result).toContain('Lint: ESLint');
698
+ });
699
+
700
+ it('should return empty string when no frameworks detected', () => {
701
+ const ctx = makeEnrichedContext({
702
+ detectedFrameworks: [],
703
+ primaryFramework: null,
704
+ });
705
+
706
+ const result = frameworkBadge(ctx);
707
+ expect(result).toBe('');
708
+ });
709
+
710
+ it('should handle frameworks without versions', () => {
711
+ const ctx = makeEnrichedContext({
712
+ detectedFrameworks: [
713
+ { name: 'NestJS', version: null, category: 'web', confidence: 0.99 },
714
+ ],
715
+ primaryFramework: { name: 'NestJS', version: null, category: 'web', confidence: 0.99 },
716
+ });
717
+
718
+ const result = frameworkBadge(ctx);
719
+ expect(result).toContain('NestJS');
720
+ });
721
+ });
722
+
723
+ // ─ 12. projectStructureBadge ─
724
+ describe('projectStructureBadge', () => {
725
+ it('should return clean architecture badge', () => {
726
+ const ctx = makeEnrichedContext({ projectStructure: 'clean-architecture' });
727
+ const result = projectStructureBadge(ctx);
728
+ expect(result).toBe('🏛️ Clean Architecture / DDD');
729
+ });
730
+
731
+ it('should return MVC badge', () => {
732
+ const ctx = makeEnrichedContext({ projectStructure: 'mvc' });
733
+ const result = projectStructureBadge(ctx);
734
+ expect(result).toBe('📐 MVC (Model-View-Controller)');
735
+ });
736
+
737
+ it('should return modular badge', () => {
738
+ const ctx = makeEnrichedContext({ projectStructure: 'modular' });
739
+ const result = projectStructureBadge(ctx);
740
+ expect(result).toBe('📦 Modular (Feature-based)');
741
+ });
742
+
743
+ it('should return flat badge', () => {
744
+ const ctx = makeEnrichedContext({ projectStructure: 'flat' });
745
+ const result = projectStructureBadge(ctx);
746
+ expect(result).toBe('📄 Flat Structure');
747
+ });
748
+
749
+ it('should return monorepo badge', () => {
750
+ const ctx = makeEnrichedContext({ projectStructure: 'monorepo' });
751
+ const result = projectStructureBadge(ctx);
752
+ expect(result).toBe('🏗️ Monorepo');
753
+ });
754
+
755
+ it('should return unknown badge', () => {
756
+ const ctx = makeEnrichedContext({ projectStructure: 'unknown' });
757
+ const result = projectStructureBadge(ctx);
758
+ expect(result).toBe('❓ Estrutura não identificada');
759
+ });
760
+ });
761
+
762
+ // ─ 13. toolchainCommands ─
763
+ describe('toolchainCommands', () => {
764
+ it('should generate toolchain commands block', () => {
765
+ const ctx = makeEnrichedContext();
766
+ const result = toolchainCommands(ctx);
767
+
768
+ expect(result).toContain('🔧 Toolchain Detectado');
769
+ expect(result).toContain('```bash');
770
+ expect(result).toContain('npm run build');
771
+ expect(result).toContain('npm test');
772
+ expect(result).toContain('npm run lint');
773
+ expect(result).toContain('npm run start:dev');
774
+ expect(result).toContain('npm run test:cov');
775
+ });
776
+
777
+ it('should include migration command when present', () => {
778
+ const ctx = makeEnrichedContext();
779
+ const result = toolchainCommands(ctx);
780
+
781
+ expect(result).toContain('npm run migration:run');
782
+ });
783
+
784
+ it('should show deps file', () => {
785
+ const ctx = makeEnrichedContext();
786
+ const result = toolchainCommands(ctx);
787
+
788
+ expect(result).toContain('package.json');
789
+ });
790
+
791
+ it('should return empty string when no toolchain', () => {
792
+ const ctx = makeEnrichedContext({
793
+ toolchain: undefined as any,
794
+ });
795
+
796
+ const result = toolchainCommands(ctx);
797
+ expect(result).toBe('');
798
+ });
799
+
800
+ it('should omit migration section when migrateCmd is null', () => {
801
+ const ctx = makeEnrichedContext({
802
+ toolchain: {
803
+ buildCmd: 'npm run build',
804
+ testCmd: 'npm test',
805
+ lintCmd: 'npm run lint',
806
+ runCmd: 'npm run start:dev',
807
+ coverageCmd: 'npm run test:cov',
808
+ installCmd: 'npm install',
809
+ migrateCmd: null,
810
+ depsFile: 'package.json',
811
+ },
812
+ });
813
+
814
+ const result = toolchainCommands(ctx);
815
+ expect(result).not.toContain('# Migrations');
816
+ });
817
+ });
818
+
819
+ // ─ 14. frameworkModuleStructure ─
820
+ describe('frameworkModuleStructure', () => {
821
+ it('should return FastAPI structure for FastAPI framework', () => {
822
+ const ctx = makeEnrichedContext({
823
+ stack: makeStack({ primary: 'Python', frameworks: ['FastAPI'] }),
824
+ primaryFramework: { name: 'FastAPI', version: '0.104.1', category: 'web', confidence: 0.99 },
825
+ projectStructure: 'modular',
826
+ });
827
+
828
+ const result = frameworkModuleStructure(ctx);
829
+
830
+ expect(result).toContain('app/');
831
+ expect(result).toContain('main.py');
832
+ expect(result).toContain('api/');
833
+ expect(result).toContain('routes/');
834
+ expect(result).toContain('dependencies.py');
835
+ expect(result).toContain('core/');
836
+ expect(result).toContain('config.py');
837
+ expect(result).toContain('services/');
838
+ });
839
+
840
+ it('should return Django structure for Django framework', () => {
841
+ const ctx = makeEnrichedContext({
842
+ stack: makeStack({ primary: 'Python', frameworks: ['Django'] }),
843
+ primaryFramework: { name: 'Django', version: '4.2', category: 'web', confidence: 0.99 },
844
+ projectStructure: 'modular',
845
+ });
846
+
847
+ const result = frameworkModuleStructure(ctx);
848
+
849
+ expect(result).toContain('manage.py');
850
+ expect(result).toContain('config/');
851
+ expect(result).toContain('settings/');
852
+ expect(result).toContain('apps/');
853
+ expect(result).toContain('models.py');
854
+ expect(result).toContain('views.py');
855
+ expect(result).toContain('serializers.py');
856
+ });
857
+
858
+ it('should return NestJS structure for NestJS framework', () => {
859
+ const ctx = makeEnrichedContext({
860
+ primaryFramework: { name: 'NestJS', version: '10.2.8', category: 'web', confidence: 0.99 },
861
+ projectStructure: 'modular',
862
+ });
863
+
864
+ const result = frameworkModuleStructure(ctx);
865
+
866
+ expect(result).toContain('src/');
867
+ expect(result).toContain('main.ts');
868
+ expect(result).toContain('modules/');
869
+ expect(result).toContain('[name].module.ts');
870
+ expect(result).toContain('[name].controller.ts');
871
+ expect(result).toContain('[name].service.ts');
872
+ expect(result).toContain('dto/');
873
+ });
874
+
875
+ it('should return Express structure for Express framework', () => {
876
+ const ctx = makeEnrichedContext({
877
+ primaryFramework: { name: 'Express', version: '4.18.2', category: 'web', confidence: 0.99 },
878
+ projectStructure: 'modular',
879
+ });
880
+
881
+ const result = frameworkModuleStructure(ctx);
882
+
883
+ expect(result).toContain('src/');
884
+ expect(result).toContain('routes/');
885
+ expect(result).toContain('controllers/');
886
+ expect(result).toContain('services/');
887
+ expect(result).toContain('models/');
888
+ expect(result).toContain('middleware/');
889
+ });
890
+
891
+ it('should return Spring Boot structure for Spring Boot framework', () => {
892
+ const ctx = makeEnrichedContext({
893
+ stack: makeStack({ primary: 'Java', frameworks: ['Spring Boot'] }),
894
+ primaryFramework: { name: 'Spring Boot', version: '3.1.5', category: 'web', confidence: 0.99 },
895
+ projectStructure: 'modular',
896
+ });
897
+
898
+ const result = frameworkModuleStructure(ctx);
899
+
900
+ expect(result).toContain('src/main/java');
901
+ expect(result).toContain('Application.java');
902
+ expect(result).toContain('controller/');
903
+ expect(result).toContain('service/');
904
+ expect(result).toContain('repository/');
905
+ expect(result).toContain('model/');
906
+ expect(result).toContain('@SpringBootApplication');
907
+ });
908
+
909
+ it('should return Laravel structure for Laravel framework', () => {
910
+ const ctx = makeEnrichedContext({
911
+ stack: makeStack({ primary: 'PHP', frameworks: ['Laravel'] }),
912
+ primaryFramework: { name: 'Laravel', version: '10.0', category: 'web', confidence: 0.99 },
913
+ projectStructure: 'modular',
914
+ });
915
+
916
+ const result = frameworkModuleStructure(ctx);
917
+
918
+ expect(result).toContain('app/');
919
+ expect(result).toContain('Http/');
920
+ expect(result).toContain('Controllers/');
921
+ expect(result).toContain('Models/');
922
+ expect(result).toContain('database/');
923
+ expect(result).toContain('migrations/');
924
+ });
925
+
926
+ it('should return Ruby on Rails structure for Rails framework', () => {
927
+ const ctx = makeEnrichedContext({
928
+ stack: makeStack({ primary: 'Ruby', frameworks: ['Ruby on Rails'] }),
929
+ primaryFramework: { name: 'Ruby on Rails', version: '7.0', category: 'web', confidence: 0.99 },
930
+ projectStructure: 'modular',
931
+ });
932
+
933
+ const result = frameworkModuleStructure(ctx);
934
+
935
+ expect(result).toContain('app/');
936
+ expect(result).toContain('controllers/');
937
+ expect(result).toContain('models/');
938
+ expect(result).toContain('views/');
939
+ expect(result).toContain('config/');
940
+ expect(result).toContain('routes.rb');
941
+ });
942
+
943
+ it('should return Go framework structure for Gin', () => {
944
+ const ctx = makeEnrichedContext({
945
+ stack: makeStack({ primary: 'Go', frameworks: ['Gin'] }),
946
+ primaryFramework: { name: 'Gin', version: '1.9.1', category: 'web', confidence: 0.99 },
947
+ projectStructure: 'modular',
948
+ });
949
+
950
+ const result = frameworkModuleStructure(ctx);
951
+
952
+ expect(result).toContain('cmd/');
953
+ expect(result).toContain('internal/');
954
+ expect(result).toContain('handler/');
955
+ expect(result).toContain('service/');
956
+ expect(result).toContain('go.mod');
957
+ });
958
+
959
+ it('should return clean architecture Python structure', () => {
960
+ const ctx = makeEnrichedContext({
961
+ stack: makeStack({ primary: 'Python', frameworks: ['FastAPI'] }),
962
+ primaryFramework: { name: 'FastAPI', version: '0.104.1', category: 'web', confidence: 0.99 },
963
+ projectStructure: 'clean-architecture',
964
+ });
965
+
966
+ const result = frameworkModuleStructure(ctx);
967
+
968
+ expect(result).toContain('src/[projeto]/');
969
+ expect(result).toContain('domain/');
970
+ expect(result).toContain('entities/');
971
+ expect(result).toContain('application/');
972
+ expect(result).toContain('infrastructure/');
973
+ expect(result).toContain('presentation/');
974
+ });
975
+
976
+ it('should return generic fallback structure', () => {
977
+ const ctx = makeEnrichedContext({
978
+ stack: makeStack({ primary: 'UnknownLang', frameworks: [] }),
979
+ primaryFramework: null,
980
+ projectStructure: 'unknown',
981
+ });
982
+
983
+ const result = frameworkModuleStructure(ctx);
984
+
985
+ expect(result).toContain('src/');
986
+ expect(result).toContain('controllers/');
987
+ expect(result).toContain('services/');
988
+ expect(result).toContain('models/');
989
+ });
990
+ });
991
+
992
+ // ─ 15. frameworkSecurityChecklist ─
993
+ describe('frameworkSecurityChecklist', () => {
994
+ it('should return FastAPI security checklist', () => {
995
+ const ctx = makeEnrichedContext({
996
+ primaryFramework: { name: 'FastAPI', version: '0.104.1', category: 'web', confidence: 0.99 },
997
+ });
998
+
999
+ const result = frameworkSecurityChecklist(ctx);
1000
+
1001
+ expect(result).toContain('Checklist Segurança — FastAPI');
1002
+ expect(result).toContain('Pydantic models');
1003
+ expect(result).toContain('OAuth2PasswordBearer');
1004
+ expect(result).toContain('CORS');
1005
+ expect(result).toContain('Rate limiting');
1006
+ expect(result).toContain('passlib');
1007
+ expect(result).toContain('JWT tokens');
1008
+ });
1009
+
1010
+ it('should return Django security checklist', () => {
1011
+ const ctx = makeEnrichedContext({
1012
+ stack: makeStack({ primary: 'Python', frameworks: ['Django'] }),
1013
+ primaryFramework: { name: 'Django', version: '4.2', category: 'web', confidence: 0.99 },
1014
+ });
1015
+
1016
+ const result = frameworkSecurityChecklist(ctx);
1017
+
1018
+ expect(result).toContain('Checklist Segurança — Django');
1019
+ expect(result).toContain('CSRF protection');
1020
+ expect(result).toContain('XSS protection');
1021
+ expect(result).toContain('SQL Injection');
1022
+ expect(result).toContain('SECURE_SSL_REDIRECT');
1023
+ expect(result).toContain('DEBUG = False');
1024
+ });
1025
+
1026
+ it('should return NestJS security checklist', () => {
1027
+ const ctx = makeEnrichedContext({
1028
+ primaryFramework: { name: 'NestJS', version: '10.2.8', category: 'web', confidence: 0.99 },
1029
+ });
1030
+
1031
+ const result = frameworkSecurityChecklist(ctx);
1032
+
1033
+ expect(result).toContain('Checklist Segurança — NestJS');
1034
+ expect(result).toContain('Helmet');
1035
+ expect(result).toContain('CORS');
1036
+ expect(result).toContain('Rate limiting');
1037
+ expect(result).toContain('class-validator');
1038
+ expect(result).toContain('Guards');
1039
+ expect(result).toContain('JWT');
1040
+ expect(result).toContain('npm audit');
1041
+ });
1042
+
1043
+ it('should return Express security checklist', () => {
1044
+ const ctx = makeEnrichedContext({
1045
+ primaryFramework: { name: 'Express', version: '4.18.2', category: 'web', confidence: 0.99 },
1046
+ });
1047
+
1048
+ const result = frameworkSecurityChecklist(ctx);
1049
+
1050
+ expect(result).toContain('Checklist Segurança — Express');
1051
+ expect(result).toContain('Helmet.js');
1052
+ expect(result).toContain('CORS');
1053
+ expect(result).toContain('Rate limiting');
1054
+ expect(result).toContain('Input validation');
1055
+ expect(result).toContain('JWT');
1056
+ });
1057
+
1058
+ it('should return Spring Boot security checklist', () => {
1059
+ const ctx = makeEnrichedContext({
1060
+ stack: makeStack({ primary: 'Java', frameworks: ['Spring Boot'] }),
1061
+ primaryFramework: { name: 'Spring Boot', version: '3.1.5', category: 'web', confidence: 0.99 },
1062
+ });
1063
+
1064
+ const result = frameworkSecurityChecklist(ctx);
1065
+
1066
+ expect(result).toContain('Checklist Segurança — Spring Boot');
1067
+ expect(result).toContain('Spring Security');
1068
+ expect(result).toContain('CSRF');
1069
+ expect(result).toContain('CORS');
1070
+ expect(result).toContain('BCrypt');
1071
+ });
1072
+
1073
+ it('should return Laravel security checklist', () => {
1074
+ const ctx = makeEnrichedContext({
1075
+ stack: makeStack({ primary: 'PHP', frameworks: ['Laravel'] }),
1076
+ primaryFramework: { name: 'Laravel', version: '10.0', category: 'web', confidence: 0.99 },
1077
+ });
1078
+
1079
+ const result = frameworkSecurityChecklist(ctx);
1080
+
1081
+ expect(result).toContain('Checklist Segurança — Laravel');
1082
+ expect(result).toContain('CSRF token');
1083
+ expect(result).toContain('Eloquent');
1084
+ expect(result).toContain('Form Requests');
1085
+ expect(result).toContain('Sanctum/Passport');
1086
+ });
1087
+
1088
+ it('should return Python fallback security checklist', () => {
1089
+ const ctx = makeEnrichedContext({
1090
+ stack: makeStack({ primary: 'Python', frameworks: [] }),
1091
+ primaryFramework: null,
1092
+ });
1093
+
1094
+ const result = frameworkSecurityChecklist(ctx);
1095
+
1096
+ expect(result).toContain('Checklist Segurança — Python');
1097
+ expect(result).toContain('pydantic');
1098
+ expect(result).toContain('Queries parametrizadas');
1099
+ expect(result).toContain('pip-audit');
1100
+ });
1101
+
1102
+ it('should return Go fallback security checklist', () => {
1103
+ const ctx = makeEnrichedContext({
1104
+ stack: makeStack({ primary: 'Go', frameworks: [] }),
1105
+ primaryFramework: null,
1106
+ });
1107
+
1108
+ const result = frameworkSecurityChecklist(ctx);
1109
+
1110
+ expect(result).toContain('Checklist Segurança — Go');
1111
+ expect(result).toContain('validator');
1112
+ expect(result).toContain('Prepared statements');
1113
+ expect(result).toContain('govulncheck');
1114
+ });
1115
+
1116
+ it('should return generic fallback when no framework or language match', () => {
1117
+ const ctx = makeEnrichedContext({
1118
+ stack: makeStack({ primary: 'UnknownLang', frameworks: [] }),
1119
+ primaryFramework: null,
1120
+ });
1121
+
1122
+ const result = frameworkSecurityChecklist(ctx);
1123
+
1124
+ expect(result).toContain('Checklist Segurança — UnknownLang');
1125
+ expect(result).toContain('Inputs sanitizados');
1126
+ expect(result).toContain('CSRF tokens');
1127
+ expect(result).toContain('HTTPS');
1128
+ });
1129
+ });
1130
+ });