@vibgrate/cli 2026.819.1 → 2026.819.3

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 (171) hide show
  1. package/DOCS.md +3 -3
  2. package/dist/agent-AFMDB4GM.js +30 -0
  3. package/dist/{agent-3CKNTCRX.js.map → agent-AFMDB4GM.js.map} +1 -1
  4. package/dist/{approvals-DHTG3HI4.js → approvals-F2DJGPU7.js} +7 -7
  5. package/dist/{approvals-DHTG3HI4.js.map → approvals-F2DJGPU7.js.map} +1 -1
  6. package/dist/attach-XTX2Q3AD.js +10 -0
  7. package/dist/{attach-OCQ3I76L.js.map → attach-XTX2Q3AD.js.map} +1 -1
  8. package/dist/baseline-KTE2C3LW.js +9 -0
  9. package/dist/{baseline-QDC6OQ2X.js.map → baseline-KTE2C3LW.js.map} +1 -1
  10. package/dist/{chunk-D33M2ARL.js → chunk-3SOJZ3VV.js} +3 -3
  11. package/dist/{chunk-D33M2ARL.js.map → chunk-3SOJZ3VV.js.map} +1 -1
  12. package/dist/{chunk-JGBOYZAF.js → chunk-3XMTRK24.js} +99 -19
  13. package/dist/chunk-3XMTRK24.js.map +1 -0
  14. package/dist/{chunk-OV4KGXPD.js → chunk-57ZRSCHY.js} +3 -3
  15. package/dist/{chunk-OV4KGXPD.js.map → chunk-57ZRSCHY.js.map} +1 -1
  16. package/dist/{chunk-KFEM6FWP.js → chunk-5R4HYDTC.js} +4 -4
  17. package/dist/{chunk-KFEM6FWP.js.map → chunk-5R4HYDTC.js.map} +1 -1
  18. package/dist/{chunk-EI5AKDSC.js → chunk-5RMME7PT.js} +3 -3
  19. package/dist/{chunk-EI5AKDSC.js.map → chunk-5RMME7PT.js.map} +1 -1
  20. package/dist/{chunk-OQT3JBWW.js → chunk-5UG4UHKU.js} +205 -36
  21. package/dist/chunk-5UG4UHKU.js.map +1 -0
  22. package/dist/{chunk-NDNNOAS6.js → chunk-6H2QV5DR.js} +3 -3
  23. package/dist/{chunk-NDNNOAS6.js.map → chunk-6H2QV5DR.js.map} +1 -1
  24. package/dist/{chunk-LJSJX6U4.js → chunk-A3WWRW7U.js} +3 -3
  25. package/dist/{chunk-LJSJX6U4.js.map → chunk-A3WWRW7U.js.map} +1 -1
  26. package/dist/{chunk-O5ASXWKF.js → chunk-ARGYMFST.js} +3 -3
  27. package/dist/{chunk-O5ASXWKF.js.map → chunk-ARGYMFST.js.map} +1 -1
  28. package/dist/{chunk-FFY6NW7P.js → chunk-C5AOLTQS.js} +5 -5
  29. package/dist/{chunk-FFY6NW7P.js.map → chunk-C5AOLTQS.js.map} +1 -1
  30. package/dist/{chunk-F46Q3AEI.js → chunk-CEJIX3O7.js} +44 -15
  31. package/dist/chunk-CEJIX3O7.js.map +1 -0
  32. package/dist/{chunk-QMRSCJUN.js → chunk-DMI4BMUL.js} +3 -3
  33. package/dist/{chunk-QMRSCJUN.js.map → chunk-DMI4BMUL.js.map} +1 -1
  34. package/dist/{chunk-TS25WFAT.js → chunk-EXFA7QFC.js} +9 -9
  35. package/dist/{chunk-TS25WFAT.js.map → chunk-EXFA7QFC.js.map} +1 -1
  36. package/dist/{chunk-VYSDR2QE.js → chunk-HB3SONYP.js} +4 -4
  37. package/dist/{chunk-VYSDR2QE.js.map → chunk-HB3SONYP.js.map} +1 -1
  38. package/dist/{chunk-KKQX3F5F.js → chunk-HRYF4PWE.js} +7 -5
  39. package/dist/chunk-HRYF4PWE.js.map +1 -0
  40. package/dist/{chunk-EIESBKLW.js → chunk-HVJHFTIV.js} +7 -7
  41. package/dist/{chunk-EIESBKLW.js.map → chunk-HVJHFTIV.js.map} +1 -1
  42. package/dist/{chunk-JFE7XCAE.js → chunk-IASO2HCI.js} +3 -3
  43. package/dist/{chunk-JFE7XCAE.js.map → chunk-IASO2HCI.js.map} +1 -1
  44. package/dist/chunk-MQJY4EQV.js +6 -0
  45. package/dist/{chunk-DHU3OOEI.js.map → chunk-MQJY4EQV.js.map} +1 -1
  46. package/dist/{chunk-7AVYKZEM.js → chunk-NV7XNBX4.js} +4 -4
  47. package/dist/{chunk-7AVYKZEM.js.map → chunk-NV7XNBX4.js.map} +1 -1
  48. package/dist/{chunk-NZELMYT4.js → chunk-OLIMW4PQ.js} +8 -56
  49. package/dist/chunk-OLIMW4PQ.js.map +1 -0
  50. package/dist/{chunk-NWWLUFN5.js → chunk-PQISIPYP.js} +5 -5
  51. package/dist/{chunk-NWWLUFN5.js.map → chunk-PQISIPYP.js.map} +1 -1
  52. package/dist/{chunk-5XY4EFR7.js → chunk-QLNJ3VWO.js} +3 -3
  53. package/dist/{chunk-5XY4EFR7.js.map → chunk-QLNJ3VWO.js.map} +1 -1
  54. package/dist/{chunk-D44PGMH7.js → chunk-QOU2Q5L4.js} +12 -12
  55. package/dist/{chunk-D44PGMH7.js.map → chunk-QOU2Q5L4.js.map} +1 -1
  56. package/dist/{chunk-TS7STRMI.js → chunk-RTURQXQL.js} +4 -4
  57. package/dist/{chunk-TS7STRMI.js.map → chunk-RTURQXQL.js.map} +1 -1
  58. package/dist/{chunk-74UBGF4P.js → chunk-SHD5TCZ5.js} +3 -3
  59. package/dist/{chunk-74UBGF4P.js.map → chunk-SHD5TCZ5.js.map} +1 -1
  60. package/dist/{chunk-WJYJCDNY.js → chunk-SOAEPTSW.js} +13 -13
  61. package/dist/{chunk-WJYJCDNY.js.map → chunk-SOAEPTSW.js.map} +1 -1
  62. package/dist/{chunk-EMEMHNE3.js → chunk-TD4JAEMH.js} +6 -6
  63. package/dist/{chunk-EMEMHNE3.js.map → chunk-TD4JAEMH.js.map} +1 -1
  64. package/dist/{chunk-5O6O7DJH.js → chunk-UAPA5AHX.js} +3 -3
  65. package/dist/{chunk-5O6O7DJH.js.map → chunk-UAPA5AHX.js.map} +1 -1
  66. package/dist/{chunk-4VAA2XSM.js → chunk-UEXDSWKN.js} +6 -6
  67. package/dist/{chunk-4VAA2XSM.js.map → chunk-UEXDSWKN.js.map} +1 -1
  68. package/dist/{chunk-YIEP5GK5.js → chunk-UP2BR6TV.js} +15 -11
  69. package/dist/chunk-UP2BR6TV.js.map +1 -0
  70. package/dist/{chunk-6F52QR6F.js → chunk-VEQA2FSM.js} +4 -4
  71. package/dist/{chunk-6F52QR6F.js.map → chunk-VEQA2FSM.js.map} +1 -1
  72. package/dist/{chunk-E53WBVUQ.js → chunk-VHRSG6CF.js} +3 -3
  73. package/dist/{chunk-E53WBVUQ.js.map → chunk-VHRSG6CF.js.map} +1 -1
  74. package/dist/{chunk-I5LP55B6.js → chunk-W44THEXF.js} +3 -3
  75. package/dist/{chunk-I5LP55B6.js.map → chunk-W44THEXF.js.map} +1 -1
  76. package/dist/{chunk-FQVAQVJV.js → chunk-WI66PODG.js} +3 -3
  77. package/dist/{chunk-FQVAQVJV.js.map → chunk-WI66PODG.js.map} +1 -1
  78. package/dist/{chunk-CQDUBAQY.js → chunk-WNKGRXUA.js} +3 -3
  79. package/dist/{chunk-CQDUBAQY.js.map → chunk-WNKGRXUA.js.map} +1 -1
  80. package/dist/{chunk-FJG5AXKZ.js → chunk-WUFIXAEJ.js} +22 -6
  81. package/dist/chunk-WUFIXAEJ.js.map +1 -0
  82. package/dist/{chunk-QSLVOVNZ.js → chunk-XAS45W3G.js} +10 -10
  83. package/dist/{chunk-QSLVOVNZ.js.map → chunk-XAS45W3G.js.map} +1 -1
  84. package/dist/{chunk-BWPBB45M.js → chunk-XP6UUCZZ.js} +3 -3
  85. package/dist/{chunk-BWPBB45M.js.map → chunk-XP6UUCZZ.js.map} +1 -1
  86. package/dist/{chunk-BPF3YX2U.js → chunk-XQNKCA2J.js} +6 -3
  87. package/dist/chunk-XQNKCA2J.js.map +1 -0
  88. package/dist/{chunk-U7A7D2HP.js → chunk-XZDI2N7M.js} +7 -7
  89. package/dist/{chunk-U7A7D2HP.js.map → chunk-XZDI2N7M.js.map} +1 -1
  90. package/dist/{chunk-7N4Y3E47.js → chunk-YJYEPYB2.js} +13 -18
  91. package/dist/chunk-YJYEPYB2.js.map +1 -0
  92. package/dist/cli.js +104 -94
  93. package/dist/cli.js.map +1 -1
  94. package/dist/client-P5XSRFV4.js +8 -0
  95. package/dist/{client-UQIELEEZ.js.map → client-P5XSRFV4.js.map} +1 -1
  96. package/dist/daemon-VMQKIIYP.js +30 -0
  97. package/dist/{daemon-UNL65PTP.js.map → daemon-VMQKIIYP.js.map} +1 -1
  98. package/dist/embed-worker-main.js +5 -5
  99. package/dist/ensure-map-YIUJWMBK.js +40 -0
  100. package/dist/{ensure-map-4D2HJ6MA.js.map → ensure-map-YIUJWMBK.js.map} +1 -1
  101. package/dist/{federation-SZYVHYB2.js → federation-M4ZNXOPX.js} +5 -5
  102. package/dist/{federation-SZYVHYB2.js.map → federation-M4ZNXOPX.js.map} +1 -1
  103. package/dist/git-ref-LMT3EXYY.js +4 -0
  104. package/dist/{git-ref-RSRAN4OH.js.map → git-ref-LMT3EXYY.js.map} +1 -1
  105. package/dist/graph-backend-FDZUY4TR.js +16 -0
  106. package/dist/{graph-backend-36EIAAPQ.js.map → graph-backend-FDZUY4TR.js.map} +1 -1
  107. package/dist/index.d.ts +1 -1
  108. package/dist/index.js +23 -23
  109. package/dist/{interactive-ZZMHSZ3W.js → interactive-CS4PGZPK.js} +40 -40
  110. package/dist/{interactive-ZZMHSZ3W.js.map → interactive-CS4PGZPK.js.map} +1 -1
  111. package/dist/{llm-host-XFYFOAAX.js → llm-host-QVTJJVER.js} +5 -5
  112. package/dist/{llm-host-XFYFOAAX.js.map → llm-host-QVTJJVER.js.map} +1 -1
  113. package/dist/load-4EY64JJO.js +11 -0
  114. package/dist/{load-6CYLMUT5.js.map → load-4EY64JJO.js.map} +1 -1
  115. package/dist/local-runtime-GA43KYS5.js +6 -0
  116. package/dist/{local-runtime-6SNWKSA7.js.map → local-runtime-GA43KYS5.js.map} +1 -1
  117. package/dist/model-manager-6H3TMZKK.js +10 -0
  118. package/dist/{model-manager-SXHZ5VD4.js.map → model-manager-6H3TMZKK.js.map} +1 -1
  119. package/dist/{model-orchestrator-LHYPJBFH.js → model-orchestrator-X3NE3Y2G.js} +6 -6
  120. package/dist/{model-orchestrator-LHYPJBFH.js.map → model-orchestrator-X3NE3Y2G.js.map} +1 -1
  121. package/dist/parse-worker.js +2 -2
  122. package/dist/{paths-62AKTFSR.js → paths-RVK6FKRN.js} +4 -4
  123. package/dist/{paths-62AKTFSR.js.map → paths-RVK6FKRN.js.map} +1 -1
  124. package/dist/publish-27S66NOW.js +9 -0
  125. package/dist/{publish-7YHRTBRA.js.map → publish-27S66NOW.js.map} +1 -1
  126. package/dist/resolve-gguf-WVKVDN45.js +9 -0
  127. package/dist/{resolve-gguf-SDIYGGI6.js.map → resolve-gguf-WVKVDN45.js.map} +1 -1
  128. package/dist/{run-outcome-ADEAKXHH.js → run-outcome-T7VDBNWB.js} +7 -7
  129. package/dist/{run-outcome-ADEAKXHH.js.map → run-outcome-T7VDBNWB.js.map} +1 -1
  130. package/dist/runtime-session-WZLVADPQ.js +26 -0
  131. package/dist/{runtime-session-VNSXQAEO.js.map → runtime-session-WZLVADPQ.js.map} +1 -1
  132. package/dist/session-VPP2VGUN.js +17 -0
  133. package/dist/{session-3A6LKJHD.js.map → session-VPP2VGUN.js.map} +1 -1
  134. package/dist/{slot-subscription-25GOARW5.js → slot-subscription-C2ZUJED6.js} +5 -5
  135. package/dist/{slot-subscription-25GOARW5.js.map → slot-subscription-C2ZUJED6.js.map} +1 -1
  136. package/dist/{stream-json-S2TP2VPU.js → stream-json-XXCFN4MF.js} +17 -17
  137. package/dist/{stream-json-S2TP2VPU.js.map → stream-json-XXCFN4MF.js.map} +1 -1
  138. package/dist/version-2UBJ7N2I.js +4 -0
  139. package/dist/{version-SZI6I3A2.js.map → version-2UBJ7N2I.js.map} +1 -1
  140. package/dist/{vg-mcp-bridge-IIBEAOEB.js → vg-mcp-bridge-H6GXYNKV.js} +14 -14
  141. package/dist/{vg-mcp-bridge-IIBEAOEB.js.map → vg-mcp-bridge-H6GXYNKV.js.map} +1 -1
  142. package/dist/{vgd-KGXIKGOS.js → vgd-SBZO4ONQ.js} +13 -13
  143. package/dist/vgd-SBZO4ONQ.js.map +1 -0
  144. package/package.json +1 -1
  145. package/dist/agent-3CKNTCRX.js +0 -30
  146. package/dist/attach-OCQ3I76L.js +0 -10
  147. package/dist/baseline-QDC6OQ2X.js +0 -9
  148. package/dist/chunk-7N4Y3E47.js.map +0 -1
  149. package/dist/chunk-BPF3YX2U.js.map +0 -1
  150. package/dist/chunk-DHU3OOEI.js +0 -6
  151. package/dist/chunk-F46Q3AEI.js.map +0 -1
  152. package/dist/chunk-FJG5AXKZ.js.map +0 -1
  153. package/dist/chunk-JGBOYZAF.js.map +0 -1
  154. package/dist/chunk-KKQX3F5F.js.map +0 -1
  155. package/dist/chunk-NZELMYT4.js.map +0 -1
  156. package/dist/chunk-OQT3JBWW.js.map +0 -1
  157. package/dist/chunk-YIEP5GK5.js.map +0 -1
  158. package/dist/client-UQIELEEZ.js +0 -8
  159. package/dist/daemon-UNL65PTP.js +0 -30
  160. package/dist/ensure-map-4D2HJ6MA.js +0 -40
  161. package/dist/git-ref-RSRAN4OH.js +0 -4
  162. package/dist/graph-backend-36EIAAPQ.js +0 -16
  163. package/dist/load-6CYLMUT5.js +0 -11
  164. package/dist/local-runtime-6SNWKSA7.js +0 -6
  165. package/dist/model-manager-SXHZ5VD4.js +0 -10
  166. package/dist/publish-7YHRTBRA.js +0 -9
  167. package/dist/resolve-gguf-SDIYGGI6.js +0 -9
  168. package/dist/runtime-session-VNSXQAEO.js +0 -26
  169. package/dist/session-3A6LKJHD.js +0 -17
  170. package/dist/version-SZI6I3A2.js +0 -4
  171. package/dist/vgd-KGXIKGOS.js.map +0 -1
@@ -407,7 +407,10 @@ async function npmViewJson(args, cwd) {
407
407
  return new Promise((resolve9, reject) => {
408
408
  const child = spawn(NPM_COMMAND, ["view", ...args, "--json"], {
409
409
  cwd,
410
- stdio: ["ignore", "pipe", "pipe"]
410
+ stdio: ["ignore", "pipe", "pipe"],
411
+ // Scans also run from console-less hosts (vgd background rebuilds,
412
+ // editor-spawned servers) — never flash a console window on Windows.
413
+ windowsHide: true
411
414
  });
412
415
  let out = "";
413
416
  let err = "";
@@ -11685,6 +11688,30 @@ function contractKindFromName(filePath, basename22) {
11685
11688
  function hasExt(ctx, ...exts) {
11686
11689
  return exts.some((e) => ctx.extensions.has(e));
11687
11690
  }
11691
+ function projectNameHaystack(ctx) {
11692
+ return `${ctx.projectPath.replace(/\\/g, "/")}/${ctx.project.name ?? ""}`;
11693
+ }
11694
+ function looksLikeWebAppName(ctx) {
11695
+ return /webapp|frontend|(?:^|[/._-])spa(?:[/._-]|$)/i.test(projectNameHaystack(ctx));
11696
+ }
11697
+ function looksLikeClientName(ctx) {
11698
+ return /(?:^|[/._-])client(?:[/._-]|$)/i.test(projectNameHaystack(ctx));
11699
+ }
11700
+ var SPA_UI_PACKAGES = [
11701
+ "react",
11702
+ "vue",
11703
+ "svelte",
11704
+ "@angular/core",
11705
+ "vue-router",
11706
+ "vuetify",
11707
+ "@vitejs/plugin-vue",
11708
+ "react-router",
11709
+ "react-router-dom",
11710
+ "@angular/router"
11711
+ ];
11712
+ function hasSpaUiSignal(ctx) {
11713
+ return hasPackage(ctx, ...SPA_UI_PACKAGES) || hasExt(ctx, ".vue", ".svelte");
11714
+ }
11688
11715
  function hasFile(ctx, ...names) {
11689
11716
  return names.some((n) => ctx.fileNames.has(n.toLowerCase()));
11690
11717
  }
@@ -11889,6 +11916,30 @@ var frameworkPacks = [
11889
11916
  depFramework("framework/remix", "remix", ["@remix-run/react", "@remix-run/node", "@remix-run/dev"]),
11890
11917
  depFramework("framework/sveltekit", "sveltekit", ["@sveltejs/kit"]),
11891
11918
  depFramework("framework/nuxt", "nuxt", ["nuxt"]),
11919
+ {
11920
+ id: "framework/vue",
11921
+ frameworks: ["vue"],
11922
+ pathRules: [
11923
+ { pattern: /\/api\//, layer: "infrastructure", confidence: 0.88, signal: "SPA HTTP client (api/)" },
11924
+ { pattern: /\/plugins\//, layer: "config", confidence: 0.82, signal: "SPA plugin wiring" },
11925
+ { pattern: /(^|\/)router\.[jt]sx?$/, layer: "routing", confidence: 0.92, signal: "client router module" },
11926
+ { pattern: /(^|\/)routes\.[jt]sx?$/, layer: "routing", confidence: 0.9, signal: "client routes module" }
11927
+ ],
11928
+ match(ctx) {
11929
+ if (hasPackage(ctx, "nuxt")) return [];
11930
+ const dep = hasPackage(ctx, "vue", "vue-router", "vuetify", "@vitejs/plugin-vue");
11931
+ const files = hasExt(ctx, ".vue");
11932
+ if (!dep && !files) return [];
11933
+ const signals = [];
11934
+ if (hasPackage(ctx, "vue")) signals.push("dep:vue");
11935
+ if (hasPackage(ctx, "vue-router")) signals.push("dep:vue-router");
11936
+ if (hasPackage(ctx, "vuetify")) signals.push("dep:vuetify");
11937
+ if (hasPackage(ctx, "@vitejs/plugin-vue")) signals.push("dep:@vitejs/plugin-vue");
11938
+ if (files) signals.push("vue-source");
11939
+ const confidence = hasPackage(ctx, "vue") ? 0.9 : files ? 0.78 : 0.82;
11940
+ return [evidenceOf("framework/vue", "framework", "vue", confidence, signals)];
11941
+ }
11942
+ },
11892
11943
  depFramework("framework/fastify", "fastify", ["fastify"]),
11893
11944
  depFramework("framework/hono", "hono", ["hono"]),
11894
11945
  depFramework("framework/koa", "koa", ["koa"]),
@@ -12307,17 +12358,28 @@ var projectKindPacks = [
12307
12358
  match(ctx) {
12308
12359
  const metaFw = hasPackage(ctx, "next", "@next/core", "nuxt", "@remix-run/react", "@sveltejs/kit");
12309
12360
  const uiDep = hasPackage(ctx, "react", "vue", "svelte", "@angular/core");
12361
+ const spaDeps = hasPackage(ctx, "vue-router", "vuetify", "@vitejs/plugin-vue", "react-router", "react-router-dom", "@angular/router");
12362
+ const vueFiles = hasExt(ctx, ".vue");
12310
12363
  const pages = filePathHas(ctx, /(^|\/)(pages|app\/.*page\.)/);
12311
12364
  const railsViews = filePathHas(ctx, /(^|\/)app\/views\//);
12312
12365
  const libPath = /(^|\/)(packages|libs)(\/|$)/.test(ctx.projectPath.replace(/\\/g, "/"));
12313
- if (!metaFw && !pages && !railsViews && !(uiDep && !libPath)) return [];
12314
- const apiOnly = !metaFw && !railsViews && filePathHas(ctx, /(^|\/)(controllers|routes)\//) && !pages;
12366
+ const namedWebApp = looksLikeWebAppName(ctx);
12367
+ const clientWithUi = looksLikeClientName(ctx) && (uiDep || spaDeps || vueFiles || pages || railsViews || metaFw);
12368
+ const uiWithoutLib = uiDep && !libPath;
12369
+ if (!metaFw && !pages && !railsViews && !uiWithoutLib && !namedWebApp && !clientWithUi && !spaDeps && !vueFiles) {
12370
+ return [];
12371
+ }
12372
+ const apiOnly = !metaFw && !railsViews && !namedWebApp && !uiDep && !vueFiles && !spaDeps && filePathHas(ctx, /(^|\/)(controllers|routes)\//) && !pages;
12315
12373
  if (apiOnly) return [];
12316
12374
  const signals = [];
12317
12375
  if (metaFw) signals.push("meta-framework");
12318
- else if (uiDep) signals.push("ui-dependency");
12376
+ else if (uiDep || spaDeps) signals.push("ui-dependency");
12319
12377
  if (pages || railsViews) signals.push("ui-layout");
12320
- return [evidenceOf("project-kind/web-app", "projectKind", "web-app", metaFw ? 0.88 : 0.72, signals)];
12378
+ if (namedWebApp) signals.push("webapp-path");
12379
+ if (clientWithUi) signals.push("client-path");
12380
+ if (vueFiles) signals.push("vue-source");
12381
+ const confidence = metaFw || namedWebApp && (uiDep || spaDeps || vueFiles) || spaDeps ? 0.88 : namedWebApp || clientWithUi ? 0.8 : 0.72;
12382
+ return [evidenceOf("project-kind/web-app", "projectKind", "web-app", confidence, signals)];
12321
12383
  }
12322
12384
  },
12323
12385
  {
@@ -12341,7 +12403,8 @@ var projectKindPacks = [
12341
12403
  ctx,
12342
12404
  (p) => p.includes("springframework") || p.includes("spring-boot") || p.toLowerCase().includes("microsoft.aspnetcore")
12343
12405
  );
12344
- const layout = filePathHas(ctx, /(^|\/)(controllers|routes|handlers|api)\//) || filePathHas(ctx, /\.controller\.[jt]sx?$/) || filePathHas(ctx, /Controller\.(cs|java|kt)$/);
12406
+ const spaClient = hasSpaUiSignal(ctx) || looksLikeWebAppName(ctx);
12407
+ const layout = spaClient ? filePathHas(ctx, /(^|\/)(controllers|routes|handlers)\//) || filePathHas(ctx, /\.controller\.[jt]sx?$/) || filePathHas(ctx, /Controller\.(cs|java|kt)$/) : filePathHas(ctx, /(^|\/)(controllers|routes|handlers|api)\//) || filePathHas(ctx, /\.controller\.[jt]sx?$/) || filePathHas(ctx, /Controller\.(cs|java|kt)$/);
12345
12408
  if (!apiDep && !layout) return [];
12346
12409
  const signals = [];
12347
12410
  if (apiDep) signals.push("api-dependency");
@@ -12411,7 +12474,10 @@ function isToolingConfigFile(filePath) {
12411
12474
  }
12412
12475
  function isTestFilePath(filePath) {
12413
12476
  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);
12477
+ return /\/(__tests__|__mocks__|tests?|spec|fixtures)\//.test(n) || /\.(tests?|spec)\.[^./]+$/.test(n) || /_(test|spec)\.[^./]+$/.test(n) || /\/(conftest|test_[^/]*)\.py$/.test(n) || isTestProjectDir(n);
12478
+ }
12479
+ function isTestProjectDir(loweredPath) {
12480
+ return /\/[^/]*\.tests?\//.test(loweredPath) || /\/[^/]*(?:e2e|unit|integration|functional|acceptance|smoke|component)tests?\//.test(loweredPath);
12415
12481
  }
12416
12482
  function folderLooksLikeTests(dir) {
12417
12483
  const n = `/${normalizeRelPath(dir).toLowerCase()}/`;
@@ -12899,6 +12965,9 @@ var PATH_RULES = [
12899
12965
  // Directory rules above already cover Controllers/, Services/, Models/,
12900
12966
  // Views/, Migrations/, Middleware/ … because matching is case-insensitive.
12901
12967
  { pattern: /\.tests?\//, layer: "testing", confidence: 0.9, signal: "*.Tests project directory" },
12968
+ // Compound test-project names without the dot: `FooE2ETests/`, `unittests/`.
12969
+ // Closed keyword list so `latest/` / `contest/` never match.
12970
+ { pattern: /\/[^/]*(?:e2e|unit|integration|functional|acceptance|smoke|component)tests?\//, layer: "testing", confidence: 0.9, signal: "test project directory" },
12902
12971
  // Layer-named project directories (`Company.Product.Domain/`,
12903
12972
  // `Company.Product.Database/`) — the dotted segment carries the layer.
12904
12973
  { pattern: /\.domain\//, layer: "domain", confidence: 0.85, signal: "*.Domain project" },
@@ -12906,7 +12975,8 @@ var PATH_RULES = [
12906
12975
  { pattern: /\.(infrastructure|infra)\//, layer: "infrastructure", confidence: 0.85, signal: "*.Infrastructure project" },
12907
12976
  { pattern: /\.worker\//, layer: "infrastructure", confidence: 0.8, signal: "*.Worker project" },
12908
12977
  { pattern: /\.(webapi|api)\//, layer: "routing", confidence: 0.8, signal: "*.WebApi project" },
12909
- { pattern: /\.(webapp|web|ui)\//, layer: "presentation", confidence: 0.75, signal: "*.WebApp project" },
12978
+ // `*.WebApp` / `*.Client` / `*.UI` are project-kind signals, not a
12979
+ // blanket presentation stamp. See isSpaWebApp + project-kind/web-app.
12910
12980
  { pattern: /\.(services?|application)\//, layer: "services", confidence: 0.8, signal: "*.Services project" },
12911
12981
  { pattern: /\/wwwroot\//, layer: "presentation", confidence: 0.85, signal: "wwwroot/ static assets" },
12912
12982
  { pattern: /\/properties\//, layer: "config", confidence: 0.85, signal: "Properties/ directory" },
@@ -13014,50 +13084,105 @@ var PASCAL_SUFFIX_RULES = [
13014
13084
  { suffix: "Configuration", layer: "config", confidence: 0.85, signal: "Configuration class" },
13015
13085
  { suffix: "Config", layer: "config", confidence: 0.8, signal: "Config class" },
13016
13086
  { suffix: "Interceptor", layer: "middleware", confidence: 0.85, signal: "Interceptor class" },
13017
- { suffix: "Activity", layer: "presentation", confidence: 0.85, signal: "Android Activity" },
13018
- { suffix: "Fragment", layer: "presentation", confidence: 0.85, signal: "Android Fragment" },
13087
+ // Mobile suffixes are platform conventions, not universal scoped to their
13088
+ // languages so a .NET `ProjectApproverSqlFragment.cs` never lands in
13089
+ // presentation on the strength of an Android naming rule.
13090
+ { suffix: "Activity", layer: "presentation", confidence: 0.85, signal: "Android Activity", extensions: [".java", ".kt", ".kts"] },
13091
+ { suffix: "Fragment", layer: "presentation", confidence: 0.85, signal: "Android Fragment", extensions: [".java", ".kt", ".kts"] },
13019
13092
  // Swift / iOS — higher confidence than the generic Controller→routing rule
13020
13093
  // so FooViewController lands in presentation, not routing.
13021
- { suffix: "ViewController", layer: "presentation", confidence: 0.95, signal: "UIKit ViewController" },
13094
+ { suffix: "ViewController", layer: "presentation", confidence: 0.95, signal: "UIKit ViewController", extensions: [".swift", ".m", ".mm", ".h"] },
13022
13095
  // Flutter
13023
- { suffix: "Screen", layer: "presentation", confidence: 0.85, signal: "Screen widget" },
13024
- { suffix: "Widget", layer: "presentation", confidence: 0.75, signal: "Widget class" }
13096
+ { suffix: "Screen", layer: "presentation", confidence: 0.85, signal: "Screen widget", extensions: [".dart"] },
13097
+ { suffix: "Widget", layer: "presentation", confidence: 0.75, signal: "Widget class", extensions: [".dart"] }
13025
13098
  ];
13026
13099
  var UI_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".vue", ".svelte"]);
13100
+ var META_WEBAPP_ARCHETYPES = /* @__PURE__ */ new Set([
13101
+ "nextjs",
13102
+ "nuxt",
13103
+ "remix",
13104
+ "sveltekit",
13105
+ "rails"
13106
+ ]);
13107
+ var SPA_SKIP_PASCAL = /* @__PURE__ */ new Set(["Service", "Handler", "Client"]);
13108
+ var SPA_PATH_RULES = [
13109
+ { pattern: /\/api\//, layer: "infrastructure", confidence: 0.88, signal: "SPA HTTP client (api/)" },
13110
+ { pattern: /\/plugins\//, layer: "config", confidence: 0.82, signal: "SPA plugin wiring" },
13111
+ { pattern: /(^|\/)router\.[jt]sx?$/, layer: "routing", confidence: 0.92, signal: "client router module" },
13112
+ { pattern: /(^|\/)routes\.[jt]sx?$/, layer: "routing", confidence: 0.9, signal: "client routes module" }
13113
+ ];
13114
+ function isSpaWebApp(projectKind, archetype) {
13115
+ return projectKind === "web-app" && !META_WEBAPP_ARCHETYPES.has(archetype);
13116
+ }
13117
+ function collectPackLayerRules(packs) {
13118
+ const pathRules = [];
13119
+ const suffixRules = [];
13120
+ const pascalSuffixRules = [];
13121
+ for (const pack of packs) {
13122
+ if (pack.pathRules) pathRules.push(...pack.pathRules);
13123
+ if (pack.suffixRules) suffixRules.push(...pack.suffixRules);
13124
+ if (pack.pascalSuffixRules) pascalSuffixRules.push(...pack.pascalSuffixRules);
13125
+ }
13126
+ return { pathRules, suffixRules, pascalSuffixRules };
13127
+ }
13027
13128
  function isDomainRepositoryPort(baseName, loweredPath) {
13028
13129
  if (!/^I[A-Z]\w*(Repository|Repo)$/.test(baseName)) return false;
13029
13130
  return /\/(domain|interfaces)\//.test(loweredPath);
13030
13131
  }
13031
- function classifyOne(filePath, archetype) {
13132
+ function considerRule(bestMatch, layer, confidence, signal) {
13133
+ if (!bestMatch || confidence > bestMatch.confidence) {
13134
+ return { layer, confidence, signal };
13135
+ }
13136
+ return bestMatch;
13137
+ }
13138
+ function classifyOne(filePath, archetype, opts) {
13032
13139
  const normalised = "/" + filePath.replace(/\\/g, "/").replace(/^\/+/, "");
13033
13140
  const lowered = normalised.toLowerCase();
13141
+ const spa = isSpaWebApp(opts?.projectKind, archetype);
13034
13142
  let bestMatch = null;
13035
- for (const rule of PATH_RULES) {
13143
+ const pathRules = spa ? [...SPA_PATH_RULES, ...PATH_RULES] : PATH_RULES;
13144
+ for (const rule of pathRules) {
13036
13145
  if (rule.archetypes && rule.archetypes.length > 0 && !rule.archetypes.includes(archetype)) {
13037
13146
  continue;
13038
13147
  }
13039
13148
  if (rule.pattern.test(lowered)) {
13040
13149
  const boost = rule.archetypes ? 0.05 : 0;
13041
13150
  const adjustedConfidence = Math.min(rule.confidence + boost, 1);
13042
- if (!bestMatch || adjustedConfidence > bestMatch.confidence) {
13043
- bestMatch = { layer: rule.layer, confidence: adjustedConfidence, signal: rule.signal };
13044
- }
13151
+ bestMatch = considerRule(bestMatch, rule.layer, adjustedConfidence, rule.signal);
13152
+ }
13153
+ }
13154
+ for (const rule of opts?.extraPathRules ?? []) {
13155
+ if (rule.archetypes && rule.archetypes.length > 0 && !rule.archetypes.includes(archetype)) {
13156
+ continue;
13157
+ }
13158
+ if (rule.pattern.test(lowered)) {
13159
+ bestMatch = considerRule(bestMatch, rule.layer, rule.confidence, rule.signal);
13045
13160
  }
13046
13161
  }
13047
13162
  const baseName = path31.basename(filePath, path31.extname(filePath));
13048
13163
  const cleanBase = baseName.replace(/\.(test|spec)$/, "");
13049
13164
  for (const rule of SUFFIX_RULES) {
13050
13165
  if (cleanBase.endsWith(rule.suffix)) {
13051
- if (!bestMatch || rule.confidence > bestMatch.confidence) {
13052
- bestMatch = { layer: rule.layer, confidence: rule.confidence, signal: rule.signal };
13053
- }
13166
+ bestMatch = considerRule(bestMatch, rule.layer, rule.confidence, rule.signal);
13167
+ }
13168
+ }
13169
+ for (const rule of opts?.extraSuffixRules ?? []) {
13170
+ if (cleanBase.endsWith(rule.suffix)) {
13171
+ bestMatch = considerRule(bestMatch, rule.layer, rule.confidence, rule.signal);
13054
13172
  }
13055
13173
  }
13174
+ const fileExt = path31.extname(filePath).toLowerCase();
13056
13175
  for (const rule of PASCAL_SUFFIX_RULES) {
13176
+ if (spa && SPA_SKIP_PASCAL.has(rule.suffix)) continue;
13177
+ if (rule.extensions && !rule.extensions.includes(fileExt)) continue;
13057
13178
  if (cleanBase.endsWith(rule.suffix)) {
13058
- if (!bestMatch || rule.confidence > bestMatch.confidence) {
13059
- bestMatch = { layer: rule.layer, confidence: rule.confidence, signal: rule.signal };
13060
- }
13179
+ bestMatch = considerRule(bestMatch, rule.layer, rule.confidence, rule.signal);
13180
+ }
13181
+ }
13182
+ for (const rule of opts?.extraPascalSuffixRules ?? []) {
13183
+ if (spa && SPA_SKIP_PASCAL.has(rule.suffix)) continue;
13184
+ if (cleanBase.endsWith(rule.suffix)) {
13185
+ bestMatch = considerRule(bestMatch, rule.layer, rule.confidence, rule.signal);
13061
13186
  }
13062
13187
  }
13063
13188
  if (isDomainRepositoryPort(cleanBase, lowered)) {
@@ -13079,16 +13204,34 @@ function classifyOne(filePath, archetype) {
13079
13204
  }
13080
13205
  var LAYER_HINT_SEGMENT = /(?:^|\/)(application|domain|infrastructure|persistence|entities)(?:\/|$)/i;
13081
13206
  function prefixHasLayerHint(repoRelative, localPath) {
13207
+ const prefix = strippedPrefix(repoRelative, localPath);
13208
+ return prefix !== null && LAYER_HINT_SEGMENT.test(`/${prefix}/`);
13209
+ }
13210
+ function strippedPrefix(repoRelative, localPath) {
13082
13211
  const repo = repoRelative.replace(/\\/g, "/").replace(/^\/+/, "");
13083
13212
  const local = localPath.replace(/\\/g, "/").replace(/^\/+/, "");
13084
- if (!repo.endsWith(local)) return false;
13213
+ if (!repo.endsWith(local)) return null;
13085
13214
  const prefix = repo.slice(0, repo.length - local.length).replace(/\/+$/, "");
13086
- return prefix.length > 0 && LAYER_HINT_SEGMENT.test(`/${prefix}/`);
13215
+ return prefix.length > 0 ? prefix : null;
13216
+ }
13217
+ var TEST_PREFIX_SEGMENT = /\/(__tests__|__mocks__|tests?|spec|testing|e2e)\/|\/[^/]*\.tests?\/|\/[^/]*(?:e2e|unit|integration|functional|acceptance|smoke|component)tests?\//;
13218
+ function prefixLooksLikeTests(repoRelative, localPath) {
13219
+ const prefix = strippedPrefix(repoRelative, localPath);
13220
+ return prefix !== null && TEST_PREFIX_SEGMENT.test(`/${prefix.toLowerCase()}/`);
13087
13221
  }
13088
13222
  function classifyFile(filePath, archetype, opts) {
13089
- const local = classifyOne(filePath, archetype);
13223
+ const repoPathForTests = opts?.repoRelative?.replace(/\\/g, "/");
13224
+ if (repoPathForTests && repoPathForTests !== filePath.replace(/\\/g, "/") && prefixLooksLikeTests(repoPathForTests, filePath)) {
13225
+ return {
13226
+ filePath,
13227
+ layer: "testing",
13228
+ confidence: 0.9,
13229
+ signals: ["test project prefix"]
13230
+ };
13231
+ }
13232
+ const local = classifyOne(filePath, archetype, opts);
13090
13233
  const repoPath = opts?.repoRelative?.replace(/\\/g, "/");
13091
- const repo = repoPath && repoPath !== filePath.replace(/\\/g, "/") && prefixHasLayerHint(repoPath, filePath) ? classifyOne(repoPath, archetype) : null;
13234
+ const repo = repoPath && repoPath !== filePath.replace(/\\/g, "/") && prefixHasLayerHint(repoPath, filePath) ? classifyOne(repoPath, archetype, opts) : null;
13092
13235
  let best = local;
13093
13236
  let usedHint = false;
13094
13237
  if (repo && (!local || repo.confidence > local.confidence)) {
@@ -13377,6 +13520,16 @@ function inferStructure(result, projects) {
13377
13520
  confidence: 0.8
13378
13521
  };
13379
13522
  }
13523
+ if (result.projectKind === "web-app") {
13524
+ if (evidencePrimary && !["layered", "mvc", "mvvm"].includes(evidencePrimary.value)) {
13525
+ return {
13526
+ primary: evidencePrimary.value,
13527
+ characteristics: [],
13528
+ confidence: evidencePrimary.confidence
13529
+ };
13530
+ }
13531
+ return void 0;
13532
+ }
13380
13533
  if (evidencePrimary) {
13381
13534
  return {
13382
13535
  primary: evidencePrimary.value,
@@ -13391,6 +13544,10 @@ function inferStructure(result, projects) {
13391
13544
  }
13392
13545
  function selectBoundaryProfile(structure, result) {
13393
13546
  const primary = structure?.primary;
13547
+ if (result.projectKind === "web-app") {
13548
+ if (primary && (CLEAN_PROFILES.has(primary) || primary === "vertical-slice")) return primary;
13549
+ return void 0;
13550
+ }
13394
13551
  if (primary && CLEAN_PROFILES.has(primary)) return primary;
13395
13552
  if (primary === "vertical-slice" || primary === "mvc" || primary === "mvvm" || primary === "layered") {
13396
13553
  return primary;
@@ -13406,7 +13563,7 @@ function isSliceInternal(filePath) {
13406
13563
  const base = normalizeRelPath3(filePath).split("/").pop() ?? "";
13407
13564
  return !/^(index|public|api|mod)\.[^./]+$/i.test(base);
13408
13565
  }
13409
- function isIllegalEdge(profile, from, to, fromFile, toFile) {
13566
+ function isIllegalEdge(profile, from, to, fromFile, toFile, projectKind) {
13410
13567
  if (profile === "vertical-slice") {
13411
13568
  const fromSlice = sliceOf(fromFile);
13412
13569
  const toSlice = sliceOf(toFile);
@@ -13423,6 +13580,9 @@ function isIllegalEdge(profile, from, to, fromFile, toFile) {
13423
13580
  return { illegal: false, rule: "" };
13424
13581
  }
13425
13582
  if (profile === "layered" || profile === "mvc" || profile === "mvvm") {
13583
+ if (projectKind === "web-app" && to === "presentation" && (from === "routing" || from === "middleware")) {
13584
+ return { illegal: false, rule: "" };
13585
+ }
13426
13586
  if (EXEMPT_LAYERS.has(from) || EXEMPT_LAYERS.has(to)) return { illegal: false, rule: "" };
13427
13587
  if (to === "domain") return { illegal: false, rule: "" };
13428
13588
  if (from === "domain" && (to === "data-access" || to === "infrastructure")) {
@@ -13562,10 +13722,11 @@ function collectBoundaryViolations(result, graph, profile, projectPath, projects
13562
13722
  if (!fromFile || !toFile || fromFile === toFile) continue;
13563
13723
  if (!fileInScope(fromFile, projectPath) || !fileInScope(toFile, projectPath)) continue;
13564
13724
  if (!sameOwningProject(fromFile, toFile, projectPath, projects)) continue;
13725
+ if (isTestFilePath(fromFile) || isTestFilePath(toFile)) continue;
13565
13726
  const fromState = states.get(fromFile);
13566
13727
  const toState = states.get(toFile);
13567
13728
  if (!fromState?.layer || !toState?.layer) continue;
13568
- const { illegal, rule } = isIllegalEdge(profile, fromState.layer, toState.layer, fromFile, toFile);
13729
+ const { illegal, rule } = isIllegalEdge(profile, fromState.layer, toState.layer, fromFile, toFile, result.projectKind);
13569
13730
  if (!illegal) continue;
13570
13731
  const key = `${fromFile}|${toFile}|${rule}`;
13571
13732
  if (seen.has(key)) continue;
@@ -13784,7 +13945,7 @@ function buildFileState2(filePath, result) {
13784
13945
  role
13785
13946
  };
13786
13947
  }
13787
- const pathClass = classifyFile(n, result.archetype);
13948
+ const pathClass = classifyFile(n, result.archetype, { projectKind: result.projectKind });
13788
13949
  if (pathClass) {
13789
13950
  return {
13790
13951
  filePath: n,
@@ -14096,7 +14257,8 @@ var FRAMEWORK_TO_PROJECT_KIND = {
14096
14257
  rails: "web-app",
14097
14258
  laravel: "web-api",
14098
14259
  phoenix: "web-api",
14099
- serverless: "worker"
14260
+ serverless: "worker",
14261
+ vue: "web-app"
14100
14262
  };
14101
14263
  function projectKindFromFramework(framework) {
14102
14264
  if (!framework) return void 0;
@@ -14889,19 +15051,26 @@ async function classifyTree(rootDir, projects, tooling, services, cache, scope)
14889
15051
  dependencyAgeBuckets: { current: 0, oneBehind: 0, twoPlusBehind: 0, unknown: 0 }
14890
15052
  };
14891
15053
  const context = buildProjectContext(primary, sourceFiles);
14892
- const { evidence: rawEvidence } = collectPackEvidence(ARCHITECTURE_PACKS, context);
15054
+ const { evidence: rawEvidence, matching } = collectPackEvidence(ARCHITECTURE_PACKS, context);
14893
15055
  const fusion = fuseEvidence(rawEvidence);
14894
15056
  const { archetype, confidence: archetypeConfidence } = deriveArchetype(detected, fusion);
14895
15057
  const projectKind = fusion.winners.get("projectKind")?.value ?? projectKindFromFramework(fusion.winners.get("framework")?.value);
14896
15058
  const artifactKind = fusion.winners.get("artifactKind")?.value;
14897
15059
  const skipAllLayers = projectKind === "iac" || projectKind === "contract";
15060
+ const packRules = collectPackLayerRules(matching);
14898
15061
  sourceFiles.sort(compareRelPath4);
14899
15062
  const seedClassified = [];
14900
15063
  const seedUnclassified = [];
14901
15064
  for (const file of sourceFiles) {
14902
15065
  if (!isLayerCandidate(file) || skipAllLayers) continue;
14903
15066
  const storedPath = scope ? toRepoRelative(scope.projectPath, file) : file;
14904
- const classification = classifyFile(file, archetype, { repoRelative: storedPath });
15067
+ const classification = classifyFile(file, archetype, {
15068
+ repoRelative: storedPath,
15069
+ projectKind,
15070
+ extraPathRules: packRules.pathRules,
15071
+ extraSuffixRules: packRules.suffixRules,
15072
+ extraPascalSuffixRules: packRules.pascalSuffixRules
15073
+ });
14905
15074
  if (classification) {
14906
15075
  seedClassified.push({ ...classification, filePath: storedPath });
14907
15076
  } else {
@@ -15785,5 +15954,5 @@ async function computeTreeMetadataHash(rootDir, options) {
15785
15954
  }
15786
15955
 
15787
15956
  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-OQT3JBWW.js.map
15789
- //# sourceMappingURL=chunk-OQT3JBWW.js.map
15957
+ //# sourceMappingURL=chunk-5UG4UHKU.js.map
15958
+ //# sourceMappingURL=chunk-5UG4UHKU.js.map