@vibgrate/cli 2026.817.2 → 2026.818.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 (153) hide show
  1. package/dist/activity-MF2GNYAI.js +5 -0
  2. package/dist/activity-MF2GNYAI.js.map +1 -0
  3. package/dist/agent-X6VYCE63.js +30 -0
  4. package/dist/{agent-UQC7QN77.js.map → agent-X6VYCE63.js.map} +1 -1
  5. package/dist/{approvals-ASPJQUZK.js → approvals-TPQFQSWG.js} +5 -5
  6. package/dist/{approvals-ASPJQUZK.js.map → approvals-TPQFQSWG.js.map} +1 -1
  7. package/dist/attach-G5JUIWIT.js +10 -0
  8. package/dist/attach-G5JUIWIT.js.map +1 -0
  9. package/dist/baseline-DXI64VLW.js +9 -0
  10. package/dist/{baseline-FIV6PR2M.js.map → baseline-DXI64VLW.js.map} +1 -1
  11. package/dist/{chunk-AXZZ5CCG.js → chunk-2C33WR5O.js} +38 -19
  12. package/dist/chunk-2C33WR5O.js.map +1 -0
  13. package/dist/chunk-4NTNMT6T.js +6 -0
  14. package/dist/{chunk-PRG2ULPK.js.map → chunk-4NTNMT6T.js.map} +1 -1
  15. package/dist/chunk-5IQBIXHS.js +23 -0
  16. package/dist/chunk-5IQBIXHS.js.map +1 -0
  17. package/dist/{chunk-6K3XK7C5.js → chunk-6ABMV74F.js} +6 -3
  18. package/dist/chunk-6ABMV74F.js.map +1 -0
  19. package/dist/chunk-6BEBJCK4.js +467 -0
  20. package/dist/chunk-6BEBJCK4.js.map +1 -0
  21. package/dist/{chunk-E2FAQREZ.js → chunk-6PFHDHOL.js} +174 -401
  22. package/dist/chunk-6PFHDHOL.js.map +1 -0
  23. package/dist/chunk-6WRG7VDO.js +118 -0
  24. package/dist/chunk-6WRG7VDO.js.map +1 -0
  25. package/dist/{chunk-3NJUOIZQ.js → chunk-AEJYA6HZ.js} +5 -5
  26. package/dist/{chunk-3NJUOIZQ.js.map → chunk-AEJYA6HZ.js.map} +1 -1
  27. package/dist/{chunk-O2DL2Q55.js → chunk-B4EXD5LK.js} +5 -5
  28. package/dist/{chunk-O2DL2Q55.js.map → chunk-B4EXD5LK.js.map} +1 -1
  29. package/dist/{chunk-EXV4QSAD.js → chunk-BMOFJIMG.js} +3 -3
  30. package/dist/{chunk-EXV4QSAD.js.map → chunk-BMOFJIMG.js.map} +1 -1
  31. package/dist/chunk-DBX3DL27.js +26 -0
  32. package/dist/chunk-DBX3DL27.js.map +1 -0
  33. package/dist/{chunk-KNGAZDGF.js → chunk-E3O5UKNA.js} +151 -42
  34. package/dist/chunk-E3O5UKNA.js.map +1 -0
  35. package/dist/{chunk-RBIRXQR6.js → chunk-E53WBVUQ.js} +7 -14
  36. package/dist/chunk-E53WBVUQ.js.map +1 -0
  37. package/dist/{chunk-C3LMWZKF.js → chunk-FFXGWFAE.js} +4 -4
  38. package/dist/{chunk-C3LMWZKF.js.map → chunk-FFXGWFAE.js.map} +1 -1
  39. package/dist/chunk-H5Q4JUY4.js +47 -0
  40. package/dist/chunk-H5Q4JUY4.js.map +1 -0
  41. package/dist/{chunk-LHKQGVRF.js → chunk-HF6R73UC.js} +100 -11
  42. package/dist/chunk-HF6R73UC.js.map +1 -0
  43. package/dist/{chunk-K6DXETMC.js → chunk-JGA63RGF.js} +13 -12
  44. package/dist/chunk-JGA63RGF.js.map +1 -0
  45. package/dist/{chunk-3FMRFECC.js → chunk-KU7FI5EV.js} +3 -3
  46. package/dist/{chunk-3FMRFECC.js.map → chunk-KU7FI5EV.js.map} +1 -1
  47. package/dist/{chunk-5OL2TSHK.js → chunk-L2OS4WHT.js} +4 -4
  48. package/dist/{chunk-5OL2TSHK.js.map → chunk-L2OS4WHT.js.map} +1 -1
  49. package/dist/chunk-LJSJX6U4.js +38 -0
  50. package/dist/chunk-LJSJX6U4.js.map +1 -0
  51. package/dist/{chunk-Q4G2BWE3.js → chunk-MRZHNUN7.js} +12 -6
  52. package/dist/chunk-MRZHNUN7.js.map +1 -0
  53. package/dist/chunk-NDNNOAS6.js +16 -0
  54. package/dist/chunk-NDNNOAS6.js.map +1 -0
  55. package/dist/chunk-NJQZRM55.js +100 -0
  56. package/dist/chunk-NJQZRM55.js.map +1 -0
  57. package/dist/{chunk-DVW3SVCW.js → chunk-NKLYDSB7.js} +29 -9
  58. package/dist/chunk-NKLYDSB7.js.map +1 -0
  59. package/dist/{chunk-TVDMNIUT.js → chunk-O5IJDMTB.js} +4 -4
  60. package/dist/{chunk-TVDMNIUT.js.map → chunk-O5IJDMTB.js.map} +1 -1
  61. package/dist/chunk-POOL355F.js +237 -0
  62. package/dist/chunk-POOL355F.js.map +1 -0
  63. package/dist/{chunk-XLXJC7H3.js → chunk-PRHH4DVO.js} +5 -118
  64. package/dist/chunk-PRHH4DVO.js.map +1 -0
  65. package/dist/{chunk-3H3SVJUY.js → chunk-RHKOUPWT.js} +107 -542
  66. package/dist/chunk-RHKOUPWT.js.map +1 -0
  67. package/dist/{chunk-WAKP7SK7.js → chunk-V2UGRUTL.js} +225 -48
  68. package/dist/chunk-V2UGRUTL.js.map +1 -0
  69. package/dist/{chunk-2FEB5KJS.js → chunk-V6WONSIK.js} +5 -4
  70. package/dist/chunk-V6WONSIK.js.map +1 -0
  71. package/dist/{chunk-WVMOGIPC.js → chunk-VMAIDM4K.js} +3 -3
  72. package/dist/{chunk-WVMOGIPC.js.map → chunk-VMAIDM4K.js.map} +1 -1
  73. package/dist/{chunk-GOGMS3ST.js → chunk-VQ5KMHW6.js} +860 -65
  74. package/dist/chunk-VQ5KMHW6.js.map +1 -0
  75. package/dist/{chunk-M7IO3DXH.js → chunk-X2MQ7UFL.js} +250 -30
  76. package/dist/chunk-X2MQ7UFL.js.map +1 -0
  77. package/dist/{chunk-OZ3IFXRD.js → chunk-YENM3HT7.js} +5 -4
  78. package/dist/chunk-YENM3HT7.js.map +1 -0
  79. package/dist/{chunk-KJT2R6WW.js → chunk-YF54UMOU.js} +3 -3
  80. package/dist/{chunk-KJT2R6WW.js.map → chunk-YF54UMOU.js.map} +1 -1
  81. package/dist/{chunk-Q3M6K3HY.js → chunk-ZUOBPKVK.js} +3 -3
  82. package/dist/{chunk-Q3M6K3HY.js.map → chunk-ZUOBPKVK.js.map} +1 -1
  83. package/dist/cli.d.ts +6 -0
  84. package/dist/cli.js +711 -463
  85. package/dist/cli.js.map +1 -1
  86. package/dist/client-UQIELEEZ.js +8 -0
  87. package/dist/client-UQIELEEZ.js.map +1 -0
  88. package/dist/daemon-GUMWMKCA.js +31 -0
  89. package/dist/{daemon-FPTRHO5N.js.map → daemon-GUMWMKCA.js.map} +1 -1
  90. package/dist/embed-worker-main.js +3 -3
  91. package/dist/ensure-map-FHDJTO7Y.js +41 -0
  92. package/dist/{ensure-map-342G2IV3.js.map → ensure-map-FHDJTO7Y.js.map} +1 -1
  93. package/dist/graph-backend-W2D3HRRD.js +16 -0
  94. package/dist/{graph-backend-RNWQBT3P.js.map → graph-backend-W2D3HRRD.js.map} +1 -1
  95. package/dist/index.d.ts +633 -4
  96. package/dist/index.js +26 -17
  97. package/dist/index.js.map +1 -1
  98. package/dist/{interactive-SR7TMF6M.js → interactive-2MK4TLRD.js} +42 -34
  99. package/dist/interactive-2MK4TLRD.js.map +1 -0
  100. package/dist/load-4R4HYMBB.js +11 -0
  101. package/dist/{load-AYFECIQB.js.map → load-4R4HYMBB.js.map} +1 -1
  102. package/dist/parse-worker.js +3 -2
  103. package/dist/parse-worker.js.map +1 -1
  104. package/dist/publish-7YHRTBRA.js +9 -0
  105. package/dist/publish-7YHRTBRA.js.map +1 -0
  106. package/dist/{run-outcome-YQQJG3LW.js → run-outcome-H5GVDDZJ.js} +5 -5
  107. package/dist/{run-outcome-YQQJG3LW.js.map → run-outcome-H5GVDDZJ.js.map} +1 -1
  108. package/dist/runtime-session-JBIHHH5N.js +27 -0
  109. package/dist/{runtime-session-CNJ4DAV5.js.map → runtime-session-JBIHHH5N.js.map} +1 -1
  110. package/dist/semantic-status-2JFLIQQJ.js +4 -0
  111. package/dist/semantic-status-2JFLIQQJ.js.map +1 -0
  112. package/dist/{session-H34HUV2Y.js → session-N5IU4K5Q.js} +8 -8
  113. package/dist/{session-H34HUV2Y.js.map → session-N5IU4K5Q.js.map} +1 -1
  114. package/dist/slot-subscription-25GOARW5.js +95 -0
  115. package/dist/slot-subscription-25GOARW5.js.map +1 -0
  116. package/dist/{stream-json-55YDNAFX.js → stream-json-4WLSUF6I.js} +18 -15
  117. package/dist/stream-json-4WLSUF6I.js.map +1 -0
  118. package/dist/version-DTEU3SQD.js +4 -0
  119. package/dist/{version-WSE3QOPK.js.map → version-DTEU3SQD.js.map} +1 -1
  120. package/dist/{vg-mcp-bridge-2CNLHNEL.js → vg-mcp-bridge-KDVYIMFX.js} +12 -11
  121. package/dist/vg-mcp-bridge-KDVYIMFX.js.map +1 -0
  122. package/dist/{vgd-URUZQORN.js → vgd-M7UOPWLB.js} +15 -10
  123. package/dist/vgd-M7UOPWLB.js.map +1 -0
  124. package/package.json +1 -1
  125. package/dist/agent-UQC7QN77.js +0 -27
  126. package/dist/baseline-FIV6PR2M.js +0 -9
  127. package/dist/chunk-2FEB5KJS.js.map +0 -1
  128. package/dist/chunk-3H3SVJUY.js.map +0 -1
  129. package/dist/chunk-6K3XK7C5.js.map +0 -1
  130. package/dist/chunk-AXZZ5CCG.js.map +0 -1
  131. package/dist/chunk-DVW3SVCW.js.map +0 -1
  132. package/dist/chunk-E2FAQREZ.js.map +0 -1
  133. package/dist/chunk-GOGMS3ST.js.map +0 -1
  134. package/dist/chunk-K6DXETMC.js.map +0 -1
  135. package/dist/chunk-KNGAZDGF.js.map +0 -1
  136. package/dist/chunk-LHKQGVRF.js.map +0 -1
  137. package/dist/chunk-M7IO3DXH.js.map +0 -1
  138. package/dist/chunk-OZ3IFXRD.js.map +0 -1
  139. package/dist/chunk-PRG2ULPK.js +0 -6
  140. package/dist/chunk-Q4G2BWE3.js.map +0 -1
  141. package/dist/chunk-RBIRXQR6.js.map +0 -1
  142. package/dist/chunk-WAKP7SK7.js.map +0 -1
  143. package/dist/chunk-XLXJC7H3.js.map +0 -1
  144. package/dist/daemon-FPTRHO5N.js +0 -26
  145. package/dist/ensure-map-342G2IV3.js +0 -33
  146. package/dist/graph-backend-RNWQBT3P.js +0 -15
  147. package/dist/interactive-SR7TMF6M.js.map +0 -1
  148. package/dist/load-AYFECIQB.js +0 -11
  149. package/dist/runtime-session-CNJ4DAV5.js +0 -22
  150. package/dist/stream-json-55YDNAFX.js.map +0 -1
  151. package/dist/version-WSE3QOPK.js +0 -4
  152. package/dist/vg-mcp-bridge-2CNLHNEL.js.map +0 -1
  153. package/dist/vgd-URUZQORN.js.map +0 -1
@@ -8009,6 +8009,7 @@ function formatArchitectureDiagram(arch) {
8009
8009
  lines.push("");
8010
8010
  if (arch.layers.length > 0) {
8011
8011
  for (const layer of arch.layers) {
8012
+ if (layer.fileCount === 0) continue;
8012
8013
  const risk = layer.riskLevel === "none" ? chalk3.dim("none") : layer.riskLevel === "low" ? chalk3.green("low") : layer.riskLevel === "moderate" ? chalk3.yellow("moderate") : chalk3.red("high");
8013
8014
  lines.push(` ${chalk3.bold(layer.layer)} ${layer.fileCount} file${layer.fileCount !== 1 ? "s" : ""} drift ${scoreBar(layer.driftScore)} risk ${risk}`);
8014
8015
  }
@@ -8016,12 +8017,27 @@ function formatArchitectureDiagram(arch) {
8016
8017
  }
8017
8018
  if (arch.violations && arch.violations.length > 0) {
8018
8019
  const extra = arch.violationsCapped ? "+" : "";
8019
- lines.push(` Boundary violations (${arch.violations.length}${extra})`);
8020
- for (const v of arch.violations.slice(0, 8)) {
8021
- lines.push(` ${v.fromFile} \u2192 ${v.toFile} ${v.rule}`);
8020
+ const boundary = arch.violations.filter((v) => !v.rule.startsWith("graph-conflict:"));
8021
+ const conflicts = arch.violations.filter((v) => v.rule.startsWith("graph-conflict:"));
8022
+ if (boundary.length > 0) {
8023
+ const cap = extra && conflicts.length === 0 ? extra : "";
8024
+ lines.push(` Boundary violations (${boundary.length}${cap})`);
8025
+ for (const v of boundary.slice(0, 8)) {
8026
+ lines.push(` ${v.fromFile} \u2192 ${v.toFile} ${v.rule}`);
8027
+ }
8028
+ if (boundary.length > 8) {
8029
+ lines.push(chalk3.dim(` + ${boundary.length - 8} more`));
8030
+ }
8022
8031
  }
8023
- if (arch.violations.length > 8) {
8024
- lines.push(chalk3.dim(` + ${arch.violations.length - 8} more`));
8032
+ if (conflicts.length > 0) {
8033
+ const cap = extra ? extra : "";
8034
+ lines.push(` Layer conflicts (${conflicts.length}${cap})`);
8035
+ for (const v of conflicts.slice(0, 8)) {
8036
+ lines.push(` ${v.fromFile} \u2192 ${v.toFile} ${v.rule}`);
8037
+ }
8038
+ if (conflicts.length > 8) {
8039
+ lines.push(chalk3.dim(` + ${conflicts.length - 8} more`));
8040
+ }
8025
8041
  }
8026
8042
  lines.push("");
8027
8043
  }
@@ -12278,7 +12294,10 @@ var projectKindPacks = [
12278
12294
  const named = /(^|\/)(worker|workers|jobs)(\/|$)/.test(ctx.projectPath.replace(/\\/g, "/"));
12279
12295
  const layout = filePathHas(ctx, /(^|\/)(workers|jobs)\//) && !filePathHas(ctx, /(^|\/)(controllers|pages|app\/)\//);
12280
12296
  if (!dep && !named && !layout) return [];
12281
- if (filePathHas(ctx, /(^|\/)(pages|app\/.*page\.)/)) return [];
12297
+ if (filePathHas(ctx, /(^|\/)(pages|app\/.*page\.|app\/views\/|app\/controllers\/)/)) return [];
12298
+ if (hasPackage(ctx, "rails", "django", "laravel", "next", "@next/core", "@nestjs/core", "fastapi", "phoenix")) {
12299
+ return [];
12300
+ }
12282
12301
  return [evidenceOf("project-kind/worker", "projectKind", "worker", dep || named ? 0.8 : 0.62, named ? ["worker-path"] : ["worker-signal"])];
12283
12302
  }
12284
12303
  },
@@ -12386,6 +12405,30 @@ function folderConflictSignal(layer) {
12386
12405
  function folderInheritSignal(layer) {
12387
12406
  return `folder-inherit:${layer}`;
12388
12407
  }
12408
+ function isToolingConfigFile(filePath) {
12409
+ const base = normalizeRelPath(filePath).split("/").pop()?.toLowerCase() ?? "";
12410
+ return /\.config\.[cm]?[jt]sx?$/.test(base);
12411
+ }
12412
+ function isTestFilePath(filePath) {
12413
+ const n = `/${normalizeRelPath(filePath).toLowerCase()}`;
12414
+ return /\/(__tests__|__mocks__|tests?|spec|fixtures)\//.test(n) || /\.(tests?|spec)\.[^./]+$/.test(n) || /_(test|spec)\.[^./]+$/.test(n) || /\/(conftest|test_[^/]*)\.py$/.test(n);
12415
+ }
12416
+ function folderLooksLikeTests(dir) {
12417
+ const n = `/${normalizeRelPath(dir).toLowerCase()}/`;
12418
+ return /\/(__tests__|__mocks__|tests?|spec|fixtures)\//.test(n);
12419
+ }
12420
+ function folderLooksLikeConfig(dir) {
12421
+ const n = `/${normalizeRelPath(dir).toLowerCase()}/`;
12422
+ return /\/(config|properties)\//.test(n);
12423
+ }
12424
+ function folderLayerAppliesToFile(layer, filePath) {
12425
+ if (layer === "testing") return isTestFilePath(filePath);
12426
+ if (layer === "config") {
12427
+ const parent = parentDir(filePath);
12428
+ return folderLooksLikeConfig(parent) || /\/(config|env|bootstrap|setup)\.[^./]+$/i.test(`/${normalizeRelPath(filePath)}`);
12429
+ }
12430
+ return true;
12431
+ }
12389
12432
  function normalizeRelPath(p) {
12390
12433
  return (p || ".").replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "") || ".";
12391
12434
  }
@@ -12439,6 +12482,7 @@ function applyFolderInheritance(input) {
12439
12482
  }
12440
12483
  const classifiedByParent = /* @__PURE__ */ new Map();
12441
12484
  for (const c of classified) {
12485
+ if (isToolingConfigFile(c.filePath)) continue;
12442
12486
  const parent = parentDir(c.filePath);
12443
12487
  const list = classifiedByParent.get(parent);
12444
12488
  if (list) list.push(c);
@@ -12464,6 +12508,8 @@ function applyFolderInheritance(input) {
12464
12508
  if (!winner) continue;
12465
12509
  const share = winnerCount / children.length;
12466
12510
  if (share < FOLDER_LAYER_MIN_SHARE || winnerCount < FOLDER_LAYER_MIN_COUNT) continue;
12511
+ if (winner === "testing" && !folderLooksLikeTests(dir)) continue;
12512
+ if (winner === "config" && !folderLooksLikeConfig(dir)) continue;
12467
12513
  votes.set(dir, {
12468
12514
  path: dir,
12469
12515
  layer: winner,
@@ -12483,6 +12529,8 @@ function applyFolderInheritance(input) {
12483
12529
  if (ancestor === dir || ancestor === ".") continue;
12484
12530
  const parent = votes.get(ancestor);
12485
12531
  if (!parent) continue;
12532
+ if (parent.layer === "testing" && !folderLooksLikeTests(dir)) continue;
12533
+ if (parent.layer === "config" && !folderLooksLikeConfig(dir)) continue;
12486
12534
  votes.set(dir, {
12487
12535
  path: dir,
12488
12536
  layer: parent.layer,
@@ -12503,7 +12551,7 @@ function applyFolderInheritance(input) {
12503
12551
  const stillUnclassified = [];
12504
12552
  for (const file of unclassified) {
12505
12553
  const folder = nearestFolder3(file);
12506
- if (folder && folder.confidence >= FOLDER_INHERIT_MIN_CONFIDENCE) {
12554
+ if (folder && folder.confidence >= FOLDER_INHERIT_MIN_CONFIDENCE && folderLayerAppliesToFile(folder.layer, file)) {
12507
12555
  classified.push({
12508
12556
  filePath: file,
12509
12557
  layer: folder.layer,
@@ -12771,7 +12819,7 @@ var PATH_RULES = [
12771
12819
  { pattern: /\.pipe\.[jt]sx?$/, layer: "middleware", confidence: 0.85, signal: "NestJS pipe", archetypes: ["nestjs"] },
12772
12820
  { pattern: /\.middleware\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "NestJS middleware", archetypes: ["nestjs"] },
12773
12821
  { pattern: /\.entity\.[jt]sx?$/, layer: "domain", confidence: 0.9, signal: "NestJS entity", archetypes: ["nestjs"] },
12774
- { pattern: /\.dto\.[jt]sx?$/, layer: "domain", confidence: 0.85, signal: "NestJS DTO", archetypes: ["nestjs"] },
12822
+ { pattern: /\.dto\.[jt]sx?$/, layer: "services", confidence: 0.85, signal: "NestJS DTO", archetypes: ["nestjs"] },
12775
12823
  { pattern: /\.repository\.[jt]sx?$/, layer: "data-access", confidence: 0.9, signal: "NestJS repository", archetypes: ["nestjs"] },
12776
12824
  // ── Generic routing patterns ──
12777
12825
  { pattern: /\/routes\//, layer: "routing", confidence: 0.8, signal: "routes/ directory" },
@@ -12783,7 +12831,7 @@ var PATH_RULES = [
12783
12831
  // ── Middleware ──
12784
12832
  { pattern: /\/middleware\//, layer: "middleware", confidence: 0.85, signal: "middleware/ directory" },
12785
12833
  { pattern: /\/middlewares\//, layer: "middleware", confidence: 0.85, signal: "middlewares/ directory" },
12786
- { pattern: /\/hooks\//, layer: "middleware", confidence: 0.6, signal: "hooks/ directory" },
12834
+ { pattern: /\/hooks\//, layer: "presentation", confidence: 0.75, signal: "hooks/ directory (UI)" },
12787
12835
  { pattern: /\/plugins\//, layer: "middleware", confidence: 0.6, signal: "plugins/ directory" },
12788
12836
  { pattern: /\/guards\//, layer: "middleware", confidence: 0.85, signal: "guards/ directory" },
12789
12837
  { pattern: /\/interceptors\//, layer: "middleware", confidence: 0.85, signal: "interceptors/ directory" },
@@ -12871,7 +12919,7 @@ var PATH_RULES = [
12871
12919
  { pattern: /\/resource\//, layer: "routing", confidence: 0.7, signal: "resource/ package (JAX-RS)" },
12872
12920
  { pattern: /\/model\//, layer: "domain", confidence: 0.75, signal: "model/ package" },
12873
12921
  { pattern: /\/entity\//, layer: "domain", confidence: 0.85, signal: "entity/ package" },
12874
- { pattern: /\/dto\//, layer: "domain", confidence: 0.85, signal: "dto/ package" },
12922
+ { pattern: /\/dto\//, layer: "services", confidence: 0.85, signal: "dto/ package" },
12875
12923
  { pattern: /\/mappers?\//, layer: "data-access", confidence: 0.75, signal: "mapper/ package" },
12876
12924
  // ── Python (Django/Flask/FastAPI module conventions) ──
12877
12925
  { pattern: /\/(test_[^/]*|conftest)\.py$/, layer: "testing", confidence: 0.95, signal: "pytest test module" },
@@ -12914,7 +12962,9 @@ var SUFFIX_RULES = [
12914
12962
  { suffix: ".usecase", layer: "services", confidence: 0.85, signal: "usecase suffix" },
12915
12963
  { suffix: ".model", layer: "domain", confidence: 0.8, signal: "model suffix" },
12916
12964
  { suffix: ".entity", layer: "domain", confidence: 0.85, signal: "entity suffix" },
12917
- { suffix: ".dto", layer: "domain", confidence: 0.8, signal: "DTO suffix" },
12965
+ { suffix: ".dto", layer: "services", confidence: 0.85, signal: "DTO suffix" },
12966
+ { suffix: ".request", layer: "services", confidence: 0.85, signal: "request DTO suffix" },
12967
+ { suffix: ".response", layer: "services", confidence: 0.85, signal: "response DTO suffix" },
12918
12968
  { suffix: ".schema", layer: "domain", confidence: 0.75, signal: "schema suffix" },
12919
12969
  { suffix: ".validator", layer: "domain", confidence: 0.75, signal: "validator suffix" },
12920
12970
  { suffix: ".repository", layer: "data-access", confidence: 0.9, signal: "repository suffix" },
@@ -12942,7 +12992,12 @@ var PASCAL_SUFFIX_RULES = [
12942
12992
  { suffix: "Handler", layer: "services", confidence: 0.75, signal: "Handler class" },
12943
12993
  { suffix: "UseCase", layer: "services", confidence: 0.85, signal: "UseCase class" },
12944
12994
  { suffix: "Entity", layer: "domain", confidence: 0.85, signal: "Entity class" },
12945
- { suffix: "Dto", layer: "domain", confidence: 0.8, signal: "DTO class" },
12995
+ { suffix: "Dto", layer: "services", confidence: 0.85, signal: "DTO class" },
12996
+ { suffix: "DTO", layer: "services", confidence: 0.85, signal: "DTO class" },
12997
+ { suffix: "Request", layer: "services", confidence: 0.85, signal: "request DTO class" },
12998
+ { suffix: "Response", layer: "services", confidence: 0.85, signal: "response DTO class" },
12999
+ { suffix: "Command", layer: "services", confidence: 0.8, signal: "Command class" },
13000
+ { suffix: "Query", layer: "services", confidence: 0.8, signal: "Query class" },
12946
13001
  { suffix: "Validator", layer: "domain", confidence: 0.75, signal: "Validator class" },
12947
13002
  { suffix: "ViewModel", layer: "presentation", confidence: 0.85, signal: "ViewModel class" },
12948
13003
  { suffix: "Repository", layer: "data-access", confidence: 0.9, signal: "Repository class" },
@@ -12968,7 +13023,12 @@ var PASCAL_SUFFIX_RULES = [
12968
13023
  { suffix: "Screen", layer: "presentation", confidence: 0.85, signal: "Screen widget" },
12969
13024
  { suffix: "Widget", layer: "presentation", confidence: 0.75, signal: "Widget class" }
12970
13025
  ];
12971
- function classifyFile(filePath, archetype) {
13026
+ var UI_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".vue", ".svelte"]);
13027
+ function isDomainRepositoryPort(baseName, loweredPath) {
13028
+ if (!/^I[A-Z]\w*(Repository|Repo)$/.test(baseName)) return false;
13029
+ return /\/(domain|interfaces)\//.test(loweredPath);
13030
+ }
13031
+ function classifyOne(filePath, archetype) {
12972
13032
  const normalised = "/" + filePath.replace(/\\/g, "/").replace(/^\/+/, "");
12973
13033
  const lowered = normalised.toLowerCase();
12974
13034
  let bestMatch = null;
@@ -13000,15 +13060,48 @@ function classifyFile(filePath, archetype) {
13000
13060
  }
13001
13061
  }
13002
13062
  }
13003
- if (bestMatch) {
13004
- return {
13005
- filePath,
13006
- layer: bestMatch.layer,
13007
- confidence: bestMatch.confidence,
13008
- signals: [bestMatch.signal]
13009
- };
13063
+ if (isDomainRepositoryPort(cleanBase, lowered)) {
13064
+ const port = { layer: "domain", confidence: 0.93, signal: "domain repository port" };
13065
+ if (!bestMatch || port.confidence >= bestMatch.confidence || bestMatch.layer === "data-access") {
13066
+ bestMatch = port;
13067
+ }
13010
13068
  }
13011
- return null;
13069
+ if (bestMatch && (bestMatch.layer === "routing" || bestMatch.layer === "services") && /\/(model|entity|entities)\//.test(lowered) && /(Controller|Request|Response|Dto|DTO)$/.test(cleanBase)) {
13070
+ bestMatch = { layer: "domain", confidence: 0.88, signal: "entity folder beats type suffix" };
13071
+ }
13072
+ if (!bestMatch) {
13073
+ const ext = path31.extname(filePath).toLowerCase();
13074
+ if (UI_SOURCE_EXTENSIONS.has(ext)) {
13075
+ bestMatch = { layer: "presentation", confidence: 0.62, signal: "ui source extension" };
13076
+ }
13077
+ }
13078
+ return bestMatch;
13079
+ }
13080
+ var LAYER_HINT_SEGMENT = /(?:^|\/)(application|domain|infrastructure|persistence|entities)(?:\/|$)/i;
13081
+ function prefixHasLayerHint(repoRelative, localPath) {
13082
+ const repo = repoRelative.replace(/\\/g, "/").replace(/^\/+/, "");
13083
+ const local = localPath.replace(/\\/g, "/").replace(/^\/+/, "");
13084
+ if (!repo.endsWith(local)) return false;
13085
+ const prefix = repo.slice(0, repo.length - local.length).replace(/\/+$/, "");
13086
+ return prefix.length > 0 && LAYER_HINT_SEGMENT.test(`/${prefix}/`);
13087
+ }
13088
+ function classifyFile(filePath, archetype, opts) {
13089
+ const local = classifyOne(filePath, archetype);
13090
+ const repoPath = opts?.repoRelative?.replace(/\\/g, "/");
13091
+ const repo = repoPath && repoPath !== filePath.replace(/\\/g, "/") && prefixHasLayerHint(repoPath, filePath) ? classifyOne(repoPath, archetype) : null;
13092
+ let best = local;
13093
+ let usedHint = false;
13094
+ if (repo && (!local || repo.confidence > local.confidence)) {
13095
+ best = repo;
13096
+ usedHint = true;
13097
+ }
13098
+ if (!best) return null;
13099
+ return {
13100
+ filePath,
13101
+ layer: best.layer,
13102
+ confidence: best.confidence,
13103
+ signals: usedHint ? [best.signal, "project-path-hint"] : [best.signal]
13104
+ };
13012
13105
  }
13013
13106
 
13014
13107
  // src/core-open/scanners/architecture/graph-refine.ts
@@ -13153,27 +13246,31 @@ function indexGraph(graph) {
13153
13246
  else fileNodes.set(file, [node.id]);
13154
13247
  }
13155
13248
  const outboundImport = /* @__PURE__ */ new Map();
13156
- const inboundCall = /* @__PURE__ */ new Map();
13157
13249
  for (const edge of graph.edges) {
13158
13250
  if (IGNORE_EDGE_KINDS.has(edge.kind)) continue;
13159
- if (edge.kind !== "import" && edge.kind !== "call") continue;
13251
+ if (edge.kind !== "import") continue;
13160
13252
  const srcFile = nodeFile.get(edge.src);
13161
13253
  const dstFile = nodeFile.get(edge.dst);
13162
13254
  if (!srcFile || !dstFile || srcFile === dstFile) continue;
13163
- if (edge.kind === "import") pushEdge(outboundImport, srcFile, edge);
13164
- else pushEdge(inboundCall, dstFile, edge);
13255
+ pushEdge(outboundImport, srcFile, edge);
13165
13256
  }
13166
- return { nodeFile, fileNodes, outboundImport, inboundCall };
13257
+ return { nodeFile, fileNodes, outboundImport };
13258
+ }
13259
+ function countsTowardDisagreement(from, to) {
13260
+ if (EXEMPT_LAYERS.has(from) || EXEMPT_LAYERS.has(to)) return false;
13261
+ return from === "domain" && (to === "data-access" || to === "infrastructure");
13167
13262
  }
13168
13263
  function neighbourhoodVotes(filePath, index, stateOf) {
13169
13264
  const votes = [];
13170
13265
  const seen = /* @__PURE__ */ new Set();
13171
- const consider = (neighbour, edge) => {
13172
- if (!neighbour || neighbour === filePath) return;
13266
+ for (const edge of index.outboundImport.get(filePath) ?? []) {
13267
+ const neighbour = index.nodeFile.get(edge.dst);
13268
+ if (!neighbour || neighbour === filePath) continue;
13173
13269
  const neighbourState = stateOf(neighbour);
13174
- if (!neighbourState.layer) return;
13270
+ if (!neighbourState.layer) continue;
13271
+ if (EXEMPT_LAYERS.has(neighbourState.layer)) continue;
13175
13272
  const key = `${edge.kind}|${neighbour}|${neighbourState.layer}`;
13176
- if (seen.has(key)) return;
13273
+ if (seen.has(key)) continue;
13177
13274
  seen.add(key);
13178
13275
  votes.push({
13179
13276
  layer: neighbourState.layer,
@@ -13181,12 +13278,6 @@ function neighbourhoodVotes(filePath, index, stateOf) {
13181
13278
  kind: edge.kind,
13182
13279
  resolution: edge.resolution ?? "unknown"
13183
13280
  });
13184
- };
13185
- for (const edge of index.outboundImport.get(filePath) ?? []) {
13186
- consider(index.nodeFile.get(edge.dst), edge);
13187
- }
13188
- for (const edge of index.inboundCall.get(filePath) ?? []) {
13189
- consider(index.nodeFile.get(edge.src), edge);
13190
13281
  }
13191
13282
  return votes;
13192
13283
  }
@@ -13316,13 +13407,6 @@ function isSliceInternal(filePath) {
13316
13407
  return !/^(index|public|api|mod)\.[^./]+$/i.test(base);
13317
13408
  }
13318
13409
  function isIllegalEdge(profile, from, to, fromFile, toFile) {
13319
- if (from === to) return { illegal: false, rule: "" };
13320
- if (CLEAN_PROFILES.has(profile)) {
13321
- if (from === "domain" && (to === "data-access" || to === "infrastructure")) {
13322
- return { illegal: true, rule: `${profile}:domain\u2192${to}` };
13323
- }
13324
- return { illegal: false, rule: "" };
13325
- }
13326
13410
  if (profile === "vertical-slice") {
13327
13411
  const fromSlice = sliceOf(fromFile);
13328
13412
  const toSlice = sliceOf(toFile);
@@ -13331,8 +13415,19 @@ function isIllegalEdge(profile, from, to, fromFile, toFile) {
13331
13415
  }
13332
13416
  return { illegal: false, rule: "" };
13333
13417
  }
13418
+ if (from === to) return { illegal: false, rule: "" };
13419
+ if (CLEAN_PROFILES.has(profile)) {
13420
+ if (from === "domain" && (to === "data-access" || to === "infrastructure")) {
13421
+ return { illegal: true, rule: `${profile}:domain\u2192${to}` };
13422
+ }
13423
+ return { illegal: false, rule: "" };
13424
+ }
13334
13425
  if (profile === "layered" || profile === "mvc" || profile === "mvvm") {
13335
13426
  if (EXEMPT_LAYERS.has(from) || EXEMPT_LAYERS.has(to)) return { illegal: false, rule: "" };
13427
+ if (to === "domain") return { illegal: false, rule: "" };
13428
+ if (from === "domain" && (to === "data-access" || to === "infrastructure")) {
13429
+ return { illegal: true, rule: `${profile}:domain\u2192${to}` };
13430
+ }
13336
13431
  const a = LAYERED_RANK.get(from);
13337
13432
  const b = LAYERED_RANK.get(to);
13338
13433
  if (a === void 0 || b === void 0) return { illegal: false, rule: "" };
@@ -13341,6 +13436,31 @@ function isIllegalEdge(profile, from, to, fromFile, toFile) {
13341
13436
  }
13342
13437
  return { illegal: false, rule: "" };
13343
13438
  }
13439
+ function boundaryProfileRules(profile) {
13440
+ if (!profile) return [];
13441
+ if (CLEAN_PROFILES.has(profile)) {
13442
+ return [
13443
+ "domain must not depend on data-access",
13444
+ "domain must not depend on infrastructure"
13445
+ ];
13446
+ }
13447
+ if (profile === "vertical-slice") {
13448
+ return [
13449
+ "a slice must not import another slice's internals",
13450
+ "cross-slice imports must go through an entry point (index, public, api, mod)"
13451
+ ];
13452
+ }
13453
+ if (profile === "layered" || profile === "mvc" || profile === "mvvm") {
13454
+ return [
13455
+ `outer layers flow one way: ${LAYERED_STACK.filter((l) => l !== "domain").join(" \u2192 ")}`,
13456
+ "data-access and infrastructure may depend on domain (entities / ports)",
13457
+ "domain must not depend on data-access or infrastructure",
13458
+ "no upward dependency toward presentation / routing",
13459
+ `exempt from the check: ${[...EXEMPT_LAYERS].join(", ")}`
13460
+ ];
13461
+ }
13462
+ return [];
13463
+ }
13344
13464
  function sameOwningProject(fromFile, toFile, projectPath, projects) {
13345
13465
  if (projects.length > 0) {
13346
13466
  const paths = projects.map((p) => p.path);
@@ -13412,6 +13532,7 @@ function applyConfirmation(result, graph, projectPath, index) {
13412
13532
  addFolderSignal(result, file, GRAPH_OVERRIDE_SIGNAL);
13413
13533
  continue;
13414
13534
  }
13535
+ if (!countsTowardDisagreement(state.layer, majority.layer)) continue;
13415
13536
  const conflictSignal = `${GRAPH_CONFLICT_SIGNAL_PREFIX}${majority.layer}`;
13416
13537
  state.signals = sortedSignals2([...state.signals, conflictSignal, ...extra]);
13417
13538
  addFolderSignal(result, file, conflictSignal);
@@ -13795,6 +13916,39 @@ function applyAstRoles(result, hits, opts = {}) {
13795
13916
  applied = true;
13796
13917
  continue;
13797
13918
  }
13919
+ const astOverridesSuffix = hit.role === "entity" && (state.layer === "routing" || state.layer === "presentation");
13920
+ if (astOverridesSuffix) {
13921
+ const previous = state.layer;
13922
+ const fromSummary = result.layers.find((l) => l.layer === previous);
13923
+ if (fromSummary) {
13924
+ const n = normalizeRelPath4(hit.filePath);
13925
+ const next = fromSummary.files.filter((f) => normalizeRelPath4(f) !== n);
13926
+ if (next.length !== fromSummary.files.length && fromSummary.fileCount > 0) {
13927
+ fromSummary.fileCount -= 1;
13928
+ }
13929
+ fromSummary.files = next;
13930
+ }
13931
+ state.layer = hit.layer;
13932
+ state.confidence = hit.confidence;
13933
+ const signals2 = sortedSignals3([
13934
+ ...state.signals,
13935
+ ...already?.signals ?? [],
13936
+ `${AST_ROLE_SIGNAL_PREFIX}${hit.role}`,
13937
+ "ast-overrides-suffix",
13938
+ hit.signal
13939
+ ]);
13940
+ classified.set(hit.filePath, {
13941
+ filePath: hit.filePath,
13942
+ layer: hit.layer,
13943
+ confidence: hit.confidence,
13944
+ signals: signals2,
13945
+ role: hit.role
13946
+ });
13947
+ addFileToLayer2(ensureLayer2(result, hit.layer), hit.filePath);
13948
+ addFolderSignal2(result, hit.filePath, `${AST_ROLE_SIGNAL_PREFIX}${hit.role}`);
13949
+ applied = true;
13950
+ continue;
13951
+ }
13798
13952
  const keepConfidence = state.confidence;
13799
13953
  const signals = sortedSignals3([
13800
13954
  ...state.signals,
@@ -13920,7 +14074,10 @@ var FRAMEWORK_TO_ARCHETYPE = {
13920
14074
  spring: "spring",
13921
14075
  aspnet: "aspnet",
13922
14076
  django: "django",
13923
- fastapi: "fastapi"
14077
+ fastapi: "fastapi",
14078
+ rails: "rails",
14079
+ laravel: "laravel",
14080
+ phoenix: "phoenix"
13924
14081
  };
13925
14082
  var FRAMEWORK_TO_PROJECT_KIND = {
13926
14083
  nextjs: "web-app",
@@ -14027,6 +14184,16 @@ function inferWorkspaceShape(projects) {
14027
14184
  const types = new Set(apps.map((p) => p.type));
14028
14185
  return types.size >= 2 ? "polyglot-platform" : "monorepo";
14029
14186
  }
14187
+ function residualProject(seed) {
14188
+ return {
14189
+ type: seed?.type ?? "node",
14190
+ path: ".",
14191
+ name: "",
14192
+ frameworks: [],
14193
+ dependencies: [],
14194
+ dependencyAgeBuckets: { current: 0, oneBehind: 0, twoPlusBehind: 0, unknown: 0 }
14195
+ };
14196
+ }
14030
14197
  function compareRelPath4(a, b) {
14031
14198
  return a.replace(/\\/g, "/").localeCompare(b.replace(/\\/g, "/"));
14032
14199
  }
@@ -14678,6 +14845,16 @@ async function scanArchitectureBundle(rootDir, projects, tooling, services, cach
14678
14845
  }));
14679
14846
  const projectResults = projects.map((p) => resultByPath.get(normalizeRelPath5(p.path)));
14680
14847
  const uniqueResults = [...resultByPath.values()];
14848
+ const ownerPaths = owners.map((o) => normalizeRelPath5(o.path));
14849
+ if (!ownerPaths.includes(".")) {
14850
+ const residual = await classifyTree(rootDir, [residualProject(owners[0])], tooling, services, cache, {
14851
+ projectPath: ".",
14852
+ workspacePaths: [...ownerPaths, "."]
14853
+ });
14854
+ if (residual.totalClassified > 0 || residual.unclassified > 0) {
14855
+ uniqueResults.push(residual);
14856
+ }
14857
+ }
14681
14858
  const workspace = finalizeWorkspace(uniqueResults, projects, tooling, services);
14682
14859
  const siblingEdges = detectWorkspaceEdges(projects, projectResults);
14683
14860
  const mergedEdges = [
@@ -14724,7 +14901,7 @@ async function classifyTree(rootDir, projects, tooling, services, cache, scope)
14724
14901
  for (const file of sourceFiles) {
14725
14902
  if (!isLayerCandidate(file) || skipAllLayers) continue;
14726
14903
  const storedPath = scope ? toRepoRelative(scope.projectPath, file) : file;
14727
- const classification = classifyFile(file, archetype);
14904
+ const classification = classifyFile(file, archetype, { repoRelative: storedPath });
14728
14905
  if (classification) {
14729
14906
  seedClassified.push({ ...classification, filePath: storedPath });
14730
14907
  } else {
@@ -15607,6 +15784,6 @@ async function computeTreeMetadataHash(rootDir, options) {
15607
15784
  return digest.digest("hex");
15608
15785
  }
15609
15786
 
15610
- export { PROJECT_TYPE_TO_OSV_ECOSYSTEM, aggregateSolutionArchitecture, brandProgressBar, buildVersionTimelines, compactUiPurpose, computeDriftScore, computeRepoFingerprint, computeUpgradeImpact, detectVcs, driftBar, fetchRiskySymbols, fetchScanPreflight, findPackageAnyEcosystem, findPackageTimeline, findVersionCrossings, getChangelogSignals, gitHistoryAvailable, loadConfig, mermaidFromArchitecture, normalizeConstraint, parseDsn, perDependencyDrift, prepareCompressedUpload, projectTypeToVulnEcosystem, refineArchitectureWithAstRoles, refineArchitectureWithGraph, resolveHead, resolveRepositoryName, runCoreScan, scanArchitectureBundle, severityRank, titleBox, versionSatisfies, workingTreeDirty, writeDefaultConfig };
15611
- //# sourceMappingURL=chunk-WAKP7SK7.js.map
15612
- //# sourceMappingURL=chunk-WAKP7SK7.js.map
15787
+ export { PROJECT_TYPE_TO_OSV_ECOSYSTEM, aggregateSolutionArchitecture, boundaryProfileRules, brandProgressBar, buildVersionTimelines, compactUiPurpose, computeDriftScore, computeRepoFingerprint, computeUpgradeImpact, detectVcs, driftBar, fetchRiskySymbols, fetchScanPreflight, findPackageAnyEcosystem, findPackageTimeline, findVersionCrossings, getChangelogSignals, gitHistoryAvailable, loadConfig, mermaidFromArchitecture, normalizeConstraint, parseDsn, perDependencyDrift, prepareCompressedUpload, projectTypeToVulnEcosystem, refineArchitectureWithAstRoles, refineArchitectureWithGraph, resolveHead, resolveRepositoryName, runCoreScan, scanArchitectureBundle, severityRank, titleBox, versionSatisfies, workingTreeDirty, writeDefaultConfig };
15788
+ //# sourceMappingURL=chunk-V2UGRUTL.js.map
15789
+ //# sourceMappingURL=chunk-V2UGRUTL.js.map