@girardelli/architect 5.0.0 → 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 (335) hide show
  1. package/dist/{cli.d.ts → src/adapters/cli.d.ts} +1 -2
  2. package/dist/{cli.js → src/adapters/cli.js} +191 -213
  3. package/dist/src/adapters/cli.js.map +1 -0
  4. package/dist/src/adapters/github-action.d.ts +9 -0
  5. package/dist/src/adapters/github-action.js +94 -0
  6. package/dist/src/adapters/github-action.js.map +1 -0
  7. package/dist/src/adapters/html-reporter/scripts.d.ts +5 -0
  8. package/dist/src/adapters/html-reporter/scripts.js +400 -0
  9. package/dist/src/adapters/html-reporter/scripts.js.map +1 -0
  10. package/dist/src/adapters/html-reporter/sections/agents.d.ts +2 -0
  11. package/dist/src/adapters/html-reporter/sections/agents.js +260 -0
  12. package/dist/src/adapters/html-reporter/sections/agents.js.map +1 -0
  13. package/dist/src/adapters/html-reporter/sections/anti-patterns.d.ts +13 -0
  14. package/dist/src/adapters/html-reporter/sections/anti-patterns.js +64 -0
  15. package/dist/src/adapters/html-reporter/sections/anti-patterns.js.map +1 -0
  16. package/dist/src/adapters/html-reporter/sections/header.d.ts +3 -0
  17. package/dist/src/adapters/html-reporter/sections/header.js +30 -0
  18. package/dist/src/adapters/html-reporter/sections/header.js.map +1 -0
  19. package/dist/src/adapters/html-reporter/sections/layers.d.ts +9 -0
  20. package/dist/src/adapters/html-reporter/sections/layers.js +143 -0
  21. package/dist/src/adapters/html-reporter/sections/layers.js.map +1 -0
  22. package/dist/src/adapters/html-reporter/sections/overview.d.ts +2 -0
  23. package/dist/src/adapters/html-reporter/sections/overview.js +58 -0
  24. package/dist/src/adapters/html-reporter/sections/overview.js.map +1 -0
  25. package/dist/src/adapters/html-reporter/sections/refactoring-plan.d.ts +3 -0
  26. package/dist/src/adapters/html-reporter/sections/refactoring-plan.js +151 -0
  27. package/dist/src/adapters/html-reporter/sections/refactoring-plan.js.map +1 -0
  28. package/dist/src/adapters/html-reporter/sections/score.d.ts +7 -0
  29. package/dist/src/adapters/html-reporter/sections/score.js +70 -0
  30. package/dist/src/adapters/html-reporter/sections/score.js.map +1 -0
  31. package/dist/src/adapters/html-reporter/sections/suggestions.d.ts +7 -0
  32. package/dist/src/adapters/html-reporter/sections/suggestions.js +34 -0
  33. package/dist/src/adapters/html-reporter/sections/suggestions.js.map +1 -0
  34. package/dist/src/adapters/html-reporter/styles.d.ts +1 -0
  35. package/dist/src/adapters/html-reporter/styles.js +526 -0
  36. package/dist/src/adapters/html-reporter/styles.js.map +1 -0
  37. package/dist/src/adapters/html-reporter/utils_adapters.d.ts +20 -0
  38. package/dist/src/adapters/html-reporter/utils_adapters.js +32 -0
  39. package/dist/src/adapters/html-reporter/utils_adapters.js.map +1 -0
  40. package/dist/src/adapters/html-reporter/utils_sections.d.ts +7 -0
  41. package/dist/src/adapters/html-reporter/utils_sections.js +58 -0
  42. package/dist/src/adapters/html-reporter/utils_sections.js.map +1 -0
  43. package/dist/src/adapters/html-reporter.d.ts +10 -0
  44. package/dist/src/adapters/html-reporter.js +97 -0
  45. package/dist/src/adapters/html-reporter.js.map +1 -0
  46. package/dist/src/adapters/progress-logger.d.ts +55 -0
  47. package/dist/src/adapters/progress-logger.js +200 -0
  48. package/dist/src/adapters/progress-logger.js.map +1 -0
  49. package/dist/{refactor-reporter.d.ts → src/adapters/refactor-reporter.d.ts} +1 -2
  50. package/dist/{refactor-reporter.js → src/adapters/refactor-reporter.js} +1 -1
  51. package/dist/src/adapters/refactor-reporter.js.map +1 -0
  52. package/dist/{reporter.d.ts → src/adapters/reporter.d.ts} +1 -2
  53. package/dist/src/adapters/reporter.js.map +1 -0
  54. package/dist/src/core/GenesisTerminal.d.ts +8 -0
  55. package/dist/src/core/GenesisTerminal.js +105 -0
  56. package/dist/src/core/GenesisTerminal.js.map +1 -0
  57. package/dist/{index.d.ts → src/core/architect.d.ts} +4 -18
  58. package/dist/{index.js → src/core/architect.js} +22 -21
  59. package/dist/src/core/architect.js.map +1 -0
  60. package/dist/tests/architect-adapter-enrichment.test.d.ts +1 -0
  61. package/dist/tests/architect-adapter-enrichment.test.js +11 -0
  62. package/dist/tests/architect-adapter-enrichment.test.js.map +1 -0
  63. package/dist/tests/github-action.test.d.ts +1 -0
  64. package/dist/tests/github-action.test.js +92 -0
  65. package/dist/tests/github-action.test.js.map +1 -0
  66. package/package.json +15 -65
  67. package/src/adapters/cli.ts +492 -0
  68. package/src/adapters/github-action.ts +109 -0
  69. package/src/adapters/html-reporter/scripts.ts +402 -0
  70. package/src/adapters/html-reporter/sections/agents.ts +267 -0
  71. package/src/adapters/html-reporter/sections/anti-patterns.ts +81 -0
  72. package/src/adapters/html-reporter/sections/header.ts +35 -0
  73. package/src/adapters/html-reporter/sections/layers.ts +165 -0
  74. package/src/adapters/html-reporter/sections/overview.ts +64 -0
  75. package/src/adapters/html-reporter/sections/refactoring-plan.ts +166 -0
  76. package/src/adapters/html-reporter/sections/score.ts +80 -0
  77. package/src/adapters/html-reporter/sections/suggestions.ts +39 -0
  78. package/src/adapters/html-reporter/styles.ts +525 -0
  79. package/src/adapters/html-reporter/utils_adapters.ts +39 -0
  80. package/src/adapters/html-reporter/utils_sections.ts +55 -0
  81. package/src/adapters/html-reporter.ts +102 -0
  82. package/src/adapters/progress-logger.ts +236 -0
  83. package/src/{refactor-reporter.ts → adapters/refactor-reporter.ts} +2 -2
  84. package/src/{reporter.ts → adapters/reporter.ts} +1 -1
  85. package/src/core/GenesisTerminal.ts +127 -0
  86. package/src/{index.ts → core/architect.ts} +27 -45
  87. package/tests/github-action.test.ts +109 -0
  88. package/tsconfig.json +12 -19
  89. package/CONTRIBUTING.md +0 -140
  90. package/LICENSE +0 -21
  91. package/PROJECT_STRUCTURE.txt +0 -168
  92. package/README.md +0 -257
  93. package/architect-run.sh +0 -431
  94. package/assets/banner-v3.html +0 -561
  95. package/dist/agent-generator/context-enricher.d.ts +0 -58
  96. package/dist/agent-generator/context-enricher.d.ts.map +0 -1
  97. package/dist/agent-generator/context-enricher.js +0 -613
  98. package/dist/agent-generator/context-enricher.js.map +0 -1
  99. package/dist/agent-generator/domain-inferrer.d.ts +0 -52
  100. package/dist/agent-generator/domain-inferrer.d.ts.map +0 -1
  101. package/dist/agent-generator/domain-inferrer.js +0 -585
  102. package/dist/agent-generator/domain-inferrer.js.map +0 -1
  103. package/dist/agent-generator/framework-detector.d.ts +0 -40
  104. package/dist/agent-generator/framework-detector.d.ts.map +0 -1
  105. package/dist/agent-generator/framework-detector.js +0 -611
  106. package/dist/agent-generator/framework-detector.js.map +0 -1
  107. package/dist/agent-generator/index.d.ts +0 -47
  108. package/dist/agent-generator/index.d.ts.map +0 -1
  109. package/dist/agent-generator/index.js +0 -545
  110. package/dist/agent-generator/index.js.map +0 -1
  111. package/dist/agent-generator/stack-detector.d.ts +0 -14
  112. package/dist/agent-generator/stack-detector.d.ts.map +0 -1
  113. package/dist/agent-generator/stack-detector.js +0 -124
  114. package/dist/agent-generator/stack-detector.js.map +0 -1
  115. package/dist/agent-generator/templates/core/agents.d.ts +0 -17
  116. package/dist/agent-generator/templates/core/agents.d.ts.map +0 -1
  117. package/dist/agent-generator/templates/core/agents.js +0 -1256
  118. package/dist/agent-generator/templates/core/agents.js.map +0 -1
  119. package/dist/agent-generator/templates/core/architecture-rules.d.ts +0 -7
  120. package/dist/agent-generator/templates/core/architecture-rules.d.ts.map +0 -1
  121. package/dist/agent-generator/templates/core/architecture-rules.js +0 -274
  122. package/dist/agent-generator/templates/core/architecture-rules.js.map +0 -1
  123. package/dist/agent-generator/templates/core/general-rules.d.ts +0 -8
  124. package/dist/agent-generator/templates/core/general-rules.d.ts.map +0 -1
  125. package/dist/agent-generator/templates/core/general-rules.js +0 -301
  126. package/dist/agent-generator/templates/core/general-rules.js.map +0 -1
  127. package/dist/agent-generator/templates/core/hooks-generator.d.ts +0 -21
  128. package/dist/agent-generator/templates/core/hooks-generator.d.ts.map +0 -1
  129. package/dist/agent-generator/templates/core/hooks-generator.js +0 -233
  130. package/dist/agent-generator/templates/core/hooks-generator.js.map +0 -1
  131. package/dist/agent-generator/templates/core/index-md.d.ts +0 -7
  132. package/dist/agent-generator/templates/core/index-md.d.ts.map +0 -1
  133. package/dist/agent-generator/templates/core/index-md.js +0 -246
  134. package/dist/agent-generator/templates/core/index-md.js.map +0 -1
  135. package/dist/agent-generator/templates/core/orchestrator.d.ts +0 -8
  136. package/dist/agent-generator/templates/core/orchestrator.d.ts.map +0 -1
  137. package/dist/agent-generator/templates/core/orchestrator.js +0 -422
  138. package/dist/agent-generator/templates/core/orchestrator.js.map +0 -1
  139. package/dist/agent-generator/templates/core/preflight.d.ts +0 -8
  140. package/dist/agent-generator/templates/core/preflight.d.ts.map +0 -1
  141. package/dist/agent-generator/templates/core/preflight.js +0 -213
  142. package/dist/agent-generator/templates/core/preflight.js.map +0 -1
  143. package/dist/agent-generator/templates/core/quality-gates.d.ts +0 -11
  144. package/dist/agent-generator/templates/core/quality-gates.d.ts.map +0 -1
  145. package/dist/agent-generator/templates/core/quality-gates.js +0 -254
  146. package/dist/agent-generator/templates/core/quality-gates.js.map +0 -1
  147. package/dist/agent-generator/templates/core/security-rules.d.ts +0 -7
  148. package/dist/agent-generator/templates/core/security-rules.d.ts.map +0 -1
  149. package/dist/agent-generator/templates/core/security-rules.js +0 -528
  150. package/dist/agent-generator/templates/core/security-rules.js.map +0 -1
  151. package/dist/agent-generator/templates/core/skills-generator.d.ts +0 -19
  152. package/dist/agent-generator/templates/core/skills-generator.d.ts.map +0 -1
  153. package/dist/agent-generator/templates/core/skills-generator.js +0 -546
  154. package/dist/agent-generator/templates/core/skills-generator.js.map +0 -1
  155. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts +0 -7
  156. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts.map +0 -1
  157. package/dist/agent-generator/templates/core/workflow-fix-bug.js +0 -237
  158. package/dist/agent-generator/templates/core/workflow-fix-bug.js.map +0 -1
  159. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts +0 -8
  160. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts.map +0 -1
  161. package/dist/agent-generator/templates/core/workflow-new-feature.js +0 -321
  162. package/dist/agent-generator/templates/core/workflow-new-feature.js.map +0 -1
  163. package/dist/agent-generator/templates/core/workflow-review.d.ts +0 -7
  164. package/dist/agent-generator/templates/core/workflow-review.d.ts.map +0 -1
  165. package/dist/agent-generator/templates/core/workflow-review.js +0 -104
  166. package/dist/agent-generator/templates/core/workflow-review.js.map +0 -1
  167. package/dist/agent-generator/templates/domain/index.d.ts +0 -22
  168. package/dist/agent-generator/templates/domain/index.d.ts.map +0 -1
  169. package/dist/agent-generator/templates/domain/index.js +0 -1176
  170. package/dist/agent-generator/templates/domain/index.js.map +0 -1
  171. package/dist/agent-generator/templates/stack/index.d.ts +0 -8
  172. package/dist/agent-generator/templates/stack/index.d.ts.map +0 -1
  173. package/dist/agent-generator/templates/stack/index.js +0 -695
  174. package/dist/agent-generator/templates/stack/index.js.map +0 -1
  175. package/dist/agent-generator/templates/template-helpers.d.ts +0 -75
  176. package/dist/agent-generator/templates/template-helpers.d.ts.map +0 -1
  177. package/dist/agent-generator/templates/template-helpers.js +0 -726
  178. package/dist/agent-generator/templates/template-helpers.js.map +0 -1
  179. package/dist/agent-generator/types.d.ts +0 -196
  180. package/dist/agent-generator/types.d.ts.map +0 -1
  181. package/dist/agent-generator/types.js +0 -27
  182. package/dist/agent-generator/types.js.map +0 -1
  183. package/dist/analyzer.d.ts +0 -38
  184. package/dist/analyzer.d.ts.map +0 -1
  185. package/dist/analyzer.js +0 -383
  186. package/dist/analyzer.js.map +0 -1
  187. package/dist/analyzers/forecast.d.ts +0 -85
  188. package/dist/analyzers/forecast.d.ts.map +0 -1
  189. package/dist/analyzers/forecast.js +0 -337
  190. package/dist/analyzers/forecast.js.map +0 -1
  191. package/dist/analyzers/git-cache.d.ts +0 -7
  192. package/dist/analyzers/git-cache.d.ts.map +0 -1
  193. package/dist/analyzers/git-cache.js +0 -41
  194. package/dist/analyzers/git-cache.js.map +0 -1
  195. package/dist/analyzers/git-history.d.ts +0 -113
  196. package/dist/analyzers/git-history.d.ts.map +0 -1
  197. package/dist/analyzers/git-history.js +0 -333
  198. package/dist/analyzers/git-history.js.map +0 -1
  199. package/dist/analyzers/index.d.ts +0 -10
  200. package/dist/analyzers/index.d.ts.map +0 -1
  201. package/dist/analyzers/index.js +0 -7
  202. package/dist/analyzers/index.js.map +0 -1
  203. package/dist/analyzers/temporal-scorer.d.ts +0 -72
  204. package/dist/analyzers/temporal-scorer.d.ts.map +0 -1
  205. package/dist/analyzers/temporal-scorer.js +0 -140
  206. package/dist/analyzers/temporal-scorer.js.map +0 -1
  207. package/dist/anti-patterns.d.ts +0 -24
  208. package/dist/anti-patterns.d.ts.map +0 -1
  209. package/dist/anti-patterns.js +0 -230
  210. package/dist/anti-patterns.js.map +0 -1
  211. package/dist/cli.d.ts.map +0 -1
  212. package/dist/cli.js.map +0 -1
  213. package/dist/config.d.ts +0 -12
  214. package/dist/config.d.ts.map +0 -1
  215. package/dist/config.js +0 -110
  216. package/dist/config.js.map +0 -1
  217. package/dist/diagram.d.ts +0 -9
  218. package/dist/diagram.d.ts.map +0 -1
  219. package/dist/diagram.js +0 -116
  220. package/dist/diagram.js.map +0 -1
  221. package/dist/html-reporter.d.ts +0 -47
  222. package/dist/html-reporter.d.ts.map +0 -1
  223. package/dist/html-reporter.js +0 -1747
  224. package/dist/html-reporter.js.map +0 -1
  225. package/dist/index.d.ts.map +0 -1
  226. package/dist/index.js.map +0 -1
  227. package/dist/project-summarizer.d.ts +0 -38
  228. package/dist/project-summarizer.d.ts.map +0 -1
  229. package/dist/project-summarizer.js +0 -463
  230. package/dist/project-summarizer.js.map +0 -1
  231. package/dist/refactor-engine.d.ts +0 -18
  232. package/dist/refactor-engine.d.ts.map +0 -1
  233. package/dist/refactor-engine.js +0 -86
  234. package/dist/refactor-engine.js.map +0 -1
  235. package/dist/refactor-reporter.d.ts.map +0 -1
  236. package/dist/refactor-reporter.js.map +0 -1
  237. package/dist/reporter.d.ts.map +0 -1
  238. package/dist/reporter.js.map +0 -1
  239. package/dist/rules/barrel-optimizer.d.ts +0 -13
  240. package/dist/rules/barrel-optimizer.d.ts.map +0 -1
  241. package/dist/rules/barrel-optimizer.js +0 -77
  242. package/dist/rules/barrel-optimizer.js.map +0 -1
  243. package/dist/rules/dead-code-detector.d.ts +0 -21
  244. package/dist/rules/dead-code-detector.d.ts.map +0 -1
  245. package/dist/rules/dead-code-detector.js +0 -117
  246. package/dist/rules/dead-code-detector.js.map +0 -1
  247. package/dist/rules/hub-splitter.d.ts +0 -13
  248. package/dist/rules/hub-splitter.d.ts.map +0 -1
  249. package/dist/rules/hub-splitter.js +0 -110
  250. package/dist/rules/hub-splitter.js.map +0 -1
  251. package/dist/rules/import-organizer.d.ts +0 -13
  252. package/dist/rules/import-organizer.d.ts.map +0 -1
  253. package/dist/rules/import-organizer.js +0 -85
  254. package/dist/rules/import-organizer.js.map +0 -1
  255. package/dist/rules/module-grouper.d.ts +0 -13
  256. package/dist/rules/module-grouper.d.ts.map +0 -1
  257. package/dist/rules/module-grouper.js +0 -110
  258. package/dist/rules/module-grouper.js.map +0 -1
  259. package/dist/scanner.d.ts +0 -31
  260. package/dist/scanner.d.ts.map +0 -1
  261. package/dist/scanner.js +0 -328
  262. package/dist/scanner.js.map +0 -1
  263. package/dist/scorer.d.ts +0 -27
  264. package/dist/scorer.d.ts.map +0 -1
  265. package/dist/scorer.js +0 -229
  266. package/dist/scorer.js.map +0 -1
  267. package/dist/types.d.ts +0 -186
  268. package/dist/types.d.ts.map +0 -1
  269. package/dist/types.js +0 -2
  270. package/dist/types.js.map +0 -1
  271. package/examples/sample-report.md +0 -207
  272. package/jest.config.js +0 -18
  273. package/src/agent-generator/context-enricher.ts +0 -672
  274. package/src/agent-generator/domain-inferrer.ts +0 -635
  275. package/src/agent-generator/framework-detector.ts +0 -669
  276. package/src/agent-generator/index.ts +0 -634
  277. package/src/agent-generator/stack-detector.ts +0 -115
  278. package/src/agent-generator/templates/core/agents.ts +0 -1296
  279. package/src/agent-generator/templates/core/architecture-rules.ts +0 -287
  280. package/src/agent-generator/templates/core/general-rules.ts +0 -306
  281. package/src/agent-generator/templates/core/hooks-generator.ts +0 -242
  282. package/src/agent-generator/templates/core/index-md.ts +0 -260
  283. package/src/agent-generator/templates/core/orchestrator.ts +0 -459
  284. package/src/agent-generator/templates/core/preflight.ts +0 -215
  285. package/src/agent-generator/templates/core/quality-gates.ts +0 -256
  286. package/src/agent-generator/templates/core/security-rules.ts +0 -543
  287. package/src/agent-generator/templates/core/skills-generator.ts +0 -585
  288. package/src/agent-generator/templates/core/workflow-fix-bug.ts +0 -239
  289. package/src/agent-generator/templates/core/workflow-new-feature.ts +0 -323
  290. package/src/agent-generator/templates/core/workflow-review.ts +0 -106
  291. package/src/agent-generator/templates/domain/index.ts +0 -1201
  292. package/src/agent-generator/templates/stack/index.ts +0 -705
  293. package/src/agent-generator/templates/template-helpers.ts +0 -776
  294. package/src/agent-generator/types.ts +0 -232
  295. package/src/analyzer.ts +0 -447
  296. package/src/analyzers/forecast.ts +0 -496
  297. package/src/analyzers/git-cache.ts +0 -52
  298. package/src/analyzers/git-history.ts +0 -488
  299. package/src/analyzers/index.ts +0 -33
  300. package/src/analyzers/temporal-scorer.ts +0 -227
  301. package/src/anti-patterns.ts +0 -287
  302. package/src/cli.ts +0 -517
  303. package/src/config.ts +0 -123
  304. package/src/diagram.ts +0 -144
  305. package/src/html-reporter.ts +0 -1830
  306. package/src/project-summarizer.ts +0 -521
  307. package/src/refactor-engine.ts +0 -117
  308. package/src/rules/barrel-optimizer.ts +0 -97
  309. package/src/rules/dead-code-detector.ts +0 -132
  310. package/src/rules/hub-splitter.ts +0 -123
  311. package/src/rules/import-organizer.ts +0 -98
  312. package/src/rules/module-grouper.ts +0 -124
  313. package/src/scanner.ts +0 -344
  314. package/src/scorer.ts +0 -254
  315. package/src/types.ts +0 -193
  316. package/tests/agent-generator.test.ts +0 -427
  317. package/tests/analyzers-integration.test.ts +0 -174
  318. package/tests/anti-patterns.test.ts +0 -94
  319. package/tests/context-enricher.test.ts +0 -971
  320. package/tests/fixtures/monorepo/package.json +0 -6
  321. package/tests/fixtures/monorepo/packages/app/package.json +0 -12
  322. package/tests/fixtures/monorepo/packages/app/src/index.ts +0 -6
  323. package/tests/fixtures/monorepo/packages/core/package.json +0 -7
  324. package/tests/fixtures/monorepo/packages/core/src/index.ts +0 -7
  325. package/tests/forecast.test.ts +0 -509
  326. package/tests/framework-detector.test.ts +0 -1172
  327. package/tests/git-history.test.ts +0 -254
  328. package/tests/monorepo-scan.test.ts +0 -170
  329. package/tests/scanner.test.ts +0 -54
  330. package/tests/scorer.test.ts +0 -674
  331. package/tests/stack-detector.test.ts +0 -241
  332. package/tests/template-generation.test.ts +0 -706
  333. package/tests/template-helpers.test.ts +0 -1152
  334. package/tests/temporal-scorer.test.ts +0 -307
  335. /package/dist/{reporter.js → src/adapters/reporter.js} +0 -0
@@ -1,227 +0,0 @@
1
- /**
2
- * Temporal Score Dimension — Adds time-series awareness to architecture scoring
3
- *
4
- * Combines current static score with historical velocity to produce:
5
- * - Trend per module (improving / stable / degrading)
6
- * - Temporal risk score (static score penalized by negative velocity)
7
- * - Projected score in N weeks
8
- *
9
- * @author Camilo Girardelli — Girardelli Tecnologia
10
- * @license MIT
11
- */
12
-
13
- import type {
14
- ModuleHistory,
15
- VelocityVector,
16
- GitHistoryReport,
17
- } from './git-history.js';
18
-
19
- // ═══════════════════════════════════════════════════════════════
20
- // TYPES
21
- // ═══════════════════════════════════════════════════════════════
22
-
23
- export type Trend = 'improving' | 'stable' | 'degrading';
24
-
25
- export interface TemporalScore {
26
- /** Module or file path */
27
- module: string;
28
- /** Current static score (from ArchitectureScorer) */
29
- staticScore: number;
30
- /** Temporal-adjusted score (penalizes degrading trends) */
31
- temporalScore: number;
32
- /** Direction of change */
33
- trend: Trend;
34
- /** Projected score in projectionWeeks */
35
- projectedScore: number;
36
- /** Confidence in the projection (0-1) */
37
- projectionConfidence: number;
38
- /** Weeks used for projection */
39
- projectionWeeks: number;
40
- /** Risk level derived from temporal analysis */
41
- riskLevel: 'low' | 'medium' | 'high' | 'critical';
42
- /** Velocity data */
43
- velocity: VelocityVector;
44
- }
45
-
46
- export interface TemporalReport {
47
- projectPath: string;
48
- analyzedAt: string;
49
- overallTrend: Trend;
50
- overallTemporalScore: number;
51
- modules: TemporalScore[];
52
- degradingModules: TemporalScore[];
53
- improvingModules: TemporalScore[];
54
- }
55
-
56
- export interface TemporalScorerConfig {
57
- /** Weeks ahead to project (default: 12) */
58
- projectionWeeks?: number;
59
- /** Weight of churn trend in temporal penalty (0-1, default: 0.6) */
60
- churnWeight?: number;
61
- /** Weight of commit acceleration in temporal penalty (0-1, default: 0.4) */
62
- commitWeight?: number;
63
- /** Threshold for trend classification: accelerating if > threshold % */
64
- acceleratingThreshold?: number;
65
- /** Threshold for trend classification: decelerating if < -threshold % */
66
- deceleratingThreshold?: number;
67
- }
68
-
69
- const DEFAULT_CONFIG: Required<TemporalScorerConfig> = {
70
- projectionWeeks: 12,
71
- churnWeight: 0.6,
72
- commitWeight: 0.4,
73
- acceleratingThreshold: 15,
74
- deceleratingThreshold: -15,
75
- };
76
-
77
- // ═══════════════════════════════════════════════════════════════
78
- // TEMPORAL SCORER
79
- // ═══════════════════════════════════════════════════════════════
80
-
81
- export class TemporalScorer {
82
- private config: Required<TemporalScorerConfig>;
83
-
84
- constructor(config?: TemporalScorerConfig) {
85
- this.config = { ...DEFAULT_CONFIG, ...config };
86
- }
87
-
88
- /**
89
- * Score modules temporally using git history + static scores.
90
- *
91
- * @param gitReport - Output from GitHistoryAnalyzer
92
- * @param staticScores - Map of modulePath → static score (0-100)
93
- */
94
- score(
95
- gitReport: GitHistoryReport,
96
- staticScores: Map<string, number>,
97
- ): TemporalReport {
98
- const modules: TemporalScore[] = [];
99
-
100
- for (const moduleHistory of gitReport.modules) {
101
- const staticScore = staticScores.get(moduleHistory.modulePath)
102
- ?? this.inferStaticScore(moduleHistory);
103
-
104
- const ts = this.scoreModule(moduleHistory, staticScore);
105
- modules.push(ts);
106
- }
107
-
108
- // Sort by risk (worst first)
109
- modules.sort((a, b) => a.temporalScore - b.temporalScore);
110
-
111
- const degrading = modules.filter(m => m.trend === 'degrading');
112
- const improving = modules.filter(m => m.trend === 'improving');
113
-
114
- const overallTrend = this.classifyOverallTrend(modules);
115
- const overallScore = modules.length > 0
116
- ? Math.round(modules.reduce((s, m) => s + m.temporalScore, 0) / modules.length)
117
- : 0;
118
-
119
- return {
120
- projectPath: gitReport.projectPath,
121
- analyzedAt: new Date().toISOString(),
122
- overallTrend: overallTrend,
123
- overallTemporalScore: overallScore,
124
- modules,
125
- degradingModules: degrading,
126
- improvingModules: improving,
127
- };
128
- }
129
-
130
- private scoreModule(module: ModuleHistory, staticScore: number): TemporalScore {
131
- const velocity = module.velocityVector;
132
-
133
- // Calculate temporal penalty based on velocity
134
- const churnPenalty = velocity.churnTrend > 0
135
- ? velocity.churnTrend * this.config.churnWeight * 0.3 // 30% impact per 100% churn increase
136
- : velocity.churnTrend * this.config.churnWeight * 0.1; // 10% bonus per 100% churn decrease
137
-
138
- const commitPenalty = velocity.commitAcceleration > 20
139
- ? (velocity.commitAcceleration - 20) * this.config.commitWeight * 0.2 // penalty for excessive churn
140
- : 0;
141
-
142
- const totalPenalty = Math.max(-20, Math.min(30, churnPenalty + commitPenalty));
143
- const temporalScore = Math.max(0, Math.min(100, Math.round(staticScore - totalPenalty)));
144
-
145
- // Trend classification
146
- const trend = this.classifyTrend(velocity);
147
-
148
- // Linear projection
149
- const weeklyDelta = totalPenalty / Math.max(this.config.projectionWeeks, 1);
150
- const projectedScore = Math.max(0, Math.min(100,
151
- Math.round(temporalScore - (weeklyDelta * this.config.projectionWeeks))
152
- ));
153
-
154
- // Confidence decreases with projection distance and instability
155
- const instability = Math.abs(velocity.churnTrend) + Math.abs(velocity.commitAcceleration);
156
- const projectionConfidence = Math.max(0.1, Math.min(1,
157
- 1 - (instability / 200) - (this.config.projectionWeeks / 52)
158
- ));
159
-
160
- const riskLevel = this.classifyRisk(temporalScore, trend, module.busFactor);
161
-
162
- return {
163
- module: module.modulePath,
164
- staticScore,
165
- temporalScore,
166
- trend,
167
- projectedScore,
168
- projectionConfidence: Math.round(projectionConfidence * 100) / 100,
169
- projectionWeeks: this.config.projectionWeeks,
170
- riskLevel,
171
- velocity,
172
- };
173
- }
174
-
175
- private classifyTrend(velocity: VelocityVector): Trend {
176
- // Degrading: churn increasing significantly or commit acceleration very high
177
- if (velocity.churnTrend > 30 || velocity.commitAcceleration > 50) {
178
- return 'degrading';
179
- }
180
- // Improving: churn decreasing and stable or decelerating
181
- if (velocity.churnTrend < -10 && velocity.direction !== 'accelerating') {
182
- return 'improving';
183
- }
184
- return 'stable';
185
- }
186
-
187
- private classifyRisk(
188
- temporalScore: number,
189
- trend: Trend,
190
- busFactor: number,
191
- ): TemporalScore['riskLevel'] {
192
- if (temporalScore < 30 || (temporalScore < 50 && trend === 'degrading')) {
193
- return 'critical';
194
- }
195
- if (temporalScore < 50 || (trend === 'degrading' && busFactor <= 1)) {
196
- return 'high';
197
- }
198
- if (temporalScore < 70 || trend === 'degrading') {
199
- return 'medium';
200
- }
201
- return 'low';
202
- }
203
-
204
- private classifyOverallTrend(modules: TemporalScore[]): Trend {
205
- if (modules.length === 0) return 'stable';
206
-
207
- const degrading = modules.filter(m => m.trend === 'degrading').length;
208
- const improving = modules.filter(m => m.trend === 'improving').length;
209
-
210
- const degradingRatio = degrading / modules.length;
211
- const improvingRatio = improving / modules.length;
212
-
213
- if (degradingRatio > 0.3) return 'degrading';
214
- if (improvingRatio > 0.3) return 'improving';
215
- return 'stable';
216
- }
217
-
218
- /** Infer a static score when none is provided (based on churn metrics) */
219
- private inferStaticScore(module: ModuleHistory): number {
220
- const avgChurn = module.aggregateChurn / Math.max(module.aggregateCommits, 1);
221
- if (avgChurn < 20) return 85;
222
- if (avgChurn < 50) return 75;
223
- if (avgChurn < 100) return 65;
224
- if (avgChurn < 200) return 50;
225
- return 35;
226
- }
227
- }
@@ -1,287 +0,0 @@
1
- import { readFileSync } from 'fs';
2
- import { AntiPattern, FileNode, ArchitectConfig } from './types.js';
3
-
4
- export class AntiPatternDetector {
5
- private config: ArchitectConfig;
6
- private dependencyGraph: Map<string, Set<string>>;
7
-
8
- /** Paths that indicate third-party or build artifacts — never report anti-patterns here */
9
- private static readonly EXCLUDED_PATH_SEGMENTS = [
10
- 'node_modules', '/dist/', '/build/', '/coverage/',
11
- '/.next/', '/venv/', '/__pycache__/', '/target/',
12
- ];
13
-
14
- constructor(config: ArchitectConfig) {
15
- this.config = config;
16
- this.dependencyGraph = new Map();
17
- }
18
-
19
- /**
20
- * Check if a file path belongs to the project's own source code.
21
- * Returns false for node_modules, dist, build artifacts, etc.
22
- */
23
- private isProjectFile(filePath: string): boolean {
24
- const normalized = filePath.replace(/\\/g, '/');
25
- return !AntiPatternDetector.EXCLUDED_PATH_SEGMENTS.some(seg =>
26
- normalized.includes(seg)
27
- );
28
- }
29
-
30
- detect(
31
- fileTree: FileNode,
32
- dependencies: Map<string, Set<string>>
33
- ): AntiPattern[] {
34
- this.dependencyGraph = dependencies;
35
- const patterns: AntiPattern[] = [];
36
-
37
- patterns.push(...this.detectGodClasses(fileTree));
38
- patterns.push(...this.detectCircularDependencies());
39
- patterns.push(...this.detectLeakyAbstractions(fileTree));
40
- patterns.push(...this.detectFeatureEnvy(fileTree, dependencies));
41
- patterns.push(...this.detectShotgunSurgery(dependencies));
42
-
43
- return patterns.sort((a, b) => {
44
- const severityOrder: Record<string, number> = {
45
- CRITICAL: 0,
46
- HIGH: 1,
47
- MEDIUM: 2,
48
- LOW: 3,
49
- };
50
- return severityOrder[a.severity] - severityOrder[b.severity];
51
- });
52
- }
53
-
54
- private detectGodClasses(node: FileNode): AntiPattern[] {
55
- const patterns: AntiPattern[] = [];
56
- const threshold =
57
- this.config.antiPatterns?.godClass?.linesThreshold || 500;
58
- const methodThreshold =
59
- this.config.antiPatterns?.godClass?.methodsThreshold || 10;
60
-
61
- this.walkFileTree(node, (file) => {
62
- if (file.type === 'file' && (file.lines || 0) > threshold && this.isProjectFile(file.path)) {
63
- const methods = this.countMethods(file.path);
64
- if (methods > methodThreshold) {
65
- patterns.push({
66
- name: 'God Class',
67
- severity: 'CRITICAL',
68
- location: file.path,
69
- description: `Class with ${file.lines} lines and ${methods} methods violates single responsibility principle`,
70
- suggestion:
71
- 'Consider splitting into smaller, focused classes with specific responsibilities',
72
- metrics: {
73
- lines: file.lines || 0,
74
- methods,
75
- },
76
- });
77
- }
78
- }
79
- });
80
-
81
- return patterns;
82
- }
83
-
84
- private detectCircularDependencies(): AntiPattern[] {
85
- const patterns: AntiPattern[] = [];
86
- const visited = new Set<string>();
87
- const recursionStack = new Set<string>();
88
-
89
- for (const file of this.dependencyGraph.keys()) {
90
- // Only check cycles starting from project files
91
- if (!this.isProjectFile(file)) continue;
92
-
93
- if (!visited.has(file)) {
94
- const cycle = this.findCycle(file, visited, recursionStack);
95
- if (cycle && cycle.every(f => this.isProjectFile(f))) {
96
- patterns.push({
97
- name: 'Circular Dependency',
98
- severity: 'HIGH',
99
- location: cycle.join(' -> '),
100
- description: `Circular dependency detected: ${cycle.join(' -> ')}`,
101
- suggestion:
102
- 'Refactor code to break the circular dependency using dependency injection or intermediate abstractions',
103
- affectedFiles: cycle,
104
- });
105
- }
106
- }
107
- }
108
-
109
- return patterns;
110
- }
111
-
112
- private findCycle(
113
- node: string,
114
- visited: Set<string>,
115
- recursionStack: Set<string>
116
- ): string[] | null {
117
- visited.add(node);
118
- recursionStack.add(node);
119
-
120
- const neighbors = this.dependencyGraph.get(node) || new Set();
121
- for (const neighbor of neighbors) {
122
- if (!visited.has(neighbor)) {
123
- const cycle = this.findCycle(neighbor, visited, recursionStack);
124
- if (cycle) {
125
- cycle.unshift(node);
126
- return cycle;
127
- }
128
- } else if (recursionStack.has(neighbor)) {
129
- return [node, neighbor];
130
- }
131
- }
132
-
133
- recursionStack.delete(node);
134
- return null;
135
- }
136
-
137
- private detectLeakyAbstractions(node: FileNode): AntiPattern[] {
138
- const patterns: AntiPattern[] = [];
139
-
140
- this.walkFileTree(node, (file) => {
141
- if (file.type === 'file' && this.isProjectFile(file.path)) {
142
- const internalExports = this.countInternalExports(file.path);
143
- if (internalExports > 5) {
144
- patterns.push({
145
- name: 'Leaky Abstraction',
146
- severity: 'MEDIUM',
147
- location: file.path,
148
- description: `Exports ${internalExports} internal types that should be private`,
149
- suggestion:
150
- 'Use private/internal access modifiers and facade patterns to hide implementation details',
151
- metrics: {
152
- exportedInternalTypes: internalExports,
153
- },
154
- });
155
- }
156
- }
157
- });
158
-
159
- return patterns;
160
- }
161
-
162
- private detectFeatureEnvy(
163
- node: FileNode,
164
- dependencies: Map<string, Set<string>>
165
- ): AntiPattern[] {
166
- const patterns: AntiPattern[] = [];
167
-
168
- this.walkFileTree(node, (file) => {
169
- if (file.type === 'file' && this.isProjectFile(file.path)) {
170
- const externalMethodCalls = (dependencies.get(file.path) || new Set())
171
- .size;
172
- const internalMethods = this.countMethods(file.path);
173
- const name = file.name.toLowerCase();
174
-
175
- // Skip infrastructure files where external deps are by design
176
- const isInfraFile =
177
- name.endsWith('.module.ts') ||
178
- name.endsWith('.dto.ts') ||
179
- name.endsWith('.entity.ts') ||
180
- name.endsWith('.guard.ts') ||
181
- name.endsWith('.pipe.ts') ||
182
- name.endsWith('.interceptor.ts') ||
183
- name.endsWith('.filter.ts') ||
184
- name.endsWith('.decorator.ts') ||
185
- name.endsWith('.spec.ts') ||
186
- name.endsWith('.test.ts');
187
-
188
- if (!isInfraFile && internalMethods > 0 && externalMethodCalls > internalMethods * 3) {
189
- patterns.push({
190
- name: 'Feature Envy',
191
- severity: 'MEDIUM',
192
- location: file.path,
193
- description: `Uses more external methods (${externalMethodCalls}) than internal methods (${internalMethods})`,
194
- suggestion:
195
- 'Move functionality closer to where it is used or extract to shared utility',
196
- metrics: {
197
- externalMethodCalls,
198
- internalMethods,
199
- },
200
- });
201
- }
202
- }
203
- });
204
-
205
- return patterns;
206
- }
207
-
208
- private detectShotgunSurgery(
209
- dependencies: Map<string, Set<string>>
210
- ): AntiPattern[] {
211
- const patterns: AntiPattern[] = [];
212
- const threshold =
213
- this.config.antiPatterns?.shotgunSurgery
214
- ?.changePropagationThreshold || 8;
215
-
216
- for (const [file, dependents] of dependencies) {
217
- // Only report for project files
218
- if (!this.isProjectFile(file)) continue;
219
-
220
- if (dependents.size >= threshold) {
221
- patterns.push({
222
- name: 'Shotgun Surgery',
223
- severity: 'HIGH',
224
- location: file,
225
- description: `Changes to this file likely require modifications in ${dependents.size} other files`,
226
- suggestion:
227
- 'Refactor to reduce coupling and consolidate related functionality into modules',
228
- affectedFiles: Array.from(dependents).filter(f => this.isProjectFile(f)),
229
- metrics: {
230
- dependentFileCount: dependents.size,
231
- },
232
- });
233
- }
234
- }
235
-
236
- return patterns;
237
- }
238
-
239
- private countMethods(filePath: string): number {
240
- try {
241
- const content = readFileSync(filePath, 'utf-8');
242
- const methodRegex = /(?:async\s+)?(?:function|public|private|protected|static)\s+\w+\s*\(/g;
243
- const arrowMethodRegex = /(?:readonly\s+)?\w+\s*=\s*(?:async\s+)?\(/g;
244
- const matches = content.match(methodRegex);
245
- const arrowMatches = content.match(arrowMethodRegex);
246
- return (matches ? matches.length : 0) + (arrowMatches ? arrowMatches.length : 0);
247
- } catch {
248
- return 0;
249
- }
250
- }
251
-
252
- private countInternalExports(filePath: string): number {
253
- try {
254
- const content = readFileSync(filePath, 'utf-8');
255
- const internalTypes = [
256
- '_',
257
- 'Internal',
258
- 'Private',
259
- 'Impl',
260
- 'Detail',
261
- ];
262
- let count = 0;
263
-
264
- for (const type of internalTypes) {
265
- const regex = new RegExp(`export\\s+\\w*${type}\\w*`, 'g');
266
- const matches = content.match(regex);
267
- count += matches ? matches.length : 0;
268
- }
269
-
270
- return count;
271
- } catch {
272
- return 0;
273
- }
274
- }
275
-
276
- private walkFileTree(
277
- node: FileNode,
278
- callback: (node: FileNode) => void
279
- ): void {
280
- callback(node);
281
- if (node.children) {
282
- for (const child of node.children) {
283
- this.walkFileTree(child, callback);
284
- }
285
- }
286
- }
287
- }