@vibgrate/cli 2026.814.2 → 2026.817.2

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 (157) hide show
  1. package/DOCS.md +61 -0
  2. package/README.md +1 -0
  3. package/dist/agent-UQC7QN77.js +27 -0
  4. package/dist/{agent-5ANHRYEI.js.map → agent-UQC7QN77.js.map} +1 -1
  5. package/dist/{approvals-T2KXPJLV.js → approvals-ASPJQUZK.js} +6 -5
  6. package/dist/{approvals-T2KXPJLV.js.map → approvals-ASPJQUZK.js.map} +1 -1
  7. package/dist/baseline-FIV6PR2M.js +9 -0
  8. package/dist/{baseline-WVD6P5IO.js.map → baseline-FIV6PR2M.js.map} +1 -1
  9. package/dist/{chunk-FOW5IF73.js → chunk-2FEB5KJS.js} +11 -34
  10. package/dist/chunk-2FEB5KJS.js.map +1 -0
  11. package/dist/{chunk-WQLZSVNF.js → chunk-3FMRFECC.js} +7 -6
  12. package/dist/chunk-3FMRFECC.js.map +1 -0
  13. package/dist/{chunk-7QDHQLUS.js → chunk-3H3SVJUY.js} +13 -11
  14. package/dist/chunk-3H3SVJUY.js.map +1 -0
  15. package/dist/{chunk-REIGWTTH.js → chunk-3HNPVXUK.js} +3 -3
  16. package/dist/{chunk-REIGWTTH.js.map → chunk-3HNPVXUK.js.map} +1 -1
  17. package/dist/{chunk-YQNTIBKS.js → chunk-3NJUOIZQ.js} +6 -6
  18. package/dist/{chunk-YQNTIBKS.js.map → chunk-3NJUOIZQ.js.map} +1 -1
  19. package/dist/{chunk-BH54SLGZ.js → chunk-5OL2TSHK.js} +4 -4
  20. package/dist/{chunk-BH54SLGZ.js.map → chunk-5OL2TSHK.js.map} +1 -1
  21. package/dist/{chunk-TFAXW7VM.js → chunk-6K3XK7C5.js} +69 -976
  22. package/dist/chunk-6K3XK7C5.js.map +1 -0
  23. package/dist/{chunk-N3XFY3PX.js → chunk-74UBGF4P.js} +3 -3
  24. package/dist/{chunk-N3XFY3PX.js.map → chunk-74UBGF4P.js.map} +1 -1
  25. package/dist/{chunk-X76VPOYH.js → chunk-AXZZ5CCG.js} +4 -4
  26. package/dist/{chunk-X76VPOYH.js.map → chunk-AXZZ5CCG.js.map} +1 -1
  27. package/dist/{chunk-5GLQNMTI.js → chunk-C3LMWZKF.js} +6 -6
  28. package/dist/{chunk-5GLQNMTI.js.map → chunk-C3LMWZKF.js.map} +1 -1
  29. package/dist/{chunk-WWGLVF7D.js → chunk-DVW3SVCW.js} +9 -8
  30. package/dist/chunk-DVW3SVCW.js.map +1 -0
  31. package/dist/{chunk-TNROG5CO.js → chunk-E2FAQREZ.js} +1739 -116
  32. package/dist/chunk-E2FAQREZ.js.map +1 -0
  33. package/dist/{chunk-7NMXE6KG.js → chunk-EXV4QSAD.js} +4 -4
  34. package/dist/{chunk-7NMXE6KG.js.map → chunk-EXV4QSAD.js.map} +1 -1
  35. package/dist/{chunk-3LSG7Z4I.js → chunk-EZ7UC5Y5.js} +25 -4
  36. package/dist/chunk-EZ7UC5Y5.js.map +1 -0
  37. package/dist/{chunk-OWSFZQOP.js → chunk-FJG5AXKZ.js} +3 -3
  38. package/dist/{chunk-OWSFZQOP.js.map → chunk-FJG5AXKZ.js.map} +1 -1
  39. package/dist/{chunk-NKFXXP6W.js → chunk-GOGMS3ST.js} +8 -6
  40. package/dist/chunk-GOGMS3ST.js.map +1 -0
  41. package/dist/{chunk-WHJMS7XC.js → chunk-I5LP55B6.js} +3 -3
  42. package/dist/{chunk-WHJMS7XC.js.map → chunk-I5LP55B6.js.map} +1 -1
  43. package/dist/{chunk-IHXNOY3R.js → chunk-K6DXETMC.js} +12 -12
  44. package/dist/{chunk-IHXNOY3R.js.map → chunk-K6DXETMC.js.map} +1 -1
  45. package/dist/{chunk-DSUGC7F5.js → chunk-KJT2R6WW.js} +4 -4
  46. package/dist/{chunk-DSUGC7F5.js.map → chunk-KJT2R6WW.js.map} +1 -1
  47. package/dist/chunk-KNGAZDGF.js +467 -0
  48. package/dist/chunk-KNGAZDGF.js.map +1 -0
  49. package/dist/{chunk-JCN6MSXQ.js → chunk-LHKQGVRF.js} +17 -29
  50. package/dist/chunk-LHKQGVRF.js.map +1 -0
  51. package/dist/{chunk-YNV5M3JW.js → chunk-M7IO3DXH.js} +9 -8
  52. package/dist/chunk-M7IO3DXH.js.map +1 -0
  53. package/dist/chunk-MS6V5XKB.js +33 -0
  54. package/dist/chunk-MS6V5XKB.js.map +1 -0
  55. package/dist/{chunk-2U37PFB2.js → chunk-MVPRPSXU.js} +7 -4
  56. package/dist/chunk-MVPRPSXU.js.map +1 -0
  57. package/dist/{chunk-DT4KIVRI.js → chunk-NG4KIJW6.js} +34 -2
  58. package/dist/chunk-NG4KIJW6.js.map +1 -0
  59. package/dist/{chunk-IHLLWBZU.js → chunk-O2DL2Q55.js} +6 -6
  60. package/dist/{chunk-IHLLWBZU.js.map → chunk-O2DL2Q55.js.map} +1 -1
  61. package/dist/chunk-O3LABX6I.js +43 -0
  62. package/dist/chunk-O3LABX6I.js.map +1 -0
  63. package/dist/chunk-OZ3IFXRD.js +22 -0
  64. package/dist/chunk-OZ3IFXRD.js.map +1 -0
  65. package/dist/chunk-PRG2ULPK.js +6 -0
  66. package/dist/{chunk-2H2U3DC7.js.map → chunk-PRG2ULPK.js.map} +1 -1
  67. package/dist/{chunk-TVDYEHIM.js → chunk-Q3M6K3HY.js} +3 -3
  68. package/dist/{chunk-TVDYEHIM.js.map → chunk-Q3M6K3HY.js.map} +1 -1
  69. package/dist/{chunk-KGPX4EUN.js → chunk-Q4G2BWE3.js} +4 -4
  70. package/dist/{chunk-KGPX4EUN.js.map → chunk-Q4G2BWE3.js.map} +1 -1
  71. package/dist/chunk-T7RSQ5WD.js +227 -0
  72. package/dist/chunk-T7RSQ5WD.js.map +1 -0
  73. package/dist/{chunk-54RGT2T5.js → chunk-TVDMNIUT.js} +3 -3
  74. package/dist/{chunk-54RGT2T5.js.map → chunk-TVDMNIUT.js.map} +1 -1
  75. package/dist/{chunk-N6ZMZ5AI.js → chunk-WAKP7SK7.js} +4922 -1011
  76. package/dist/chunk-WAKP7SK7.js.map +1 -0
  77. package/dist/{chunk-75LJM5XD.js → chunk-WVMOGIPC.js} +9 -43
  78. package/dist/chunk-WVMOGIPC.js.map +1 -0
  79. package/dist/{chunk-UTNNGKKX.js → chunk-XLXJC7H3.js} +142 -14
  80. package/dist/chunk-XLXJC7H3.js.map +1 -0
  81. package/dist/cli.js +1727 -1127
  82. package/dist/cli.js.map +1 -1
  83. package/dist/daemon-FPTRHO5N.js +26 -0
  84. package/dist/daemon-FPTRHO5N.js.map +1 -0
  85. package/dist/embed-worker-main.js +5 -4
  86. package/dist/embed-worker-main.js.map +1 -1
  87. package/dist/ensure-map-342G2IV3.js +33 -0
  88. package/dist/{ensure-map-HQ7A5NDL.js.map → ensure-map-342G2IV3.js.map} +1 -1
  89. package/dist/{fs-NTQUFCXV.js → fs-TLPOWC2D.js} +3 -3
  90. package/dist/fs-TLPOWC2D.js.map +1 -0
  91. package/dist/graph-backend-RNWQBT3P.js +15 -0
  92. package/dist/{graph-backend-W2TNTMY7.js.map → graph-backend-RNWQBT3P.js.map} +1 -1
  93. package/dist/index.d.ts +28 -6
  94. package/dist/index.js +21 -18
  95. package/dist/index.js.map +1 -1
  96. package/dist/{interactive-EW2VJ3BZ.js → interactive-SR7TMF6M.js} +36 -33
  97. package/dist/interactive-SR7TMF6M.js.map +1 -0
  98. package/dist/load-AYFECIQB.js +11 -0
  99. package/dist/{load-64RK5O6C.js.map → load-AYFECIQB.js.map} +1 -1
  100. package/dist/local-runtime-6SNWKSA7.js +6 -0
  101. package/dist/{local-runtime-2ED33KK6.js.map → local-runtime-6SNWKSA7.js.map} +1 -1
  102. package/dist/model-manager-SXHZ5VD4.js +10 -0
  103. package/dist/{model-manager-GJ2YSTSK.js.map → model-manager-SXHZ5VD4.js.map} +1 -1
  104. package/dist/parse-worker.d.ts +1 -1
  105. package/dist/parse-worker.js +5 -2
  106. package/dist/parse-worker.js.map +1 -1
  107. package/dist/{run-outcome-6QNQIHPV.js → run-outcome-YQQJG3LW.js} +7 -6
  108. package/dist/run-outcome-YQQJG3LW.js.map +1 -0
  109. package/dist/runtime-session-CNJ4DAV5.js +22 -0
  110. package/dist/{runtime-session-RJHH3KMF.js.map → runtime-session-CNJ4DAV5.js.map} +1 -1
  111. package/dist/session-H34HUV2Y.js +17 -0
  112. package/dist/{session-4BGYASOH.js.map → session-H34HUV2Y.js.map} +1 -1
  113. package/dist/{stream-json-GY5N7WZT.js → stream-json-55YDNAFX.js} +18 -17
  114. package/dist/stream-json-55YDNAFX.js.map +1 -0
  115. package/dist/{types-DLH-Ritr.d.ts → types-DHqH0XIE.d.ts} +68 -6
  116. package/dist/version-WSE3QOPK.js +4 -0
  117. package/dist/{version-DPAMQW6M.js.map → version-WSE3QOPK.js.map} +1 -1
  118. package/dist/{vg-mcp-bridge-IGHJKKSL.js → vg-mcp-bridge-2CNLHNEL.js} +13 -12
  119. package/dist/vg-mcp-bridge-2CNLHNEL.js.map +1 -0
  120. package/dist/{vgd-ORPA5C2K.js → vgd-URUZQORN.js} +10 -9
  121. package/dist/vgd-URUZQORN.js.map +1 -0
  122. package/grammars/tree-sitter-hcl.wasm +0 -0
  123. package/package.json +9 -8
  124. package/dist/agent-5ANHRYEI.js +0 -26
  125. package/dist/baseline-WVD6P5IO.js +0 -9
  126. package/dist/chunk-2H2U3DC7.js +0 -6
  127. package/dist/chunk-2U37PFB2.js.map +0 -1
  128. package/dist/chunk-3LSG7Z4I.js.map +0 -1
  129. package/dist/chunk-75LJM5XD.js.map +0 -1
  130. package/dist/chunk-7QDHQLUS.js.map +0 -1
  131. package/dist/chunk-DT4KIVRI.js.map +0 -1
  132. package/dist/chunk-FOW5IF73.js.map +0 -1
  133. package/dist/chunk-JCN6MSXQ.js.map +0 -1
  134. package/dist/chunk-N6ZMZ5AI.js.map +0 -1
  135. package/dist/chunk-NKFXXP6W.js.map +0 -1
  136. package/dist/chunk-RXP66R2E.js +0 -39
  137. package/dist/chunk-RXP66R2E.js.map +0 -1
  138. package/dist/chunk-TFAXW7VM.js.map +0 -1
  139. package/dist/chunk-TNROG5CO.js.map +0 -1
  140. package/dist/chunk-UTNNGKKX.js.map +0 -1
  141. package/dist/chunk-WQLZSVNF.js.map +0 -1
  142. package/dist/chunk-WWGLVF7D.js.map +0 -1
  143. package/dist/chunk-YNV5M3JW.js.map +0 -1
  144. package/dist/ensure-map-HQ7A5NDL.js +0 -30
  145. package/dist/fs-NTQUFCXV.js.map +0 -1
  146. package/dist/graph-backend-W2TNTMY7.js +0 -14
  147. package/dist/interactive-EW2VJ3BZ.js.map +0 -1
  148. package/dist/load-64RK5O6C.js +0 -10
  149. package/dist/local-runtime-2ED33KK6.js +0 -6
  150. package/dist/model-manager-GJ2YSTSK.js +0 -10
  151. package/dist/run-outcome-6QNQIHPV.js.map +0 -1
  152. package/dist/runtime-session-RJHH3KMF.js +0 -21
  153. package/dist/session-4BGYASOH.js +0 -16
  154. package/dist/stream-json-GY5N7WZT.js.map +0 -1
  155. package/dist/version-DPAMQW6M.js +0 -4
  156. package/dist/vg-mcp-bridge-IGHJKKSL.js.map +0 -1
  157. package/dist/vgd-ORPA5C2K.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { runCoreScan, compactUiPurpose } from './chunk-N6ZMZ5AI.js';
2
- import { findPackageJsonFiles, readJsonFile, findFiles, readTextFile, pathExists, isSkippedDirName } from './chunk-DT4KIVRI.js';
1
+ import { runCoreScan, compactUiPurpose, scanArchitectureBundle, mermaidFromArchitecture, aggregateSolutionArchitecture } from './chunk-WAKP7SK7.js';
2
+ import { findPackageJsonFiles, readJsonFile, findFiles, readTextFile, pathExists } from './chunk-NG4KIJW6.js';
3
3
  import { writeJsonFile } from './chunk-CRAMOEBE.js';
4
4
  import * as path3 from 'path';
5
5
  import { Command } from 'commander';
@@ -1963,961 +1963,6 @@ function scanServiceDependencies(projects) {
1963
1963
  }
1964
1964
  return result;
1965
1965
  }
1966
- var ARCHETYPE_SIGNALS = [
1967
- // Meta-frameworks (highest priority — they imply routing patterns)
1968
- { packages: ["next", "@next/core"], archetype: "nextjs", weight: 10 },
1969
- { packages: ["@remix-run/react", "@remix-run/node", "@remix-run/dev"], archetype: "remix", weight: 10 },
1970
- { packages: ["@sveltejs/kit"], archetype: "sveltekit", weight: 10 },
1971
- { packages: ["nuxt"], archetype: "nuxt", weight: 10 },
1972
- // Backend frameworks
1973
- { packages: ["@nestjs/core", "@nestjs/common"], archetype: "nestjs", weight: 9 },
1974
- { packages: ["fastify"], archetype: "fastify", weight: 8 },
1975
- { packages: ["hono"], archetype: "hono", weight: 8 },
1976
- { packages: ["koa"], archetype: "koa", weight: 8 },
1977
- { packages: ["express"], archetype: "express", weight: 7 },
1978
- // Serverless
1979
- { packages: ["serverless", "aws-lambda", "@aws-sdk/client-lambda", "middy", "@cloudflare/workers-types"], archetype: "serverless", weight: 6 },
1980
- // CLI
1981
- { packages: ["commander", "yargs", "meow", "cac", "clipanion", "oclif"], archetype: "cli", weight: 5 }
1982
- ];
1983
- function detectArchetype(projects) {
1984
- const allPackages = /* @__PURE__ */ new Set();
1985
- for (const p of projects) {
1986
- for (const d of p.dependencies) {
1987
- allPackages.add(d.package);
1988
- }
1989
- }
1990
- if (projects.length > 2) {
1991
- return { archetype: "monorepo", confidence: 0.8 };
1992
- }
1993
- let bestArchetype = "unknown";
1994
- let bestScore = 0;
1995
- for (const signal of ARCHETYPE_SIGNALS) {
1996
- const matched = signal.packages.filter((p) => allPackages.has(p)).length;
1997
- if (matched > 0) {
1998
- const score = matched * signal.weight;
1999
- if (score > bestScore) {
2000
- bestScore = score;
2001
- bestArchetype = signal.archetype;
2002
- }
2003
- }
2004
- }
2005
- if (bestArchetype === "unknown") {
2006
- bestArchetype = "library";
2007
- bestScore = 3;
2008
- }
2009
- const confidence = Math.min(bestScore / 15, 1);
2010
- return { archetype: bestArchetype, confidence: Math.round(confidence * 100) / 100 };
2011
- }
2012
- var PATH_RULES = [
2013
- // ── Testing (high precision) ──
2014
- { pattern: /\/__tests__\//, layer: "testing", confidence: 0.95, signal: "__tests__ directory" },
2015
- { pattern: /\.test\.[jt]sx?$/, layer: "testing", confidence: 0.95, signal: ".test.* file" },
2016
- { pattern: /\.spec\.[jt]sx?$/, layer: "testing", confidence: 0.95, signal: ".spec.* file" },
2017
- { pattern: /\/test\//, layer: "testing", confidence: 0.85, signal: "test/ directory" },
2018
- { pattern: /\/tests\//, layer: "testing", confidence: 0.85, signal: "tests/ directory" },
2019
- { pattern: /\/__mocks__\//, layer: "testing", confidence: 0.9, signal: "__mocks__ directory" },
2020
- { pattern: /\/fixtures\//, layer: "testing", confidence: 0.8, signal: "fixtures/ directory" },
2021
- // ── Config/Infrastructure (high precision) ──
2022
- { pattern: /\/config\.[jt]sx?$/, layer: "config", confidence: 0.85, signal: "config.* file" },
2023
- { pattern: /\/config\//, layer: "config", confidence: 0.8, signal: "config/ directory" },
2024
- { pattern: /\.config\.[jt]sx?$/, layer: "config", confidence: 0.9, signal: ".config.* file" },
2025
- { pattern: /\/env\.[jt]sx?$/, layer: "config", confidence: 0.85, signal: "env.* file" },
2026
- { pattern: /\/bootstrap\.[jt]sx?$/, layer: "config", confidence: 0.85, signal: "bootstrap file" },
2027
- { pattern: /\/setup\.[jt]sx?$/, layer: "config", confidence: 0.8, signal: "setup file" },
2028
- // ── Next.js (archetype-specific) ──
2029
- { pattern: /(^|\/)app\/.*\/route\.[jt]sx?$/, layer: "routing", confidence: 0.95, signal: "Next.js App Router route", archetypes: ["nextjs"] },
2030
- { pattern: /(^|\/)pages\/api\//, layer: "routing", confidence: 0.95, signal: "Next.js Pages API route", archetypes: ["nextjs"] },
2031
- { pattern: /(^|\/)app\/.*page\.[jt]sx?$/, layer: "presentation", confidence: 0.9, signal: "Next.js page component", archetypes: ["nextjs"] },
2032
- { pattern: /(^|\/)app\/.*layout\.[jt]sx?$/, layer: "presentation", confidence: 0.9, signal: "Next.js layout component", archetypes: ["nextjs"] },
2033
- { pattern: /(^|\/)app\/.*loading\.[jt]sx?$/, layer: "presentation", confidence: 0.85, signal: "Next.js loading component", archetypes: ["nextjs"] },
2034
- { pattern: /(^|\/)app\/.*error\.[jt]sx?$/, layer: "presentation", confidence: 0.85, signal: "Next.js error component", archetypes: ["nextjs"] },
2035
- { pattern: /(^|\/)middleware\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "Next.js middleware", archetypes: ["nextjs"] },
2036
- // ── Remix (archetype-specific) ──
2037
- { pattern: /\/app\/routes\//, layer: "routing", confidence: 0.95, signal: "Remix route file", archetypes: ["remix"] },
2038
- { pattern: /\/app\/root\.[jt]sx?$/, layer: "presentation", confidence: 0.9, signal: "Remix root", archetypes: ["remix"] },
2039
- // ── SvelteKit (archetype-specific) ──
2040
- { pattern: /\/src\/routes\/.*\+server\.[jt]s$/, layer: "routing", confidence: 0.95, signal: "SvelteKit API route", archetypes: ["sveltekit"] },
2041
- { pattern: /\/src\/routes\/.*\+page\.svelte$/, layer: "presentation", confidence: 0.9, signal: "SvelteKit page", archetypes: ["sveltekit"] },
2042
- { pattern: /\/src\/routes\/.*\+layout\.svelte$/, layer: "presentation", confidence: 0.9, signal: "SvelteKit layout", archetypes: ["sveltekit"] },
2043
- { pattern: /\/src\/hooks\.server\.[jt]s$/, layer: "middleware", confidence: 0.9, signal: "SvelteKit server hooks", archetypes: ["sveltekit"] },
2044
- // ── Nuxt (archetype-specific) ──
2045
- { pattern: /\/server\/api\//, layer: "routing", confidence: 0.95, signal: "Nuxt server API", archetypes: ["nuxt"] },
2046
- { pattern: /\/server\/routes\//, layer: "routing", confidence: 0.95, signal: "Nuxt server route", archetypes: ["nuxt"] },
2047
- { pattern: /\/server\/middleware\//, layer: "middleware", confidence: 0.95, signal: "Nuxt server middleware", archetypes: ["nuxt"] },
2048
- { pattern: /\/pages\//, layer: "presentation", confidence: 0.85, signal: "Nuxt pages directory", archetypes: ["nuxt"] },
2049
- // ── NestJS (archetype-specific) ──
2050
- { pattern: /\.controller\.[jt]sx?$/, layer: "routing", confidence: 0.95, signal: "NestJS controller", archetypes: ["nestjs"] },
2051
- { pattern: /\.service\.[jt]sx?$/, layer: "services", confidence: 0.95, signal: "NestJS service", archetypes: ["nestjs"] },
2052
- { pattern: /\.module\.[jt]sx?$/, layer: "config", confidence: 0.9, signal: "NestJS module", archetypes: ["nestjs"] },
2053
- { pattern: /\.guard\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "NestJS guard", archetypes: ["nestjs"] },
2054
- { pattern: /\.interceptor\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "NestJS interceptor", archetypes: ["nestjs"] },
2055
- { pattern: /\.pipe\.[jt]sx?$/, layer: "middleware", confidence: 0.85, signal: "NestJS pipe", archetypes: ["nestjs"] },
2056
- { pattern: /\.middleware\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "NestJS middleware", archetypes: ["nestjs"] },
2057
- { pattern: /\.entity\.[jt]sx?$/, layer: "domain", confidence: 0.9, signal: "NestJS entity", archetypes: ["nestjs"] },
2058
- { pattern: /\.dto\.[jt]sx?$/, layer: "domain", confidence: 0.85, signal: "NestJS DTO", archetypes: ["nestjs"] },
2059
- { pattern: /\.repository\.[jt]sx?$/, layer: "data-access", confidence: 0.9, signal: "NestJS repository", archetypes: ["nestjs"] },
2060
- // ── Generic routing patterns ──
2061
- { pattern: /\/routes\//, layer: "routing", confidence: 0.8, signal: "routes/ directory" },
2062
- { pattern: /\/router\//, layer: "routing", confidence: 0.8, signal: "router/ directory" },
2063
- { pattern: /\/controllers\//, layer: "routing", confidence: 0.8, signal: "controllers/ directory" },
2064
- { pattern: /\/handlers\//, layer: "routing", confidence: 0.75, signal: "handlers/ directory" },
2065
- { pattern: /\/api\//, layer: "routing", confidence: 0.7, signal: "api/ directory" },
2066
- { pattern: /\/endpoints\//, layer: "routing", confidence: 0.8, signal: "endpoints/ directory" },
2067
- // ── Middleware ──
2068
- { pattern: /\/middleware\//, layer: "middleware", confidence: 0.85, signal: "middleware/ directory" },
2069
- { pattern: /\/middlewares\//, layer: "middleware", confidence: 0.85, signal: "middlewares/ directory" },
2070
- { pattern: /\/hooks\//, layer: "middleware", confidence: 0.6, signal: "hooks/ directory" },
2071
- { pattern: /\/plugins\//, layer: "middleware", confidence: 0.6, signal: "plugins/ directory" },
2072
- { pattern: /\/guards\//, layer: "middleware", confidence: 0.85, signal: "guards/ directory" },
2073
- { pattern: /\/interceptors\//, layer: "middleware", confidence: 0.85, signal: "interceptors/ directory" },
2074
- // ── Services / application layer ──
2075
- { pattern: /\/services\//, layer: "services", confidence: 0.85, signal: "services/ directory" },
2076
- { pattern: /\/service\//, layer: "services", confidence: 0.8, signal: "service/ directory" },
2077
- { pattern: /\/usecases\//, layer: "services", confidence: 0.85, signal: "usecases/ directory" },
2078
- { pattern: /\/use-cases\//, layer: "services", confidence: 0.85, signal: "use-cases/ directory" },
2079
- { pattern: /\/application\//, layer: "services", confidence: 0.7, signal: "application/ directory" },
2080
- { pattern: /\/actions\//, layer: "services", confidence: 0.65, signal: "actions/ directory" },
2081
- // ── Domain / models ──
2082
- { pattern: /\/domain\//, layer: "domain", confidence: 0.85, signal: "domain/ directory" },
2083
- { pattern: /\/models\//, layer: "domain", confidence: 0.8, signal: "models/ directory" },
2084
- { pattern: /\/entities\//, layer: "domain", confidence: 0.85, signal: "entities/ directory" },
2085
- { pattern: /\/types\//, layer: "domain", confidence: 0.7, signal: "types/ directory" },
2086
- { pattern: /\/schemas\//, layer: "domain", confidence: 0.7, signal: "schemas/ directory" },
2087
- { pattern: /\/validators\//, layer: "domain", confidence: 0.7, signal: "validators/ directory" },
2088
- // ── Data access ──
2089
- { pattern: /\/repositories\//, layer: "data-access", confidence: 0.9, signal: "repositories/ directory" },
2090
- { pattern: /\/repository\//, layer: "data-access", confidence: 0.85, signal: "repository/ directory" },
2091
- { pattern: /\/dao\//, layer: "data-access", confidence: 0.9, signal: "dao/ directory" },
2092
- { pattern: /\/db\//, layer: "data-access", confidence: 0.8, signal: "db/ directory" },
2093
- { pattern: /\/database\//, layer: "data-access", confidence: 0.8, signal: "database/ directory" },
2094
- { pattern: /\/persistence\//, layer: "data-access", confidence: 0.85, signal: "persistence/ directory" },
2095
- { pattern: /\/migrations\//, layer: "data-access", confidence: 0.9, signal: "migrations/ directory" },
2096
- { pattern: /\/seeds\//, layer: "data-access", confidence: 0.85, signal: "seeds/ directory" },
2097
- { pattern: /\/prisma\//, layer: "data-access", confidence: 0.85, signal: "prisma/ directory" },
2098
- { pattern: /\/drizzle\//, layer: "data-access", confidence: 0.85, signal: "drizzle/ directory" },
2099
- // ── Infrastructure ──
2100
- { pattern: /\/infra\//, layer: "infrastructure", confidence: 0.85, signal: "infra/ directory" },
2101
- { pattern: /\/infrastructure\//, layer: "infrastructure", confidence: 0.85, signal: "infrastructure/ directory" },
2102
- { pattern: /\/adapters\//, layer: "infrastructure", confidence: 0.8, signal: "adapters/ directory" },
2103
- { pattern: /\/clients\//, layer: "infrastructure", confidence: 0.75, signal: "clients/ directory" },
2104
- { pattern: /\/integrations\//, layer: "infrastructure", confidence: 0.8, signal: "integrations/ directory" },
2105
- { pattern: /\/external\//, layer: "infrastructure", confidence: 0.75, signal: "external/ directory" },
2106
- { pattern: /\/queue\//, layer: "infrastructure", confidence: 0.8, signal: "queue/ directory" },
2107
- { pattern: /\/jobs\//, layer: "infrastructure", confidence: 0.75, signal: "jobs/ directory" },
2108
- { pattern: /\/workers\//, layer: "infrastructure", confidence: 0.75, signal: "workers/ directory" },
2109
- { pattern: /\/cron\//, layer: "infrastructure", confidence: 0.8, signal: "cron/ directory" },
2110
- // ── Presentation (UI layer) ──
2111
- { pattern: /\/components\//, layer: "presentation", confidence: 0.85, signal: "components/ directory" },
2112
- { pattern: /\/views\//, layer: "presentation", confidence: 0.85, signal: "views/ directory" },
2113
- { pattern: /\/pages\//, layer: "presentation", confidence: 0.8, signal: "pages/ directory" },
2114
- { pattern: /\/layouts\//, layer: "presentation", confidence: 0.85, signal: "layouts/ directory" },
2115
- { pattern: /\/templates\//, layer: "presentation", confidence: 0.8, signal: "templates/ directory" },
2116
- { pattern: /\/widgets\//, layer: "presentation", confidence: 0.8, signal: "widgets/ directory" },
2117
- { pattern: /\/ui\//, layer: "presentation", confidence: 0.75, signal: "ui/ directory" },
2118
- // ── Shared / utils ──
2119
- { pattern: /\/utils\//, layer: "shared", confidence: 0.7, signal: "utils/ directory" },
2120
- { pattern: /\/helpers\//, layer: "shared", confidence: 0.7, signal: "helpers/ directory" },
2121
- { pattern: /\/lib\//, layer: "shared", confidence: 0.6, signal: "lib/ directory" },
2122
- { pattern: /\/common\//, layer: "shared", confidence: 0.65, signal: "common/ directory" },
2123
- { pattern: /\/shared\//, layer: "shared", confidence: 0.75, signal: "shared/ directory" },
2124
- { pattern: /\/constants\//, layer: "shared", confidence: 0.7, signal: "constants/ directory" },
2125
- // ── CLI-specific (command layer → routing) ──
2126
- { pattern: /\/commands\//, layer: "routing", confidence: 0.8, signal: "commands/ directory", archetypes: ["cli"] },
2127
- { pattern: /\/formatters\//, layer: "presentation", confidence: 0.8, signal: "formatters/ directory", archetypes: ["cli"] },
2128
- { pattern: /\/scanners\//, layer: "services", confidence: 0.8, signal: "scanners/ directory", archetypes: ["cli"] },
2129
- { pattern: /\/scoring\//, layer: "domain", confidence: 0.8, signal: "scoring/ directory", archetypes: ["cli"] },
2130
- // ── Serverless-specific ──
2131
- { pattern: /\/functions\//, layer: "routing", confidence: 0.8, signal: "functions/ directory", archetypes: ["serverless"] },
2132
- { pattern: /\/lambdas\//, layer: "routing", confidence: 0.85, signal: "lambdas/ directory", archetypes: ["serverless"] },
2133
- { pattern: /\/layers\//, layer: "shared", confidence: 0.7, signal: "Lambda layers/ directory", archetypes: ["serverless"] },
2134
- // ── .NET conventions ──
2135
- // Directory rules above already cover Controllers/, Services/, Models/,
2136
- // Views/, Migrations/, Middleware/ … because matching is case-insensitive.
2137
- { pattern: /\.tests?\//, layer: "testing", confidence: 0.9, signal: "*.Tests project directory" },
2138
- // Layer-named project directories (`Company.Product.Domain/`,
2139
- // `Company.Product.Database/`) — the dotted segment carries the layer.
2140
- { pattern: /\.domain\//, layer: "domain", confidence: 0.85, signal: "*.Domain project" },
2141
- { pattern: /\.(database|data|persistence)\//, layer: "data-access", confidence: 0.85, signal: "*.Database project" },
2142
- { pattern: /\.(infrastructure|infra)\//, layer: "infrastructure", confidence: 0.85, signal: "*.Infrastructure project" },
2143
- { pattern: /\.worker\//, layer: "infrastructure", confidence: 0.8, signal: "*.Worker project" },
2144
- { pattern: /\.(webapi|api)\//, layer: "routing", confidence: 0.8, signal: "*.WebApi project" },
2145
- { pattern: /\.(webapp|web|ui)\//, layer: "presentation", confidence: 0.75, signal: "*.WebApp project" },
2146
- { pattern: /\.(services?|application)\//, layer: "services", confidence: 0.8, signal: "*.Services project" },
2147
- { pattern: /\/wwwroot\//, layer: "presentation", confidence: 0.85, signal: "wwwroot/ static assets" },
2148
- { pattern: /\/properties\//, layer: "config", confidence: 0.85, signal: "Properties/ directory" },
2149
- { pattern: /\/program\.cs$/, layer: "config", confidence: 0.9, signal: "Program.cs entry point" },
2150
- { pattern: /\/startup\.cs$/, layer: "config", confidence: 0.9, signal: "Startup.cs" },
2151
- { pattern: /\.(cshtml|razor)$/, layer: "presentation", confidence: 0.9, signal: "Razor view" },
2152
- // ── JVM (Maven/Gradle standard layout + Spring package conventions) ──
2153
- { pattern: /\/src\/(test|androidtest|integrationtest)\//, layer: "testing", confidence: 0.95, signal: "src/test source set" },
2154
- { pattern: /\/controller\//, layer: "routing", confidence: 0.8, signal: "controller/ package" },
2155
- { pattern: /\/resource\//, layer: "routing", confidence: 0.7, signal: "resource/ package (JAX-RS)" },
2156
- { pattern: /\/model\//, layer: "domain", confidence: 0.75, signal: "model/ package" },
2157
- { pattern: /\/entity\//, layer: "domain", confidence: 0.85, signal: "entity/ package" },
2158
- { pattern: /\/dto\//, layer: "domain", confidence: 0.85, signal: "dto/ package" },
2159
- { pattern: /\/mappers?\//, layer: "data-access", confidence: 0.75, signal: "mapper/ package" },
2160
- // ── Python (Django/Flask/FastAPI module conventions) ──
2161
- { pattern: /\/(test_[^/]*|conftest)\.py$/, layer: "testing", confidence: 0.95, signal: "pytest test module" },
2162
- { pattern: /\/urls\.py$/, layer: "routing", confidence: 0.95, signal: "Django urls.py" },
2163
- { pattern: /\/views\.py$/, layer: "routing", confidence: 0.9, signal: "Django views.py (request handlers)" },
2164
- { pattern: /\/models\.py$/, layer: "domain", confidence: 0.9, signal: "Django models.py" },
2165
- { pattern: /\/serializers\.py$/, layer: "domain", confidence: 0.85, signal: "DRF serializers.py" },
2166
- { pattern: /\/forms\.py$/, layer: "presentation", confidence: 0.8, signal: "Django forms.py" },
2167
- { pattern: /\/(settings|admin)\.py$/, layer: "config", confidence: 0.85, signal: "Django settings/admin module" },
2168
- { pattern: /\/middleware\.py$/, layer: "middleware", confidence: 0.9, signal: "middleware.py" },
2169
- { pattern: /\/(tasks|celery)\.py$/, layer: "services", confidence: 0.8, signal: "task queue module" },
2170
- // ── Go / Rust / Dart / Ruby / Elixir test conventions ──
2171
- { pattern: /_(test|spec)\.[a-z]+$/, layer: "testing", confidence: 0.95, signal: "_test/_spec file" },
2172
- { pattern: /\/spec\//, layer: "testing", confidence: 0.85, signal: "spec/ directory (RSpec)" },
2173
- { pattern: /\/cmd\//, layer: "routing", confidence: 0.7, signal: "cmd/ entry points (Go)" },
2174
- // ── Ruby on Rails ──
2175
- { pattern: /\/migrate\//, layer: "data-access", confidence: 0.9, signal: "db/migrate/ directory" },
2176
- { pattern: /\/mailers\//, layer: "infrastructure", confidence: 0.8, signal: "mailers/ directory" },
2177
- { pattern: /\.erb$/, layer: "presentation", confidence: 0.85, signal: "ERB view template" },
2178
- // ── PHP (Laravel/Symfony) ──
2179
- { pattern: /\.blade\.php$/, layer: "presentation", confidence: 0.9, signal: "Blade view template" },
2180
- // ── Elixir (Phoenix) ──
2181
- { pattern: /\/channels\//, layer: "routing", confidence: 0.7, signal: "channels/ directory" },
2182
- { pattern: /_controller\.exs?$/, layer: "routing", confidence: 0.9, signal: "Phoenix controller" },
2183
- { pattern: /_(view|live|html|component)\.exs?$/, layer: "presentation", confidence: 0.85, signal: "Phoenix view module" },
2184
- { pattern: /\/repo\.exs?$/, layer: "data-access", confidence: 0.9, signal: "Ecto repo" },
2185
- { pattern: /\.(eex|heex)$/, layer: "presentation", confidence: 0.85, signal: "EEx/HEEx template" },
2186
- // ── Flutter / mobile ──
2187
- { pattern: /\/screens\//, layer: "presentation", confidence: 0.85, signal: "screens/ directory" }
2188
- ];
2189
- var SUFFIX_RULES = [
2190
- { suffix: ".controller", layer: "routing", confidence: 0.85, signal: "controller suffix" },
2191
- { suffix: ".route", layer: "routing", confidence: 0.85, signal: "route suffix" },
2192
- { suffix: ".router", layer: "routing", confidence: 0.85, signal: "router suffix" },
2193
- { suffix: ".handler", layer: "routing", confidence: 0.8, signal: "handler suffix" },
2194
- { suffix: ".middleware", layer: "middleware", confidence: 0.85, signal: "middleware suffix" },
2195
- { suffix: ".guard", layer: "middleware", confidence: 0.85, signal: "guard suffix" },
2196
- { suffix: ".interceptor", layer: "middleware", confidence: 0.85, signal: "interceptor suffix" },
2197
- { suffix: ".service", layer: "services", confidence: 0.85, signal: "service suffix" },
2198
- { suffix: ".usecase", layer: "services", confidence: 0.85, signal: "usecase suffix" },
2199
- { suffix: ".model", layer: "domain", confidence: 0.8, signal: "model suffix" },
2200
- { suffix: ".entity", layer: "domain", confidence: 0.85, signal: "entity suffix" },
2201
- { suffix: ".dto", layer: "domain", confidence: 0.8, signal: "DTO suffix" },
2202
- { suffix: ".schema", layer: "domain", confidence: 0.75, signal: "schema suffix" },
2203
- { suffix: ".validator", layer: "domain", confidence: 0.75, signal: "validator suffix" },
2204
- { suffix: ".repository", layer: "data-access", confidence: 0.9, signal: "repository suffix" },
2205
- { suffix: ".repo", layer: "data-access", confidence: 0.85, signal: "repo suffix" },
2206
- { suffix: ".dao", layer: "data-access", confidence: 0.9, signal: "dao suffix" },
2207
- { suffix: ".migration", layer: "data-access", confidence: 0.85, signal: "migration suffix" },
2208
- { suffix: ".adapter", layer: "infrastructure", confidence: 0.8, signal: "adapter suffix" },
2209
- { suffix: ".client", layer: "infrastructure", confidence: 0.75, signal: "client suffix" },
2210
- { suffix: ".provider", layer: "infrastructure", confidence: 0.7, signal: "provider suffix" },
2211
- { suffix: ".config", layer: "config", confidence: 0.8, signal: "config suffix" },
2212
- { suffix: ".component", layer: "presentation", confidence: 0.8, signal: "component suffix" },
2213
- { suffix: ".page", layer: "presentation", confidence: 0.85, signal: "page suffix" },
2214
- { suffix: ".view", layer: "presentation", confidence: 0.8, signal: "view suffix" },
2215
- { suffix: ".layout", layer: "presentation", confidence: 0.85, signal: "layout suffix" },
2216
- { suffix: ".util", layer: "shared", confidence: 0.7, signal: "util suffix" },
2217
- { suffix: ".helper", layer: "shared", confidence: 0.7, signal: "helper suffix" },
2218
- { suffix: ".constant", layer: "shared", confidence: 0.7, signal: "constant suffix" }
2219
- ];
2220
- var PASCAL_SUFFIX_RULES = [
2221
- { suffix: "Controller", layer: "routing", confidence: 0.9, signal: "Controller class" },
2222
- { suffix: "Endpoint", layer: "routing", confidence: 0.85, signal: "Endpoint class" },
2223
- { suffix: "Middleware", layer: "middleware", confidence: 0.9, signal: "Middleware class" },
2224
- { suffix: "Filter", layer: "middleware", confidence: 0.75, signal: "Filter class" },
2225
- { suffix: "Service", layer: "services", confidence: 0.85, signal: "Service class" },
2226
- { suffix: "Handler", layer: "services", confidence: 0.75, signal: "Handler class" },
2227
- { suffix: "UseCase", layer: "services", confidence: 0.85, signal: "UseCase class" },
2228
- { suffix: "Entity", layer: "domain", confidence: 0.85, signal: "Entity class" },
2229
- { suffix: "Dto", layer: "domain", confidence: 0.8, signal: "DTO class" },
2230
- { suffix: "Validator", layer: "domain", confidence: 0.75, signal: "Validator class" },
2231
- { suffix: "ViewModel", layer: "presentation", confidence: 0.85, signal: "ViewModel class" },
2232
- { suffix: "Repository", layer: "data-access", confidence: 0.9, signal: "Repository class" },
2233
- { suffix: "DbContext", layer: "data-access", confidence: 0.95, signal: "EF Core DbContext" },
2234
- { suffix: "Migration", layer: "data-access", confidence: 0.85, signal: "Migration class" },
2235
- { suffix: "Client", layer: "infrastructure", confidence: 0.7, signal: "Client class" },
2236
- { suffix: "Tests", layer: "testing", confidence: 0.95, signal: "Tests class" },
2237
- { suffix: "Test", layer: "testing", confidence: 0.9, signal: "Test class" },
2238
- // JVM (Spring/JEE/Android)
2239
- { suffix: "ServiceImpl", layer: "services", confidence: 0.9, signal: "ServiceImpl class" },
2240
- { suffix: "Dao", layer: "data-access", confidence: 0.9, signal: "DAO class" },
2241
- { suffix: "Mapper", layer: "data-access", confidence: 0.75, signal: "Mapper class" },
2242
- { suffix: "Resource", layer: "routing", confidence: 0.75, signal: "JAX-RS resource class" },
2243
- { suffix: "Configuration", layer: "config", confidence: 0.85, signal: "Configuration class" },
2244
- { suffix: "Config", layer: "config", confidence: 0.8, signal: "Config class" },
2245
- { suffix: "Interceptor", layer: "middleware", confidence: 0.85, signal: "Interceptor class" },
2246
- { suffix: "Activity", layer: "presentation", confidence: 0.85, signal: "Android Activity" },
2247
- { suffix: "Fragment", layer: "presentation", confidence: 0.85, signal: "Android Fragment" },
2248
- // Swift / iOS — higher confidence than the generic Controller→routing rule
2249
- // so FooViewController lands in presentation, not routing.
2250
- { suffix: "ViewController", layer: "presentation", confidence: 0.95, signal: "UIKit ViewController" },
2251
- // Flutter
2252
- { suffix: "Screen", layer: "presentation", confidence: 0.85, signal: "Screen widget" },
2253
- { suffix: "Widget", layer: "presentation", confidence: 0.75, signal: "Widget class" }
2254
- ];
2255
- var PACKAGE_LAYER_MAP = {
2256
- // Routing/controllers
2257
- "express": "routing",
2258
- "fastify": "routing",
2259
- "@nestjs/core": "routing",
2260
- "hono": "routing",
2261
- "koa": "routing",
2262
- "koa-router": "routing",
2263
- "@hapi/hapi": "routing",
2264
- "h3": "routing",
2265
- // Middleware
2266
- "cors": "middleware",
2267
- "helmet": "middleware",
2268
- "passport": "middleware",
2269
- "express-rate-limit": "middleware",
2270
- "cookie-parser": "middleware",
2271
- "body-parser": "middleware",
2272
- "multer": "middleware",
2273
- "morgan": "middleware",
2274
- "compression": "middleware",
2275
- "express-session": "middleware",
2276
- // Services / application
2277
- "bullmq": "services",
2278
- "bull": "services",
2279
- "agenda": "services",
2280
- "pg-boss": "services",
2281
- "inngest": "services",
2282
- // Domain / validation
2283
- "zod": "domain",
2284
- "joi": "domain",
2285
- "yup": "domain",
2286
- "class-validator": "domain",
2287
- "class-transformer": "domain",
2288
- "superstruct": "domain",
2289
- "valibot": "domain",
2290
- // Data access / ORM
2291
- "prisma": "data-access",
2292
- "@prisma/client": "data-access",
2293
- "drizzle-orm": "data-access",
2294
- "typeorm": "data-access",
2295
- "sequelize": "data-access",
2296
- "knex": "data-access",
2297
- "pg": "data-access",
2298
- "mysql2": "data-access",
2299
- "mongodb": "data-access",
2300
- "mongoose": "data-access",
2301
- "ioredis": "data-access",
2302
- "redis": "data-access",
2303
- "better-sqlite3": "data-access",
2304
- "kysely": "data-access",
2305
- "@mikro-orm/core": "data-access",
2306
- // Infrastructure
2307
- "@aws-sdk/client-s3": "infrastructure",
2308
- "@aws-sdk/client-sqs": "infrastructure",
2309
- "@aws-sdk/client-sns": "infrastructure",
2310
- "@aws-sdk/client-ses": "infrastructure",
2311
- "@aws-sdk/client-lambda": "infrastructure",
2312
- "@google-cloud/storage": "infrastructure",
2313
- "@azure/storage-blob": "infrastructure",
2314
- "nodemailer": "infrastructure",
2315
- "@sendgrid/mail": "infrastructure",
2316
- "stripe": "infrastructure",
2317
- "kafkajs": "infrastructure",
2318
- "amqplib": "infrastructure",
2319
- // Presentation
2320
- "react": "presentation",
2321
- "react-dom": "presentation",
2322
- "vue": "presentation",
2323
- "@angular/core": "presentation",
2324
- "svelte": "presentation",
2325
- // Shared
2326
- "lodash": "shared",
2327
- "dayjs": "shared",
2328
- "date-fns": "shared",
2329
- "uuid": "shared",
2330
- "nanoid": "shared",
2331
- // Testing
2332
- "vitest": "testing",
2333
- "jest": "testing",
2334
- "mocha": "testing",
2335
- "@playwright/test": "testing",
2336
- "cypress": "testing",
2337
- "supertest": "testing",
2338
- // Observability → infrastructure
2339
- "@sentry/node": "infrastructure",
2340
- "@opentelemetry/api": "infrastructure",
2341
- "pino": "infrastructure",
2342
- "winston": "infrastructure",
2343
- "dd-trace": "infrastructure",
2344
- // ── .NET (NuGet package ids) ──
2345
- "Microsoft.EntityFrameworkCore": "data-access",
2346
- "Dapper": "data-access",
2347
- "Npgsql": "data-access",
2348
- "Microsoft.Data.SqlClient": "data-access",
2349
- "System.Data.SqlClient": "data-access",
2350
- "MongoDB.Driver": "data-access",
2351
- "StackExchange.Redis": "data-access",
2352
- "MediatR": "services",
2353
- "Hangfire": "services",
2354
- "Quartz": "services",
2355
- "FluentValidation": "domain",
2356
- "AutoMapper": "domain",
2357
- "Microsoft.AspNetCore.Authentication.JwtBearer": "middleware",
2358
- "Swashbuckle.AspNetCore": "routing",
2359
- "Serilog": "infrastructure",
2360
- "NLog": "infrastructure",
2361
- "Polly": "infrastructure",
2362
- "RabbitMQ.Client": "infrastructure",
2363
- "MassTransit": "infrastructure",
2364
- "Confluent.Kafka": "infrastructure",
2365
- "Azure.Storage.Blobs": "infrastructure",
2366
- "AWSSDK.S3": "infrastructure",
2367
- "Newtonsoft.Json": "shared",
2368
- "xunit": "testing",
2369
- "NUnit": "testing",
2370
- "MSTest.TestFramework": "testing",
2371
- "Moq": "testing",
2372
- "NSubstitute": "testing",
2373
- "FluentAssertions": "testing",
2374
- // ── Python (PyPI) ──
2375
- "django": "routing",
2376
- "flask": "routing",
2377
- "fastapi": "routing",
2378
- "starlette": "routing",
2379
- "sqlalchemy": "data-access",
2380
- "alembic": "data-access",
2381
- "psycopg2": "data-access",
2382
- "psycopg2-binary": "data-access",
2383
- "pymongo": "data-access",
2384
- "pydantic": "domain",
2385
- "marshmallow": "domain",
2386
- "celery": "services",
2387
- "pytest": "testing",
2388
- "boto3": "infrastructure",
2389
- "httpx": "infrastructure",
2390
- "requests": "infrastructure",
2391
- "gunicorn": "infrastructure",
2392
- "uvicorn": "infrastructure",
2393
- "structlog": "infrastructure",
2394
- // ── JVM (Maven groupId:artifactId, as the Java scanner keys them) ──
2395
- "org.springframework.boot:spring-boot-starter-web": "routing",
2396
- "org.springframework:spring-webmvc": "routing",
2397
- "io.ktor:ktor-server-core": "routing",
2398
- "io.quarkus:quarkus-resteasy": "routing",
2399
- "org.springframework.boot:spring-boot-starter-data-jpa": "data-access",
2400
- "org.hibernate:hibernate-core": "data-access",
2401
- "org.hibernate.orm:hibernate-core": "data-access",
2402
- "org.mybatis:mybatis": "data-access",
2403
- "com.zaxxer:HikariCP": "data-access",
2404
- "org.jetbrains.exposed:exposed-core": "data-access",
2405
- "org.springframework.boot:spring-boot-starter-security": "middleware",
2406
- "jakarta.validation:jakarta.validation-api": "domain",
2407
- "com.fasterxml.jackson.core:jackson-databind": "shared",
2408
- "org.projectlombok:lombok": "shared",
2409
- "junit:junit": "testing",
2410
- "org.junit.jupiter:junit-jupiter": "testing",
2411
- "org.mockito:mockito-core": "testing",
2412
- "org.testng:testng": "testing",
2413
- "ch.qos.logback:logback-classic": "infrastructure",
2414
- "org.slf4j:slf4j-api": "infrastructure",
2415
- "org.apache.kafka:kafka-clients": "infrastructure",
2416
- "com.squareup.okhttp3:okhttp": "infrastructure",
2417
- // ── Go (module paths) ──
2418
- "github.com/gin-gonic/gin": "routing",
2419
- "github.com/labstack/echo/v4": "routing",
2420
- "github.com/gorilla/mux": "routing",
2421
- "github.com/go-chi/chi/v5": "routing",
2422
- "github.com/gofiber/fiber/v2": "routing",
2423
- "github.com/spf13/cobra": "routing",
2424
- "gorm.io/gorm": "data-access",
2425
- "github.com/jmoiron/sqlx": "data-access",
2426
- "github.com/jackc/pgx/v5": "data-access",
2427
- "go.mongodb.org/mongo-driver": "data-access",
2428
- "github.com/redis/go-redis/v9": "data-access",
2429
- "github.com/spf13/viper": "config",
2430
- "github.com/stretchr/testify": "testing",
2431
- "go.uber.org/zap": "infrastructure",
2432
- "github.com/sirupsen/logrus": "infrastructure",
2433
- "google.golang.org/grpc": "infrastructure",
2434
- // ── Rust (crates) ──
2435
- "actix-web": "routing",
2436
- "axum": "routing",
2437
- "rocket": "routing",
2438
- "warp": "routing",
2439
- "clap": "routing",
2440
- "diesel": "data-access",
2441
- "sqlx": "data-access",
2442
- "sea-orm": "data-access",
2443
- "serde": "domain",
2444
- "tokio": "infrastructure",
2445
- "reqwest": "infrastructure",
2446
- "tracing": "infrastructure",
2447
- // ── Ruby (gems) ──
2448
- "rails": "routing",
2449
- "sinatra": "routing",
2450
- "activerecord": "data-access",
2451
- "sequel": "data-access",
2452
- "devise": "middleware",
2453
- "pundit": "middleware",
2454
- "sidekiq": "services",
2455
- "rspec": "testing",
2456
- "rspec-rails": "testing",
2457
- "minitest": "testing",
2458
- "puma": "infrastructure",
2459
- "faraday": "infrastructure",
2460
- // ── PHP (Composer vendor/package) ──
2461
- "laravel/framework": "routing",
2462
- "symfony/http-kernel": "routing",
2463
- "slim/slim": "routing",
2464
- "doctrine/orm": "data-access",
2465
- "illuminate/database": "data-access",
2466
- "phpunit/phpunit": "testing",
2467
- "pestphp/pest": "testing",
2468
- "guzzlehttp/guzzle": "infrastructure",
2469
- "monolog/monolog": "infrastructure",
2470
- // ── Swift (SPM) ──
2471
- "Alamofire": "infrastructure",
2472
- "vapor": "routing",
2473
- "Vapor": "routing",
2474
- // ── Dart (pub) ──
2475
- "dio": "infrastructure",
2476
- "sqflite": "data-access",
2477
- "flutter_bloc": "services",
2478
- "riverpod": "services",
2479
- "flutter_riverpod": "services",
2480
- "go_router": "routing",
2481
- "auto_route": "routing",
2482
- "flutter_test": "testing",
2483
- "mockito": "testing",
2484
- // ── Elixir (Hex) ──
2485
- "phoenix": "routing",
2486
- "phoenix_live_view": "presentation",
2487
- "ecto": "data-access",
2488
- "ecto_sql": "data-access",
2489
- "postgrex": "data-access",
2490
- "oban": "services",
2491
- "ex_machina": "testing",
2492
- "tesla": "infrastructure",
2493
- "httpoison": "infrastructure",
2494
- "finch": "infrastructure",
2495
- "jason": "shared"
2496
- };
2497
- var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
2498
- ".ts",
2499
- ".tsx",
2500
- ".js",
2501
- ".jsx",
2502
- ".mts",
2503
- ".mjs",
2504
- ".cts",
2505
- ".cjs",
2506
- ".svelte",
2507
- ".vue",
2508
- // .NET — layer detection works off the same directory/suffix conventions
2509
- ".cs",
2510
- ".vb",
2511
- ".fs",
2512
- ".cshtml",
2513
- ".razor",
2514
- // JVM
2515
- ".java",
2516
- ".kt",
2517
- ".kts",
2518
- ".scala",
2519
- ".groovy",
2520
- // Python
2521
- ".py",
2522
- ".pyi",
2523
- // Go / Rust
2524
- ".go",
2525
- ".rs",
2526
- // Ruby (incl. ERB view templates)
2527
- ".rb",
2528
- ".rake",
2529
- ".erb",
2530
- // PHP (incl. Blade — extname is still .php)
2531
- ".php",
2532
- // Swift / Dart
2533
- ".swift",
2534
- ".dart",
2535
- // Elixir (incl. EEx/HEEx view templates)
2536
- ".ex",
2537
- ".exs",
2538
- ".eex",
2539
- ".heex"
2540
- ]);
2541
- async function walkSourceFiles(rootDir, cache) {
2542
- if (cache) {
2543
- const entries = await cache.walkDir(rootDir);
2544
- return entries.filter((e) => {
2545
- if (!e.isFile) return false;
2546
- const name = path3.basename(e.absPath);
2547
- if (name.startsWith(".") && name !== ".") return false;
2548
- const ext = path3.extname(name);
2549
- return SOURCE_EXTENSIONS.has(ext);
2550
- }).map((e) => e.relPath);
2551
- }
2552
- const files = [];
2553
- async function walk(dir) {
2554
- let entries;
2555
- try {
2556
- entries = await fs.readdir(dir, { withFileTypes: true });
2557
- } catch {
2558
- return;
2559
- }
2560
- for (const entry of entries) {
2561
- if (entry.name.startsWith(".") && entry.name !== ".") continue;
2562
- const fullPath = path3.join(dir, entry.name);
2563
- if (entry.isDirectory()) {
2564
- if (!isSkippedDirName(entry.name)) {
2565
- await walk(fullPath);
2566
- }
2567
- } else if (entry.isFile()) {
2568
- const ext = path3.extname(entry.name);
2569
- if (SOURCE_EXTENSIONS.has(ext)) {
2570
- files.push(path3.relative(rootDir, fullPath));
2571
- }
2572
- }
2573
- }
2574
- }
2575
- await walk(rootDir);
2576
- return files;
2577
- }
2578
- function classifyFile(filePath, archetype) {
2579
- const normalised = "/" + filePath.replace(/\\/g, "/").replace(/^\/+/, "");
2580
- const lowered = normalised.toLowerCase();
2581
- let bestMatch = null;
2582
- for (const rule of PATH_RULES) {
2583
- if (rule.archetypes && rule.archetypes.length > 0 && !rule.archetypes.includes(archetype)) {
2584
- continue;
2585
- }
2586
- if (rule.pattern.test(lowered)) {
2587
- const boost = rule.archetypes ? 0.05 : 0;
2588
- const adjustedConfidence = Math.min(rule.confidence + boost, 1);
2589
- if (!bestMatch || adjustedConfidence > bestMatch.confidence) {
2590
- bestMatch = { layer: rule.layer, confidence: adjustedConfidence, signal: rule.signal };
2591
- }
2592
- }
2593
- }
2594
- if (!bestMatch || bestMatch.confidence < 0.7) {
2595
- const baseName = path3.basename(filePath, path3.extname(filePath));
2596
- const cleanBase = baseName.replace(/\.(test|spec)$/, "");
2597
- for (const rule of SUFFIX_RULES) {
2598
- if (cleanBase.endsWith(rule.suffix)) {
2599
- if (!bestMatch || rule.confidence > bestMatch.confidence) {
2600
- bestMatch = { layer: rule.layer, confidence: rule.confidence, signal: rule.signal };
2601
- }
2602
- }
2603
- }
2604
- for (const rule of PASCAL_SUFFIX_RULES) {
2605
- if (cleanBase.endsWith(rule.suffix)) {
2606
- if (!bestMatch || rule.confidence > bestMatch.confidence) {
2607
- bestMatch = { layer: rule.layer, confidence: rule.confidence, signal: rule.signal };
2608
- }
2609
- }
2610
- }
2611
- }
2612
- if (bestMatch) {
2613
- return {
2614
- filePath,
2615
- layer: bestMatch.layer,
2616
- confidence: bestMatch.confidence,
2617
- signals: [bestMatch.signal]
2618
- };
2619
- }
2620
- return null;
2621
- }
2622
- function computeLayerDrift(packages) {
2623
- if (packages.length === 0) {
2624
- return { score: 0, riskLevel: "none" };
2625
- }
2626
- let current = 0;
2627
- let oneBehind = 0;
2628
- let twoPlusBehind = 0;
2629
- for (const pkg of packages) {
2630
- if (pkg.majorsBehind === null) ; else if (pkg.majorsBehind === 0) {
2631
- current++;
2632
- } else if (pkg.majorsBehind === 1) {
2633
- oneBehind++;
2634
- } else {
2635
- twoPlusBehind++;
2636
- }
2637
- }
2638
- const known = current + oneBehind + twoPlusBehind;
2639
- if (known === 0) return { score: 0, riskLevel: "none" };
2640
- const currentPct = current / known;
2641
- const onePct = oneBehind / known;
2642
- const twoPct = twoPlusBehind / known;
2643
- const health = Math.round(Math.max(0, Math.min(100, currentPct * 100 - onePct * 10 - twoPct * 40)));
2644
- const score = 100 - health;
2645
- const riskLevel = score <= 30 ? "low" : score <= 60 ? "moderate" : "high";
2646
- return { score, riskLevel };
2647
- }
2648
- function mapToolingToLayers(tooling, services, depsByLayer) {
2649
- const layerTooling = /* @__PURE__ */ new Map();
2650
- const layerServices = /* @__PURE__ */ new Map();
2651
- const pkgLayerLookup = /* @__PURE__ */ new Map();
2652
- for (const [layer, packages] of depsByLayer) {
2653
- for (const pkg of packages) {
2654
- pkgLayerLookup.set(pkg, layer);
2655
- }
2656
- }
2657
- if (tooling) {
2658
- for (const [, items] of Object.entries(tooling)) {
2659
- for (const item of items) {
2660
- const layer = pkgLayerLookup.get(item.package) ?? PACKAGE_LAYER_MAP[item.package] ?? "shared";
2661
- if (!layerTooling.has(layer)) layerTooling.set(layer, []);
2662
- const existing = layerTooling.get(layer);
2663
- if (!existing.some((t) => t.package === item.package)) {
2664
- existing.push(item);
2665
- }
2666
- }
2667
- }
2668
- }
2669
- if (services) {
2670
- for (const [, items] of Object.entries(services)) {
2671
- for (const item of items) {
2672
- const layer = pkgLayerLookup.get(item.package) ?? PACKAGE_LAYER_MAP[item.package] ?? "infrastructure";
2673
- if (!layerServices.has(layer)) layerServices.set(layer, []);
2674
- const existing = layerServices.get(layer);
2675
- if (!existing.some((s) => s.package === item.package)) {
2676
- existing.push(item);
2677
- }
2678
- }
2679
- }
2680
- }
2681
- return { layerTooling, layerServices };
2682
- }
2683
- function generateLayerFlowMermaid(layers) {
2684
- const labels = {
2685
- presentation: "Presentation",
2686
- routing: "Routing",
2687
- middleware: "Middleware",
2688
- services: "Services",
2689
- domain: "Domain",
2690
- "data-access": "Data Access",
2691
- infrastructure: "Infrastructure",
2692
- config: "Config",
2693
- shared: "Shared",
2694
- testing: "Testing"
2695
- };
2696
- if (layers.length === 0) {
2697
- return 'flowchart TD\n APP["Project"]';
2698
- }
2699
- const ordered = [...layers];
2700
- const lines = ["flowchart TD"];
2701
- for (let i = 0; i < ordered.length; i++) {
2702
- const layer = ordered[i];
2703
- lines.push(` L${i}["${labels[layer]}"]`);
2704
- if (i > 0) lines.push(` L${i - 1} --> L${i}`);
2705
- }
2706
- return lines.join("\n");
2707
- }
2708
- async function buildProjectArchitectureMermaid(rootDir, project, archetype, cache) {
2709
- const projectRoot = path3.resolve(rootDir, project.path || ".");
2710
- const allFiles = await walkSourceFiles(projectRoot, cache);
2711
- const layerSet = /* @__PURE__ */ new Set();
2712
- for (const rel of allFiles) {
2713
- const classification = classifyFile(rel, archetype);
2714
- if (classification) {
2715
- layerSet.add(classification.layer);
2716
- }
2717
- }
2718
- const layerOrder = [
2719
- "presentation",
2720
- "routing",
2721
- "middleware",
2722
- "services",
2723
- "domain",
2724
- "data-access",
2725
- "infrastructure",
2726
- "config",
2727
- "shared",
2728
- "testing"
2729
- ];
2730
- const orderedLayers = layerOrder.filter((l) => layerSet.has(l));
2731
- return generateLayerFlowMermaid(orderedLayers);
2732
- }
2733
- async function scanProjectArchitecture(rootDir, project, cache) {
2734
- const projectRoot = path3.resolve(rootDir, project.path || ".");
2735
- return scanArchitecture(projectRoot, [project], void 0, void 0, cache);
2736
- }
2737
- function aggregateSolutionArchitecture(projectResults) {
2738
- if (projectResults.length === 0) {
2739
- return { archetype: "unknown", archetypeConfidence: 0, layers: [], totalClassified: 0, unclassified: 0 };
2740
- }
2741
- if (projectResults.length === 1) {
2742
- return projectResults[0];
2743
- }
2744
- let bestArchetype = "unknown";
2745
- let bestConfidence = 0;
2746
- for (const r of projectResults) {
2747
- if (r.archetypeConfidence > bestConfidence || r.archetypeConfidence === bestConfidence && r.archetype !== "monorepo") {
2748
- bestArchetype = r.archetype;
2749
- bestConfidence = r.archetypeConfidence;
2750
- }
2751
- }
2752
- const layerMap = /* @__PURE__ */ new Map();
2753
- for (const r of projectResults) {
2754
- for (const ls of r.layers) {
2755
- const existing = layerMap.get(ls.layer);
2756
- if (!existing) {
2757
- layerMap.set(ls.layer, { ...ls, packages: [...ls.packages], techStack: [...ls.techStack], services: [...ls.services], files: [...ls.files] });
2758
- } else {
2759
- existing.fileCount += ls.fileCount;
2760
- const pkgNames = new Set(existing.packages.map((p) => p.name));
2761
- for (const pkg of ls.packages) {
2762
- if (!pkgNames.has(pkg.name)) {
2763
- existing.packages.push(pkg);
2764
- pkgNames.add(pkg.name);
2765
- }
2766
- }
2767
- const techPkgs = new Set(existing.techStack.map((t) => t.package));
2768
- for (const t of ls.techStack) {
2769
- if (!techPkgs.has(t.package)) {
2770
- existing.techStack.push(t);
2771
- techPkgs.add(t.package);
2772
- }
2773
- }
2774
- const svcPkgs = new Set(existing.services.map((s) => s.package));
2775
- for (const s of ls.services) {
2776
- if (!svcPkgs.has(s.package)) {
2777
- existing.services.push(s);
2778
- svcPkgs.add(s.package);
2779
- }
2780
- }
2781
- const seenFiles = new Set(existing.files);
2782
- for (const f of ls.files) {
2783
- if (existing.files.length >= 40) break;
2784
- if (!seenFiles.has(f)) {
2785
- existing.files.push(f);
2786
- seenFiles.add(f);
2787
- }
2788
- }
2789
- const { score, riskLevel } = computeLayerDrift(existing.packages);
2790
- existing.driftScore = score;
2791
- existing.riskLevel = riskLevel;
2792
- }
2793
- }
2794
- }
2795
- const LAYER_ORDER = {
2796
- "presentation": 0,
2797
- "routing": 1,
2798
- "middleware": 2,
2799
- "services": 3,
2800
- "domain": 4,
2801
- "data-access": 5,
2802
- "infrastructure": 6,
2803
- "config": 7,
2804
- "shared": 8,
2805
- "testing": 9
2806
- };
2807
- const layers = [...layerMap.values()].sort((a, b) => (LAYER_ORDER[a.layer] ?? 99) - (LAYER_ORDER[b.layer] ?? 99));
2808
- const totalClassified = projectResults.reduce((s, r) => s + r.totalClassified, 0);
2809
- const unclassified = projectResults.reduce((s, r) => s + r.unclassified, 0);
2810
- return { archetype: bestArchetype, archetypeConfidence: bestConfidence, layers, totalClassified, unclassified };
2811
- }
2812
- async function scanArchitecture(rootDir, projects, tooling, services, cache) {
2813
- const { archetype, confidence: archetypeConfidence } = detectArchetype(projects);
2814
- const sourceFiles = await walkSourceFiles(rootDir, cache);
2815
- const classifications = [];
2816
- let unclassified = 0;
2817
- for (const file of sourceFiles) {
2818
- const classification = classifyFile(file, archetype);
2819
- if (classification) {
2820
- classifications.push(classification);
2821
- } else {
2822
- unclassified++;
2823
- }
2824
- }
2825
- const allDeps = /* @__PURE__ */ new Map();
2826
- for (const p of projects) {
2827
- for (const d of p.dependencies) {
2828
- if (!allDeps.has(d.package)) {
2829
- allDeps.set(d.package, d);
2830
- }
2831
- }
2832
- }
2833
- const depsByLayer = /* @__PURE__ */ new Map();
2834
- for (const [pkg] of allDeps) {
2835
- const layer = PACKAGE_LAYER_MAP[pkg];
2836
- if (layer) {
2837
- if (!depsByLayer.has(layer)) depsByLayer.set(layer, /* @__PURE__ */ new Set());
2838
- depsByLayer.get(layer).add(pkg);
2839
- }
2840
- }
2841
- const { layerTooling, layerServices } = mapToolingToLayers(tooling, services, depsByLayer);
2842
- const ALL_LAYERS = [
2843
- "routing",
2844
- "middleware",
2845
- "services",
2846
- "domain",
2847
- "data-access",
2848
- "infrastructure",
2849
- "presentation",
2850
- "config",
2851
- "testing",
2852
- "shared"
2853
- ];
2854
- const LAYER_FILES_CAP = 40;
2855
- const layerFileCounts = /* @__PURE__ */ new Map();
2856
- const layerFiles = /* @__PURE__ */ new Map();
2857
- for (const c of classifications) {
2858
- layerFileCounts.set(c.layer, (layerFileCounts.get(c.layer) ?? 0) + 1);
2859
- const existing = layerFiles.get(c.layer);
2860
- if (existing) {
2861
- if (existing.length < LAYER_FILES_CAP) existing.push(c.filePath);
2862
- } else {
2863
- layerFiles.set(c.layer, [c.filePath]);
2864
- }
2865
- }
2866
- const layers = [];
2867
- for (const layer of ALL_LAYERS) {
2868
- const fileCount = layerFileCounts.get(layer) ?? 0;
2869
- const layerPkgs = depsByLayer.get(layer) ?? /* @__PURE__ */ new Set();
2870
- const tech = layerTooling.get(layer) ?? [];
2871
- const svc = layerServices.get(layer) ?? [];
2872
- if (fileCount === 0 && layerPkgs.size === 0 && tech.length === 0 && svc.length === 0) {
2873
- continue;
2874
- }
2875
- const packages = [];
2876
- for (const pkg of layerPkgs) {
2877
- const dep = allDeps.get(pkg);
2878
- if (dep) {
2879
- packages.push({
2880
- name: dep.package,
2881
- version: dep.resolvedVersion,
2882
- latestStable: dep.latestStable,
2883
- majorsBehind: dep.majorsBehind,
2884
- drift: dep.drift
2885
- });
2886
- }
2887
- }
2888
- const { score, riskLevel } = computeLayerDrift(packages);
2889
- layers.push({
2890
- layer,
2891
- fileCount,
2892
- driftScore: score,
2893
- riskLevel,
2894
- techStack: tech,
2895
- services: svc,
2896
- packages,
2897
- files: layerFiles.get(layer) ?? []
2898
- });
2899
- }
2900
- const LAYER_ORDER = {
2901
- "presentation": 0,
2902
- "routing": 1,
2903
- "middleware": 2,
2904
- "services": 3,
2905
- "domain": 4,
2906
- "data-access": 5,
2907
- "infrastructure": 6,
2908
- "config": 7,
2909
- "shared": 8,
2910
- "testing": 9
2911
- };
2912
- layers.sort((a, b) => (LAYER_ORDER[a.layer] ?? 99) - (LAYER_ORDER[b.layer] ?? 99));
2913
- return {
2914
- archetype,
2915
- archetypeConfidence,
2916
- layers,
2917
- totalClassified: classifications.length,
2918
- unclassified
2919
- };
2920
- }
2921
1966
  var ts;
2922
1967
  var tsLoading = null;
2923
1968
  async function ensureTypeScript() {
@@ -2928,7 +1973,7 @@ async function ensureTypeScript() {
2928
1973
  });
2929
1974
  await tsLoading;
2930
1975
  }
2931
- var SOURCE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
1976
+ var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
2932
1977
  var DEFAULT_RESULT = {
2933
1978
  filesAnalyzed: 0,
2934
1979
  functionsAnalyzed: 0,
@@ -2994,9 +2039,9 @@ async function scanCodeQuality(rootDir, cache) {
2994
2039
  async function findSourceFiles(rootDir, cache) {
2995
2040
  if (cache) {
2996
2041
  const entries = await cache.walkDir(rootDir);
2997
- return entries.filter((entry) => entry.isFile && SOURCE_EXTENSIONS2.has(path3.extname(entry.name).toLowerCase())).map((entry) => entry.absPath);
2042
+ return entries.filter((entry) => entry.isFile && SOURCE_EXTENSIONS.has(path3.extname(entry.name).toLowerCase())).map((entry) => entry.absPath);
2998
2043
  }
2999
- const files = await findFiles(rootDir, (name) => SOURCE_EXTENSIONS2.has(path3.extname(name).toLowerCase()));
2044
+ const files = await findFiles(rootDir, (name) => SOURCE_EXTENSIONS.has(path3.extname(name).toLowerCase()));
3000
2045
  return files;
3001
2046
  }
3002
2047
  function collectLocalImports(source, fileDir, rootDir) {
@@ -4272,6 +3317,11 @@ function archetypeCategory(archetype) {
4272
3317
  case "hono":
4273
3318
  case "koa":
4274
3319
  case "serverless":
3320
+ case "spring":
3321
+ case "aspnet":
3322
+ case "django":
3323
+ case "fastapi":
3324
+ case "go-service":
4275
3325
  return { category: "api", signal: `archetype:${archetype}` };
4276
3326
  case "library":
4277
3327
  return { category: "library", signal: "archetype:library" };
@@ -4281,6 +3331,41 @@ function archetypeCategory(archetype) {
4281
3331
  return null;
4282
3332
  }
4283
3333
  }
3334
+ function projectKindCategory(kind) {
3335
+ switch (kind) {
3336
+ case "web-app":
3337
+ return { category: "web-app", signal: "projectKind:web-app" };
3338
+ case "web-api":
3339
+ return { category: "api", signal: "projectKind:web-api" };
3340
+ case "library":
3341
+ return { category: "library", signal: "projectKind:library" };
3342
+ case "cli":
3343
+ return { category: "cli", signal: "projectKind:cli" };
3344
+ case "iac":
3345
+ return { category: "infra", signal: "projectKind:iac" };
3346
+ case "database":
3347
+ return { category: "data", signal: "projectKind:database" };
3348
+ case "worker":
3349
+ return { category: "api", signal: "projectKind:worker" };
3350
+ default:
3351
+ return null;
3352
+ }
3353
+ }
3354
+ var API_FRAMEWORKS = /* @__PURE__ */ new Set([
3355
+ "express",
3356
+ "nestjs",
3357
+ "fastify",
3358
+ "hono",
3359
+ "koa",
3360
+ "spring",
3361
+ "aspnet",
3362
+ "django",
3363
+ "fastapi",
3364
+ "laravel",
3365
+ "phoenix",
3366
+ "rails"
3367
+ ]);
3368
+ var WEB_FRAMEWORKS = /* @__PURE__ */ new Set(["nextjs", "remix", "sveltekit", "nuxt"]);
4284
3369
  function inferProjectPurpose(project, uiPurpose) {
4285
3370
  const signals = [];
4286
3371
  const votes = {};
@@ -4288,9 +3373,19 @@ function inferProjectPurpose(project, uiPurpose) {
4288
3373
  votes[category] = (votes[category] ?? 0) + weight;
4289
3374
  signals.push(signal);
4290
3375
  };
4291
- if (project.type === "node" || project.type === "typescript") {
4292
- const arch = archetypeCategory(project.architecture?.archetype);
4293
- if (arch) vote(arch.category, 3, arch.signal);
3376
+ const pk = projectKindCategory(project.architecture?.projectKind);
3377
+ if (pk) vote(pk.category, 3, pk.signal);
3378
+ const fwHits = (project.architecture?.evidence ?? []).filter((e) => e.dimension === "framework").map((e) => e.value.toLowerCase());
3379
+ for (const fw of fwHits) {
3380
+ if (WEB_FRAMEWORKS.has(fw)) vote("web-app", 2, `framework:${fw}`);
3381
+ if (API_FRAMEWORKS.has(fw)) vote("api", 2, `framework:${fw}`);
3382
+ }
3383
+ const arch = archetypeCategory(project.architecture?.archetype);
3384
+ if (arch) {
3385
+ const nonJsArchetype = ["spring", "aspnet", "django", "fastapi", "go-service"].includes(project.architecture?.archetype ?? "");
3386
+ if (project.type === "node" || project.type === "typescript" || nonJsArchetype) {
3387
+ vote(arch.category, 3, arch.signal);
3388
+ }
4294
3389
  }
4295
3390
  const fwNames = (project.frameworks ?? []).map((f) => f.name.toLowerCase());
4296
3391
  const uiFw = (uiPurpose?.detectedFrameworks ?? []).map((f) => f.toLowerCase());
@@ -4592,29 +3687,27 @@ async function runAdvancedAnalysis(ctx) {
4592
3687
  }
4593
3688
  if (scannerPolicy.architecture && scanners?.architecture?.enabled !== false) {
4594
3689
  progress.startStep("architecture");
4595
- extended.architecture = await scanArchitecture(
3690
+ const { workspace, projectResults } = await scanArchitectureBundle(
4596
3691
  rootDir,
4597
3692
  allProjects,
4598
3693
  extended.toolingInventory,
4599
3694
  extended.serviceDependencies,
4600
3695
  fileCache
4601
3696
  );
3697
+ extended.architecture = workspace;
4602
3698
  const arch = extended.architecture;
4603
3699
  const layerCount = arch.layers.filter((l) => l.fileCount > 0).length;
4604
- await Promise.all(allProjects.map(async (project) => {
4605
- project.architectureMermaid = await buildProjectArchitectureMermaid(
4606
- rootDir,
4607
- project,
4608
- arch.archetype,
4609
- fileCache
4610
- );
4611
- project.architecture = await scanProjectArchitecture(rootDir, project, fileCache);
4612
- }));
3700
+ for (let i = 0; i < allProjects.length; i++) {
3701
+ const project = allProjects[i];
3702
+ const projectArch = projectResults[i];
3703
+ project.architecture = projectArch;
3704
+ project.architectureMermaid = mermaidFromArchitecture(projectArch);
3705
+ }
4613
3706
  for (const solution of solutions) {
4614
3707
  const memberProjects = solution.projectPaths.map((pp) => projectsByPath.get(pp) ?? projectsByPath.get(path3.dirname(pp).replace(/\\/g, "/"))).filter((p) => Boolean(p));
4615
3708
  const memberArchResults = memberProjects.map((p) => p.architecture).filter((a) => Boolean(a));
4616
3709
  if (memberArchResults.length > 0) {
4617
- solution.architecture = aggregateSolutionArchitecture(memberArchResults);
3710
+ solution.architecture = aggregateSolutionArchitecture(memberArchResults, memberProjects);
4618
3711
  }
4619
3712
  }
4620
3713
  progress.completeStep(
@@ -4664,5 +3757,5 @@ var baselineCommand = new Command("baseline").description("Create a drift baseli
4664
3757
  });
4665
3758
 
4666
3759
  export { baselineCommand, loadAdvancedScanHook, runBaseline };
4667
- //# sourceMappingURL=chunk-TFAXW7VM.js.map
4668
- //# sourceMappingURL=chunk-TFAXW7VM.js.map
3760
+ //# sourceMappingURL=chunk-6K3XK7C5.js.map
3761
+ //# sourceMappingURL=chunk-6K3XK7C5.js.map