@launchsecure/launch-kit 0.0.17 → 0.0.18

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 (84) hide show
  1. package/dist/chart-client/assets/index--120d9P9.css +1 -0
  2. package/dist/chart-client/assets/index-D7x8nz-H.js +441 -0
  3. package/dist/chart-client/index.html +2 -2
  4. package/dist/client/assets/index-Bf8zdL3x.css +32 -0
  5. package/dist/client/assets/index-Ds9UP_cj.js +291 -0
  6. package/dist/client/index.html +2 -2
  7. package/dist/council-client/assets/index-CofZh7pS.css +1 -0
  8. package/dist/council-client/assets/index-Dc41S-R2.js +198 -0
  9. package/dist/council-client/index.html +21 -0
  10. package/dist/deck-client/assets/{_baseUniq-BbqvoK-V.js → _baseUniq-2gclQXo7.js} +1 -1
  11. package/dist/deck-client/assets/{arc-CMtYsIZt.js → arc-DcMY5Wm0.js} +1 -1
  12. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-BEN5hESa.js → architectureDiagram-Q4EWVU46-B8iirmmJ.js} +1 -1
  13. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-BV4CZ6k8.js → blockDiagram-DXYQGD6D-B4JBLjmJ.js} +1 -1
  14. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-fLcBXqdD.js → c4Diagram-AHTNJAMY-CojrJAk8.js} +1 -1
  15. package/dist/deck-client/assets/channel-ERh5jKXV.js +1 -0
  16. package/dist/deck-client/assets/{chunk-4BX2VUAB-BO_19zwB.js → chunk-4BX2VUAB-Bmb_BMDo.js} +1 -1
  17. package/dist/deck-client/assets/{chunk-4TB4RGXK-iYegd5fu.js → chunk-4TB4RGXK-CumBy8qe.js} +1 -1
  18. package/dist/deck-client/assets/{chunk-55IACEB6-DM3QwYFL.js → chunk-55IACEB6-Ka8Hb1wD.js} +1 -1
  19. package/dist/deck-client/assets/{chunk-EDXVE4YY-DGznOul1.js → chunk-EDXVE4YY-B3sIPiQo.js} +1 -1
  20. package/dist/deck-client/assets/{chunk-FMBD7UC4-DsANJqYW.js → chunk-FMBD7UC4-C1tYkaqu.js} +1 -1
  21. package/dist/deck-client/assets/{chunk-OYMX7WX6-6PGH1F7d.js → chunk-OYMX7WX6-D7Wacbky.js} +1 -1
  22. package/dist/deck-client/assets/{chunk-QZHKN3VN-Dihf0Uq7.js → chunk-QZHKN3VN-ChXI0vO3.js} +1 -1
  23. package/dist/deck-client/assets/{chunk-YZCP3GAM-Cali2wW5.js → chunk-YZCP3GAM-BXhiqf8u.js} +1 -1
  24. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CMi1Gaev.js +1 -0
  25. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CMi1Gaev.js +1 -0
  26. package/dist/deck-client/assets/clone-DfWhlD4X.js +1 -0
  27. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-DsRY4vbI.js → cose-bilkent-S5V4N54A-Bqp3p68D.js} +1 -1
  28. package/dist/deck-client/assets/cytoscape.esm-BQk4lpUV.js +331 -0
  29. package/dist/deck-client/assets/{dagre-KV5264BT-DJIKE_pI.js → dagre-KV5264BT-BS-rtyhZ.js} +1 -1
  30. package/dist/deck-client/assets/{diagram-5BDNPKRD-Ckgli1SP.js → diagram-5BDNPKRD-BIrj9YGI.js} +1 -1
  31. package/dist/deck-client/assets/{diagram-G4DWMVQ6-CozcDzae.js → diagram-G4DWMVQ6-noHWPIg4.js} +1 -1
  32. package/dist/deck-client/assets/{diagram-MMDJMWI5-xVSwW3f_.js → diagram-MMDJMWI5-C2qHxvqV.js} +1 -1
  33. package/dist/deck-client/assets/{diagram-TYMM5635-CJeZVY-P.js → diagram-TYMM5635-BytnGQr-.js} +1 -1
  34. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-j4wjAERH.js → erDiagram-SMLLAGMA-BfK5m2YQ.js} +1 -1
  35. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-CVLZ1efi.js → flowDiagram-DWJPFMVM-Cq925G1Z.js} +1 -1
  36. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-CcIJ7pkP.js → ganttDiagram-T4ZO3ILL-DhhHPAmj.js} +1 -1
  37. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-BZRhQX-a.js → gitGraphDiagram-UUTBAWPF-B3Lc0h9q.js} +1 -1
  38. package/dist/deck-client/assets/{graph-D0l25xfo.js → graph-RTawgVWm.js} +1 -1
  39. package/dist/deck-client/assets/index-765AIQ9z.css +1 -0
  40. package/dist/deck-client/assets/{index-BXcoHWVM.js → index-BfIfJXmS.js} +93 -93
  41. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-BLwgxnYT.js → infoDiagram-42DDH7IO-BlR584kX.js} +1 -1
  42. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-BfOLoWv3.js → ishikawaDiagram-UXIWVN3A-DygKoNGY.js} +1 -1
  43. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-CPuL6C9h.js → journeyDiagram-VCZTEJTY-BnaiYp9N.js} +1 -1
  44. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-D3uf7_tx.js → kanban-definition-6JOO6SKY-BQBUBzJC.js} +1 -1
  45. package/dist/deck-client/assets/{layout-CzToiXdK.js → layout-DeZ8HI1T.js} +1 -1
  46. package/dist/deck-client/assets/{linear-BU36t460.js → linear-C6roLi_9.js} +1 -1
  47. package/dist/deck-client/assets/{min-DX_q-lqP.js → min-CbUksbuI.js} +1 -1
  48. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-Ccty4O16.js → mindmap-definition-QFDTVHPH-iNxV62yN.js} +1 -1
  49. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-DVjsvH19.js → pieDiagram-DEJITSTG-DHVA0jaG.js} +1 -1
  50. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-DtOXFVW9.js → quadrantDiagram-34T5L4WZ-DBeKKLUQ.js} +1 -1
  51. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-BbO_kKg6.js → requirementDiagram-MS252O5E-CBwITx7p.js} +1 -1
  52. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-qbbj-CmC.js → sankeyDiagram-XADWPNL6-BtE-1YTU.js} +1 -1
  53. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-JNKZAgfQ.js → sequenceDiagram-FGHM5R23-DN96yPP2.js} +1 -1
  54. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-dtFalcNx.js → stateDiagram-FHFEXIEX-VUkKC2uJ.js} +1 -1
  55. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CA0IjulK.js +1 -0
  56. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-Dpp5nqSJ.js → timeline-definition-GMOUNBTQ-oUeZhRns.js} +1 -1
  57. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-D8qEutX7.js → vennDiagram-DHZGUBPP-D87fK90n.js} +1 -1
  58. package/dist/deck-client/assets/wardley-RL74JXVD-DYbYcpDp.js +162 -0
  59. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-Bxl9X3CK.js → wardleyDiagram-NUSXRM2D-Ca_i0QRA.js} +1 -1
  60. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-DYcvxLhi.js → xychartDiagram-5P7HB3ND-CUOJVIvq.js} +1 -1
  61. package/dist/deck-client/index.html +2 -2
  62. package/dist/server/chart-serve.js +258 -273
  63. package/dist/server/cli.js +305 -713
  64. package/dist/server/council-entry.js +1418 -0
  65. package/dist/server/council-serve.js +1039 -0
  66. package/dist/server/deck-server/deck-mcp-entry.js +0 -0
  67. package/dist/server/fb-wizard.js +0 -0
  68. package/dist/server/graph-mcp-entry.js +268 -701
  69. package/dist/server/server/cli.js +0 -0
  70. package/dist/server/server/fb-wizard.js +0 -0
  71. package/dist/server/server/graph-mcp-entry.js +0 -0
  72. package/package.json +17 -17
  73. package/dist/chart-client/assets/index-BUhuLBaw.js +0 -441
  74. package/dist/chart-client/assets/index-CWRZxjqR.css +0 -1
  75. package/dist/client/assets/index-CAAipH3V.js +0 -291
  76. package/dist/client/assets/index-DtbN793z.css +0 -32
  77. package/dist/deck-client/assets/channel-Nf-B3Qor.js +0 -1
  78. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-3i3-miMR.js +0 -1
  79. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-3i3-miMR.js +0 -1
  80. package/dist/deck-client/assets/clone-DXBuQlG8.js +0 -1
  81. package/dist/deck-client/assets/cytoscape.esm-BiciSPf8.js +0 -331
  82. package/dist/deck-client/assets/index-Cdh-f3-c.css +0 -1
  83. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CviYYulW.js +0 -1
  84. package/dist/deck-client/assets/wardley-RL74JXVD-BwMqiNcL.js +0 -162
@@ -188,6 +188,56 @@ var init_resolve_paths = __esm({
188
188
  }
189
189
  });
190
190
 
191
+ // src/server/graph/core/walk.ts
192
+ function walk(dir, exts) {
193
+ const results = [];
194
+ if (!(0, import_node_fs4.existsSync)(dir)) return results;
195
+ for (const entry of (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true })) {
196
+ const full = (0, import_node_path4.join)(dir, entry.name);
197
+ if (entry.isDirectory()) {
198
+ results.push(...walk(full, exts));
199
+ } else if (exts.includes((0, import_node_path4.extname)(entry.name))) {
200
+ results.push(full);
201
+ }
202
+ }
203
+ return results;
204
+ }
205
+ function walkWithIgnore(dir, exts, opts = {}) {
206
+ const results = [];
207
+ if (!(0, import_node_fs4.existsSync)(dir)) return results;
208
+ const skip = opts.extraIgnore ? /* @__PURE__ */ new Set([...DEFAULT_IGNORE_DIRS, ...opts.extraIgnore]) : DEFAULT_IGNORE_DIRS;
209
+ for (const entry of (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true })) {
210
+ if (entry.isDirectory()) {
211
+ if (skip.has(entry.name)) continue;
212
+ results.push(...walkWithIgnore((0, import_node_path4.join)(dir, entry.name), exts, opts));
213
+ } else if (exts.includes((0, import_node_path4.extname)(entry.name))) {
214
+ results.push((0, import_node_path4.join)(dir, entry.name));
215
+ }
216
+ }
217
+ return results;
218
+ }
219
+ var import_node_fs4, import_node_path4, DEFAULT_IGNORE_DIRS;
220
+ var init_walk = __esm({
221
+ "src/server/graph/core/walk.ts"() {
222
+ "use strict";
223
+ import_node_fs4 = require("node:fs");
224
+ import_node_path4 = require("node:path");
225
+ DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
226
+ "node_modules",
227
+ ".git",
228
+ ".next",
229
+ ".launchsecure",
230
+ ".claude",
231
+ "dist",
232
+ "build",
233
+ "out",
234
+ ".turbo",
235
+ ".vercel",
236
+ "coverage"
237
+ ]);
238
+ }
239
+ });
240
+
191
241
  // src/server/graph/core/ts-extractor.ts
192
242
  var ts_extractor_exports = {};
193
243
  __export(ts_extractor_exports, {
@@ -224,15 +274,15 @@ function getQuery(name) {
224
274
  ensureInit();
225
275
  const cached = queryCache.get(name);
226
276
  if (cached) return cached;
227
- const scmPath = (0, import_node_path4.join)(queriesDir, `${name}.scm`);
228
- const scm = (0, import_node_fs4.readFileSync)(scmPath, "utf-8");
277
+ const scmPath = (0, import_node_path5.join)(queriesDir, `${name}.scm`);
278
+ const scm = (0, import_node_fs5.readFileSync)(scmPath, "utf-8");
229
279
  const query = tsxLanguage.query(scm);
230
280
  queryCache.set(name, query);
231
281
  return query;
232
282
  }
233
283
  function parseSource(absPath) {
234
284
  ensureInit();
235
- const content = (0, import_node_fs4.readFileSync)(absPath, "utf-8");
285
+ const content = (0, import_node_fs5.readFileSync)(absPath, "utf-8");
236
286
  return parserInstance.parse(content);
237
287
  }
238
288
  function parseCodeTS(code) {
@@ -697,17 +747,17 @@ function extractDeep(absPath) {
697
747
  }
698
748
  return { elements, stateVars, conditions, variables, responses, params };
699
749
  }
700
- var import_node_fs4, import_node_path4, tsxLanguage, parserInstance, initPromise, initialized, queriesDir, queryCache, PRISMA_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods;
750
+ var import_node_fs5, import_node_path5, tsxLanguage, parserInstance, initPromise, initialized, queriesDir, queryCache, PRISMA_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods;
701
751
  var init_ts_extractor = __esm({
702
752
  "src/server/graph/core/ts-extractor.ts"() {
703
753
  "use strict";
704
- import_node_fs4 = require("node:fs");
705
- import_node_path4 = require("node:path");
754
+ import_node_fs5 = require("node:fs");
755
+ import_node_path5 = require("node:path");
706
756
  initialized = false;
707
757
  queriesDir = (() => {
708
- const srcPath = (0, import_node_path4.join)((0, import_node_path4.dirname)(__filename), "..", "queries");
758
+ const srcPath = (0, import_node_path5.join)((0, import_node_path5.dirname)(__filename), "..", "queries");
709
759
  if (require("fs").existsSync(srcPath)) return srcPath;
710
- return (0, import_node_path4.join)((0, import_node_path4.dirname)(__filename), "graph", "queries");
760
+ return (0, import_node_path5.join)((0, import_node_path5.dirname)(__filename), "graph", "queries");
711
761
  })();
712
762
  queryCache = /* @__PURE__ */ new Map();
713
763
  PRISMA_MUTATION_METHODS_BUILTIN = [
@@ -728,48 +778,22 @@ var init_ts_extractor = __esm({
728
778
  });
729
779
 
730
780
  // src/server/graph/parsers/ts/typescript-project.ts
731
- function walk(dir, exts) {
732
- const results = [];
733
- if (!(0, import_node_fs5.existsSync)(dir)) return results;
734
- for (const entry of (0, import_node_fs5.readdirSync)(dir, { withFileTypes: true })) {
735
- const full = (0, import_node_path5.join)(dir, entry.name);
736
- if (entry.isDirectory()) {
737
- results.push(...walk(full, exts));
738
- } else if (exts.includes((0, import_node_path5.extname)(entry.name))) {
739
- results.push(full);
740
- }
741
- }
742
- return results;
743
- }
744
- function walkWithIgnore(dir, exts, ignoreDirs) {
745
- const results = [];
746
- if (!(0, import_node_fs5.existsSync)(dir)) return results;
747
- for (const entry of (0, import_node_fs5.readdirSync)(dir, { withFileTypes: true })) {
748
- if (entry.isDirectory()) {
749
- if (ignoreDirs.has(entry.name)) continue;
750
- results.push(...walkWithIgnore((0, import_node_path5.join)(dir, entry.name), exts, ignoreDirs));
751
- } else if (exts.includes((0, import_node_path5.extname)(entry.name))) {
752
- results.push((0, import_node_path5.join)(dir, entry.name));
753
- }
754
- }
755
- return results;
756
- }
757
781
  function toNodeId(srcDir, absPath) {
758
- return (0, import_node_path5.relative)(srcDir, absPath).replace(/\\/g, "/");
782
+ return (0, import_node_path6.relative)(srcDir, absPath).replace(/\\/g, "/");
759
783
  }
760
784
  function resolveImport(srcDir, specifier) {
761
785
  if (!specifier.startsWith("@/")) return null;
762
786
  const rel = specifier.slice(2);
763
- const base = (0, import_node_path5.join)(srcDir, rel);
764
- for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path5.join)(base, "index.ts"), (0, import_node_path5.join)(base, "index.tsx")]) {
765
- if ((0, import_node_fs5.existsSync)(c) && (0, import_node_fs5.statSync)(c).isFile()) return c;
787
+ const base = (0, import_node_path6.join)(srcDir, rel);
788
+ for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path6.join)(base, "index.ts"), (0, import_node_path6.join)(base, "index.tsx")]) {
789
+ if ((0, import_node_fs6.existsSync)(c) && (0, import_node_fs6.statSync)(c).isFile()) return c;
766
790
  }
767
791
  return null;
768
792
  }
769
793
  function resolveRelativeImport(fromFile, specifier) {
770
- const base = (0, import_node_path5.join)((0, import_node_path5.dirname)(fromFile), specifier);
771
- for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path5.join)(base, "index.ts"), (0, import_node_path5.join)(base, "index.tsx")]) {
772
- if ((0, import_node_fs5.existsSync)(c) && (0, import_node_fs5.statSync)(c).isFile()) return c;
794
+ const base = (0, import_node_path6.join)((0, import_node_path6.dirname)(fromFile), specifier);
795
+ for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path6.join)(base, "index.ts"), (0, import_node_path6.join)(base, "index.tsx")]) {
796
+ if ((0, import_node_fs6.existsSync)(c) && (0, import_node_fs6.statSync)(c).isFile()) return c;
773
797
  }
774
798
  return null;
775
799
  }
@@ -790,7 +814,7 @@ function resolveBarrelMap(barrelAbsPath, parsedByPath, memo, visiting) {
790
814
  const resolved = resolveRelativeImport(barrelAbsPath, re.from);
791
815
  if (!resolved) continue;
792
816
  if (re.isWildcard) {
793
- const targetBn = (0, import_node_path5.basename)(resolved);
817
+ const targetBn = (0, import_node_path6.basename)(resolved);
794
818
  const targetIsBarrel = targetBn === "index.ts" || targetBn === "index.tsx";
795
819
  if (targetIsBarrel) {
796
820
  const nested = resolveBarrelMap(resolved, parsedByPath, memo, visiting);
@@ -817,12 +841,12 @@ function buildAllBarrelMaps(srcDir, parsedByPath) {
817
841
  const barrels = /* @__PURE__ */ new Map();
818
842
  const memo = /* @__PURE__ */ new Map();
819
843
  for (const [absPath, parsed] of parsedByPath) {
820
- const bn = (0, import_node_path5.basename)(absPath);
844
+ const bn = (0, import_node_path6.basename)(absPath);
821
845
  if (bn !== "index.ts" && bn !== "index.tsx") continue;
822
846
  if (parsed.reExports.length === 0) continue;
823
847
  const map = resolveBarrelMap(absPath, parsedByPath, memo, /* @__PURE__ */ new Set());
824
848
  if (map.size > 0) {
825
- const barrelId = (0, import_node_path5.relative)(srcDir, (0, import_node_path5.dirname)(absPath)).replace(/\\/g, "/");
849
+ const barrelId = (0, import_node_path6.relative)(srcDir, (0, import_node_path6.dirname)(absPath)).replace(/\\/g, "/");
826
850
  barrels.set(barrelId, map);
827
851
  }
828
852
  }
@@ -843,10 +867,10 @@ function extractRoute(id) {
843
867
  return route || "/";
844
868
  }
845
869
  function nameFromFilename(absPath) {
846
- return (0, import_node_path5.basename)(absPath, (0, import_node_path5.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
870
+ return (0, import_node_path6.basename)(absPath, (0, import_node_path6.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
847
871
  }
848
872
  function filePathToApiRoute(apiDir, absPath) {
849
- let route = "/" + (0, import_node_path5.relative)(apiDir, absPath).replace(/\\/g, "/").replace(/\/route\.tsx?$/, "");
873
+ let route = "/" + (0, import_node_path6.relative)(apiDir, absPath).replace(/\\/g, "/").replace(/\/route\.tsx?$/, "");
850
874
  route = route.replace(/\[([^\]]+)\]/g, ":$1");
851
875
  route = route.replace(/\/+/g, "/");
852
876
  if (route === "/") return "/api";
@@ -1030,12 +1054,9 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
1030
1054
  }
1031
1055
  return { edges, flagged };
1032
1056
  }
1033
- function hasNextConfig(rootDir) {
1034
- return (0, import_node_fs5.existsSync)((0, import_node_path5.join)(rootDir, "next.config.ts")) || (0, import_node_fs5.existsSync)((0, import_node_path5.join)(rootDir, "next.config.js")) || (0, import_node_fs5.existsSync)((0, import_node_path5.join)(rootDir, "next.config.mjs"));
1035
- }
1036
1057
  function detect(rootDir) {
1037
1058
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
1038
- return paths !== null && hasNextConfig(rootDir);
1059
+ return paths !== null;
1039
1060
  }
1040
1061
  function generate(rootDir) {
1041
1062
  const config = loadConfig(rootDir);
@@ -1043,10 +1064,10 @@ function generate(rootDir) {
1043
1064
  const srcDir = paths.srcDir;
1044
1065
  const apiDir = paths.apiDir;
1045
1066
  const appFiles = walk(paths.appDir, [".tsx", ".ts"]);
1046
- const clientFiles = walk((0, import_node_path5.join)(srcDir, "client"), [".tsx", ".ts"]);
1047
- const serverFiles = walk((0, import_node_path5.join)(srcDir, "server"), [".ts", ".tsx"]);
1048
- const libFiles = walk((0, import_node_path5.join)(srcDir, "lib"), [".ts", ".tsx"]);
1049
- const configFiles = walk((0, import_node_path5.join)(srcDir, "config"), [".ts", ".tsx"]);
1067
+ const clientFiles = walk((0, import_node_path6.join)(srcDir, "client"), [".tsx", ".ts"]);
1068
+ const serverFiles = walk((0, import_node_path6.join)(srcDir, "server"), [".ts", ".tsx"]);
1069
+ const libFiles = walk((0, import_node_path6.join)(srcDir, "lib"), [".ts", ".tsx"]);
1070
+ const configFiles = walk((0, import_node_path6.join)(srcDir, "config"), [".ts", ".tsx"]);
1050
1071
  const allDiscovered = [...appFiles, ...clientFiles, ...serverFiles, ...libFiles, ...configFiles];
1051
1072
  const parsedByPath = /* @__PURE__ */ new Map();
1052
1073
  for (const absPath of allDiscovered) {
@@ -1057,7 +1078,7 @@ function generate(rootDir) {
1057
1078
  const apiNodes = [];
1058
1079
  const nodeIdSet = /* @__PURE__ */ new Set();
1059
1080
  const routeToNodeId = /* @__PURE__ */ new Map();
1060
- const fileSet = allDiscovered.filter((f) => !(0, import_node_path5.basename)(f).startsWith("index."));
1081
+ const fileSet = allDiscovered.filter((f) => !(0, import_node_path6.basename)(f).startsWith("index."));
1061
1082
  for (const absPath of fileSet) {
1062
1083
  const id = toNodeId(srcDir, absPath);
1063
1084
  const type = classifyType(absPath, id);
@@ -1074,7 +1095,7 @@ function generate(rootDir) {
1074
1095
  const dbCalls = extractDbCallsTS(absPath);
1075
1096
  const authWrappers = extractAuthWrappersTS(absPath);
1076
1097
  const deep = extractDeep(absPath);
1077
- const routePath = (0, import_node_fs5.existsSync)(apiDir) ? filePathToApiRoute(apiDir, absPath) : `/api/${id.replace(/\/route\.tsx?$/, "")}`;
1098
+ const routePath = (0, import_node_fs6.existsSync)(apiDir) ? filePathToApiRoute(apiDir, absPath) : `/api/${id.replace(/\/route\.tsx?$/, "")}`;
1078
1099
  const mutations = dbCalls.filter((c) => c.isMutation);
1079
1100
  const mutates = mutations.length > 0;
1080
1101
  const authStrategy = [...authWrappers];
@@ -1151,20 +1172,7 @@ function generate(rootDir) {
1151
1172
  });
1152
1173
  }
1153
1174
  const externalScanned = new Set(allDiscovered.map((f) => f.replace(/\\/g, "/")));
1154
- const IGNORE_DIRS2 = /* @__PURE__ */ new Set([
1155
- "node_modules",
1156
- ".next",
1157
- "dist",
1158
- ".launchsecure",
1159
- ".git",
1160
- "src",
1161
- "coverage",
1162
- ".turbo",
1163
- "build",
1164
- "out",
1165
- ".vercel"
1166
- ]);
1167
- const externalCandidates = walkWithIgnore(rootDir, [".ts", ".tsx"], IGNORE_DIRS2);
1175
+ const externalCandidates = walkWithIgnore(rootDir, [".ts", ".tsx"], { extraIgnore: /* @__PURE__ */ new Set(["src"]) });
1168
1176
  for (const absPath of externalCandidates) {
1169
1177
  const normalized = absPath.replace(/\\/g, "/");
1170
1178
  if (externalScanned.has(normalized)) continue;
@@ -1174,7 +1182,7 @@ function generate(rootDir) {
1174
1182
  } catch {
1175
1183
  continue;
1176
1184
  }
1177
- const externalId = (0, import_node_path5.relative)(rootDir, absPath).replace(/\\/g, "/");
1185
+ const externalId = (0, import_node_path6.relative)(rootDir, absPath).replace(/\\/g, "/");
1178
1186
  const edgesFromThis = [];
1179
1187
  const seen = /* @__PURE__ */ new Set();
1180
1188
  for (const imp of parsed.imports) {
@@ -1370,14 +1378,15 @@ function generate(rootDir) {
1370
1378
  }
1371
1379
  return result;
1372
1380
  }
1373
- var import_node_fs5, import_node_path5, HTTP_METHODS, CLASSIFICATION_TO_LAYER, typescriptProjectParser;
1381
+ var import_node_fs6, import_node_path6, HTTP_METHODS, CLASSIFICATION_TO_LAYER, typescriptProjectParser;
1374
1382
  var init_typescript_project = __esm({
1375
1383
  "src/server/graph/parsers/ts/typescript-project.ts"() {
1376
1384
  "use strict";
1377
- import_node_fs5 = require("node:fs");
1378
- import_node_path5 = require("node:path");
1385
+ import_node_fs6 = require("node:fs");
1386
+ import_node_path6 = require("node:path");
1379
1387
  init_config();
1380
1388
  init_resolve_paths();
1389
+ init_walk();
1381
1390
  init_ts_extractor();
1382
1391
  HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
1383
1392
  CLASSIFICATION_TO_LAYER = {
@@ -1493,11 +1502,11 @@ function parseEnums(content) {
1493
1502
  return nodes;
1494
1503
  }
1495
1504
  function detect2(rootDir) {
1496
- return (0, import_node_fs6.existsSync)((0, import_node_path6.join)(rootDir, "prisma", "schema.prisma"));
1505
+ return (0, import_node_fs7.existsSync)((0, import_node_path7.join)(rootDir, "prisma", "schema.prisma"));
1497
1506
  }
1498
1507
  function generate2(rootDir) {
1499
- const schemaPath = (0, import_node_path6.join)(rootDir, "prisma", "schema.prisma");
1500
- const content = (0, import_node_fs6.readFileSync)(schemaPath, "utf-8");
1508
+ const schemaPath = (0, import_node_path7.join)(rootDir, "prisma", "schema.prisma");
1509
+ const content = (0, import_node_fs7.readFileSync)(schemaPath, "utf-8");
1501
1510
  const { nodes: modelNodes, relations } = parseModels(content);
1502
1511
  const enumNodes = parseEnums(content);
1503
1512
  const allNodes = [...modelNodes, ...enumNodes];
@@ -1546,12 +1555,12 @@ function generate2(rootDir) {
1546
1555
  }
1547
1556
  };
1548
1557
  }
1549
- var import_node_fs6, import_node_path6, prismaSchemaParser;
1558
+ var import_node_fs7, import_node_path7, prismaSchemaParser;
1550
1559
  var init_prisma_schema = __esm({
1551
1560
  "src/server/graph/parsers/db/prisma-schema.ts"() {
1552
1561
  "use strict";
1553
- import_node_fs6 = require("node:fs");
1554
- import_node_path6 = require("node:path");
1562
+ import_node_fs7 = require("node:fs");
1563
+ import_node_path7 = require("node:path");
1555
1564
  prismaSchemaParser = {
1556
1565
  id: "prisma-schema",
1557
1566
  layer: "db",
@@ -1685,19 +1694,19 @@ function parseUniqueIndex(sql, state) {
1685
1694
  }
1686
1695
  }
1687
1696
  function parseMigrations(rootDir) {
1688
- const migrationsDir = (0, import_node_path7.join)(rootDir, "prisma", "migrations");
1697
+ const migrationsDir = (0, import_node_path8.join)(rootDir, "prisma", "migrations");
1689
1698
  const state = {
1690
1699
  tables: /* @__PURE__ */ new Map(),
1691
1700
  enums: /* @__PURE__ */ new Map(),
1692
1701
  fks: [],
1693
1702
  uniqueIndexes: /* @__PURE__ */ new Map()
1694
1703
  };
1695
- if (!(0, import_node_fs7.existsSync)(migrationsDir)) return state;
1696
- const dirs = (0, import_node_fs7.readdirSync)(migrationsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
1704
+ if (!(0, import_node_fs8.existsSync)(migrationsDir)) return state;
1705
+ const dirs = (0, import_node_fs8.readdirSync)(migrationsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
1697
1706
  for (const dir of dirs) {
1698
- const sqlPath = (0, import_node_path7.join)(migrationsDir, dir, "migration.sql");
1699
- if (!(0, import_node_fs7.existsSync)(sqlPath)) continue;
1700
- const sql = (0, import_node_fs7.readFileSync)(sqlPath, "utf-8");
1707
+ const sqlPath = (0, import_node_path8.join)(migrationsDir, dir, "migration.sql");
1708
+ if (!(0, import_node_fs8.existsSync)(sqlPath)) continue;
1709
+ const sql = (0, import_node_fs8.readFileSync)(sqlPath, "utf-8");
1701
1710
  parseCreateEnum(sql, state);
1702
1711
  parseCreateTable(sql, state);
1703
1712
  parseAlterTable(sql, state);
@@ -1708,9 +1717,9 @@ function parseMigrations(rootDir) {
1708
1717
  return state;
1709
1718
  }
1710
1719
  function loadPrismaState(rootDir) {
1711
- const schemaPath = (0, import_node_path7.join)(rootDir, "prisma", "schema.prisma");
1712
- if (!(0, import_node_fs7.existsSync)(schemaPath)) return null;
1713
- const content = (0, import_node_fs7.readFileSync)(schemaPath, "utf-8");
1720
+ const schemaPath = (0, import_node_path8.join)(rootDir, "prisma", "schema.prisma");
1721
+ if (!(0, import_node_fs8.existsSync)(schemaPath)) return null;
1722
+ const content = (0, import_node_fs8.readFileSync)(schemaPath, "utf-8");
1714
1723
  const tables = /* @__PURE__ */ new Map();
1715
1724
  const enums = /* @__PURE__ */ new Map();
1716
1725
  const relations = [];
@@ -1875,9 +1884,9 @@ function verify(sqlState, prisma) {
1875
1884
  return { contradictions, flaggedEdges };
1876
1885
  }
1877
1886
  function detect3(rootDir) {
1878
- const migrationsDir = (0, import_node_path7.join)(rootDir, "prisma", "migrations");
1879
- if (!(0, import_node_fs7.existsSync)(migrationsDir)) return false;
1880
- return (0, import_node_fs7.readdirSync)(migrationsDir, { withFileTypes: true }).some((d) => d.isDirectory() && (0, import_node_fs7.existsSync)((0, import_node_path7.join)(migrationsDir, d.name, "migration.sql")));
1887
+ const migrationsDir = (0, import_node_path8.join)(rootDir, "prisma", "migrations");
1888
+ if (!(0, import_node_fs8.existsSync)(migrationsDir)) return false;
1889
+ return (0, import_node_fs8.readdirSync)(migrationsDir, { withFileTypes: true }).some((d) => d.isDirectory() && (0, import_node_fs8.existsSync)((0, import_node_path8.join)(migrationsDir, d.name, "migration.sql")));
1881
1890
  }
1882
1891
  function generate3(rootDir) {
1883
1892
  const sqlState = parseMigrations(rootDir);
@@ -1944,12 +1953,12 @@ function generate3(rootDir) {
1944
1953
  flagged_edges: flaggedEdges
1945
1954
  };
1946
1955
  }
1947
- var import_node_fs7, import_node_path7, PG_TO_PRISMA, sqlMigrationsParser;
1956
+ var import_node_fs8, import_node_path8, PG_TO_PRISMA, sqlMigrationsParser;
1948
1957
  var init_sql_migrations = __esm({
1949
1958
  "src/server/graph/parsers/db/sql-migrations.ts"() {
1950
1959
  "use strict";
1951
- import_node_fs7 = require("node:fs");
1952
- import_node_path7 = require("node:path");
1960
+ import_node_fs8 = require("node:fs");
1961
+ import_node_path8 = require("node:path");
1953
1962
  PG_TO_PRISMA = {
1954
1963
  "TEXT": "String",
1955
1964
  "VARCHAR": "String",
@@ -2212,28 +2221,28 @@ var init_fetch_resolver = __esm({
2212
2221
 
2213
2222
  // src/server/graph/parsers/crosslayer/api-annotations.ts
2214
2223
  function walk2(dir, exts) {
2215
- if (!(0, import_node_fs8.existsSync)(dir)) return [];
2224
+ if (!(0, import_node_fs9.existsSync)(dir)) return [];
2216
2225
  const results = [];
2217
- for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
2226
+ for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
2218
2227
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
2219
- const full = (0, import_node_path8.join)(dir, entry.name);
2228
+ const full = (0, import_node_path9.join)(dir, entry.name);
2220
2229
  if (entry.isDirectory()) {
2221
2230
  results.push(...walk2(full, exts));
2222
- } else if (exts.includes((0, import_node_path8.extname)(entry.name))) {
2231
+ } else if (exts.includes((0, import_node_path9.extname)(entry.name))) {
2223
2232
  results.push(full);
2224
2233
  }
2225
2234
  }
2226
2235
  return results;
2227
2236
  }
2228
2237
  function toNodeId2(srcDir, absPath) {
2229
- return (0, import_node_path8.relative)(srcDir, absPath).replace(/\\/g, "/");
2238
+ return (0, import_node_path9.relative)(srcDir, absPath).replace(/\\/g, "/");
2230
2239
  }
2231
- var import_node_fs8, import_node_path8, API_ANNOTATION_RE, apiAnnotationsParser;
2240
+ var import_node_fs9, import_node_path9, API_ANNOTATION_RE, apiAnnotationsParser;
2232
2241
  var init_api_annotations = __esm({
2233
2242
  "src/server/graph/parsers/crosslayer/api-annotations.ts"() {
2234
2243
  "use strict";
2235
- import_node_fs8 = require("node:fs");
2236
- import_node_path8 = require("node:path");
2244
+ import_node_fs9 = require("node:fs");
2245
+ import_node_path9 = require("node:path");
2237
2246
  init_api_route_matching();
2238
2247
  API_ANNOTATION_RE = /@api\s+(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/\S+)/g;
2239
2248
  apiAnnotationsParser = {
@@ -2241,7 +2250,7 @@ var init_api_annotations = __esm({
2241
2250
  layer: "crosslayer",
2242
2251
  concern: "api-binding",
2243
2252
  detect(rootDir) {
2244
- return (0, import_node_fs8.existsSync)((0, import_node_path8.join)(rootDir, "src"));
2253
+ return (0, import_node_fs9.existsSync)((0, import_node_path9.join)(rootDir, "src"));
2245
2254
  },
2246
2255
  generate(rootDir, layerOutputs) {
2247
2256
  const apiOutput = layerOutputs.get("api");
@@ -2252,13 +2261,13 @@ var init_api_annotations = __esm({
2252
2261
  const uiNodeIds = new Set(uiOutput?.nodes.map((n) => n.id) ?? []);
2253
2262
  const apiRoutes = loadApiRoutesFromOutput(apiOutput);
2254
2263
  const apiPathMap = buildApiPathMap(apiRoutes);
2255
- const srcDir = (0, import_node_path8.join)(rootDir, "src");
2264
+ const srcDir = (0, import_node_path9.join)(rootDir, "src");
2256
2265
  const files = walk2(srcDir, [".ts", ".tsx"]);
2257
2266
  const crossRefs = [];
2258
2267
  const flaggedEdges = [];
2259
2268
  const seen = /* @__PURE__ */ new Set();
2260
2269
  for (const absPath of files) {
2261
- const content = (0, import_node_fs8.readFileSync)(absPath, "utf-8");
2270
+ const content = (0, import_node_fs9.readFileSync)(absPath, "utf-8");
2262
2271
  const sourceId = toNodeId2(srcDir, absPath);
2263
2272
  if (!uiNodeIds.has(sourceId)) continue;
2264
2273
  let match;
@@ -2305,28 +2314,28 @@ var init_api_annotations = __esm({
2305
2314
 
2306
2315
  // src/server/graph/parsers/crosslayer/url-literal-scanner.ts
2307
2316
  function walk3(dir, exts) {
2308
- if (!(0, import_node_fs9.existsSync)(dir)) return [];
2317
+ if (!(0, import_node_fs10.existsSync)(dir)) return [];
2309
2318
  const results = [];
2310
- for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
2319
+ for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true })) {
2311
2320
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
2312
- const full = (0, import_node_path9.join)(dir, entry.name);
2321
+ const full = (0, import_node_path10.join)(dir, entry.name);
2313
2322
  if (entry.isDirectory()) {
2314
2323
  results.push(...walk3(full, exts));
2315
- } else if (exts.includes((0, import_node_path9.extname)(entry.name))) {
2324
+ } else if (exts.includes((0, import_node_path10.extname)(entry.name))) {
2316
2325
  results.push(full);
2317
2326
  }
2318
2327
  }
2319
2328
  return results;
2320
2329
  }
2321
2330
  function toNodeId3(srcDir, absPath) {
2322
- return (0, import_node_path9.relative)(srcDir, absPath).replace(/\\/g, "/");
2331
+ return (0, import_node_path10.relative)(srcDir, absPath).replace(/\\/g, "/");
2323
2332
  }
2324
- var import_node_fs9, import_node_path9, URL_LITERAL_RE, urlLiteralScannerParser;
2333
+ var import_node_fs10, import_node_path10, URL_LITERAL_RE, urlLiteralScannerParser;
2325
2334
  var init_url_literal_scanner = __esm({
2326
2335
  "src/server/graph/parsers/crosslayer/url-literal-scanner.ts"() {
2327
2336
  "use strict";
2328
- import_node_fs9 = require("node:fs");
2329
- import_node_path9 = require("node:path");
2337
+ import_node_fs10 = require("node:fs");
2338
+ import_node_path10 = require("node:path");
2330
2339
  init_api_route_matching();
2331
2340
  init_config();
2332
2341
  init_resolve_paths();
@@ -2350,7 +2359,7 @@ var init_url_literal_scanner = __esm({
2350
2359
  const apiPathMap = buildApiPathMap(apiRoutes);
2351
2360
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
2352
2361
  const srcDir = paths.srcDir;
2353
- const clientDir = (0, import_node_path9.join)(srcDir, "client");
2362
+ const clientDir = (0, import_node_path10.join)(srcDir, "client");
2354
2363
  const files = [
2355
2364
  ...walk3(clientDir, [".ts", ".tsx"]),
2356
2365
  ...walk3(paths.appDir, [".ts", ".tsx"])
@@ -2360,7 +2369,7 @@ var init_url_literal_scanner = __esm({
2360
2369
  for (const absPath of files) {
2361
2370
  const sourceId = toNodeId3(srcDir, absPath);
2362
2371
  if (!uiNodeIds.has(sourceId)) continue;
2363
- const content = (0, import_node_fs9.readFileSync)(absPath, "utf-8");
2372
+ const content = (0, import_node_fs10.readFileSync)(absPath, "utf-8");
2364
2373
  let match;
2365
2374
  URL_LITERAL_RE.lastIndex = 0;
2366
2375
  while ((match = URL_LITERAL_RE.exec(content)) !== null) {
@@ -2422,19 +2431,19 @@ function extractEnumValues(rootDir) {
2422
2431
  const nodes = [];
2423
2432
  const edges = [];
2424
2433
  const schemaPaths = [
2425
- (0, import_node_path10.join)(rootDir, "prisma", "schema.prisma"),
2426
- (0, import_node_path10.join)(rootDir, "prisma", "schema")
2434
+ (0, import_node_path11.join)(rootDir, "prisma", "schema.prisma"),
2435
+ (0, import_node_path11.join)(rootDir, "prisma", "schema")
2427
2436
  ];
2428
2437
  let content = "";
2429
2438
  for (const p of schemaPaths) {
2430
- if ((0, import_node_fs10.existsSync)(p)) {
2439
+ if ((0, import_node_fs11.existsSync)(p)) {
2431
2440
  try {
2432
- const stat = (0, import_node_fs10.statSync)(p);
2441
+ const stat = (0, import_node_fs11.statSync)(p);
2433
2442
  if (stat.isFile()) {
2434
- content = (0, import_node_fs10.readFileSync)(p, "utf-8");
2443
+ content = (0, import_node_fs11.readFileSync)(p, "utf-8");
2435
2444
  } else if (stat.isDirectory()) {
2436
- const files = (0, import_node_fs10.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
2437
- content = files.map((f) => (0, import_node_fs10.readFileSync)((0, import_node_path10.join)(p, f), "utf-8")).join("\n");
2445
+ const files = (0, import_node_fs11.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
2446
+ content = files.map((f) => (0, import_node_fs11.readFileSync)((0, import_node_path11.join)(p, f), "utf-8")).join("\n");
2438
2447
  }
2439
2448
  } catch {
2440
2449
  continue;
@@ -2508,7 +2517,7 @@ function extractStringArrayFromNode(node) {
2508
2517
  return values;
2509
2518
  }
2510
2519
  function findArrayDecl(root, varName) {
2511
- function walk5(node) {
2520
+ function walk4(node) {
2512
2521
  if (node.type === "variable_declarator") {
2513
2522
  const nameNode = node.childForFieldName("name");
2514
2523
  const valueNode = node.childForFieldName("value");
@@ -2521,12 +2530,12 @@ function findArrayDecl(root, varName) {
2521
2530
  }
2522
2531
  }
2523
2532
  for (const child of node.namedChildren) {
2524
- const found = walk5(child);
2533
+ const found = walk4(child);
2525
2534
  if (found) return found;
2526
2535
  }
2527
2536
  return null;
2528
2537
  }
2529
- return walk5(root);
2538
+ return walk4(root);
2530
2539
  }
2531
2540
  function extractObjectPropsRegex(objStr) {
2532
2541
  const props = {};
@@ -2590,14 +2599,14 @@ function extractSeedData(rootDir) {
2590
2599
  const nodes = [];
2591
2600
  const edges = [];
2592
2601
  const seedFiles = [
2593
- (0, import_node_path10.join)(rootDir, "prisma", "seed.ts"),
2594
- (0, import_node_path10.join)(rootDir, "prisma", "seed.js"),
2595
- (0, import_node_path10.join)(rootDir, "src", "server", "lib", "system-tags.ts")
2596
- ].filter(import_node_fs10.existsSync);
2602
+ (0, import_node_path11.join)(rootDir, "prisma", "seed.ts"),
2603
+ (0, import_node_path11.join)(rootDir, "prisma", "seed.js"),
2604
+ (0, import_node_path11.join)(rootDir, "src", "server", "lib", "system-tags.ts")
2605
+ ].filter(import_node_fs11.existsSync);
2597
2606
  const useTreeSitter = tryLoadTreeSitter();
2598
2607
  for (const filePath of seedFiles) {
2599
- const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
2600
- const relPath = (0, import_node_path10.relative)(rootDir, filePath);
2608
+ const content = (0, import_node_fs11.readFileSync)(filePath, "utf-8");
2609
+ const relPath = (0, import_node_path11.relative)(rootDir, filePath);
2601
2610
  const seeded = detectSeededArrays(content, relPath);
2602
2611
  let astRoot = null;
2603
2612
  if (useTreeSitter && parseCode) {
@@ -2691,11 +2700,11 @@ function extractSeedData(rootDir) {
2691
2700
  return { nodes, edges };
2692
2701
  }
2693
2702
  function walkDir(dir, exts) {
2694
- if (!(0, import_node_fs10.existsSync)(dir)) return [];
2703
+ if (!(0, import_node_fs11.existsSync)(dir)) return [];
2695
2704
  const results = [];
2696
- for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true })) {
2705
+ for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
2697
2706
  if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
2698
- const full = (0, import_node_path10.join)(dir, entry.name);
2707
+ const full = (0, import_node_path11.join)(dir, entry.name);
2699
2708
  if (entry.isDirectory()) results.push(...walkDir(full, exts));
2700
2709
  else if (exts.some((ext) => entry.name.endsWith(ext))) results.push(full);
2701
2710
  }
@@ -2703,11 +2712,11 @@ function walkDir(dir, exts) {
2703
2712
  }
2704
2713
  function extractConstants(rootDir) {
2705
2714
  const nodes = [];
2706
- const srcDir = (0, import_node_path10.join)(rootDir, "src");
2707
- if (!(0, import_node_fs10.existsSync)(srcDir)) return { nodes };
2715
+ const srcDir = (0, import_node_path11.join)(rootDir, "src");
2716
+ if (!(0, import_node_fs11.existsSync)(srcDir)) return { nodes };
2708
2717
  for (const filePath of walkDir(srcDir, [".ts", ".tsx"])) {
2709
- const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
2710
- const relPath = (0, import_node_path10.relative)(rootDir, filePath);
2718
+ const content = (0, import_node_fs11.readFileSync)(filePath, "utf-8");
2719
+ const relPath = (0, import_node_path11.relative)(rootDir, filePath);
2711
2720
  const constArrayRe = /export\s+const\s+([A-Z][A-Z_0-9]+)\s*(?::[^=]+)?\s*=\s*\[/g;
2712
2721
  let cm;
2713
2722
  while ((cm = constArrayRe.exec(content)) !== null) {
@@ -2740,7 +2749,7 @@ function extractConstants(rootDir) {
2740
2749
  return { nodes };
2741
2750
  }
2742
2751
  function detect4(rootDir) {
2743
- return (0, import_node_fs10.existsSync)((0, import_node_path10.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs10.existsSync)((0, import_node_path10.join)(rootDir, "prisma", "seed.ts"));
2752
+ return (0, import_node_fs11.existsSync)((0, import_node_path11.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs11.existsSync)((0, import_node_path11.join)(rootDir, "prisma", "seed.ts"));
2744
2753
  }
2745
2754
  function generate4(rootDir) {
2746
2755
  const enumResult = extractEnumValues(rootDir);
@@ -2807,12 +2816,12 @@ function generate4(rootDir) {
2807
2816
  }
2808
2817
  };
2809
2818
  }
2810
- var import_node_fs10, import_node_path10, parseCode, SHARED_MODELS, DB_MODELS, staticValuesParser;
2819
+ var import_node_fs11, import_node_path11, parseCode, SHARED_MODELS, DB_MODELS, staticValuesParser;
2811
2820
  var init_static_values = __esm({
2812
2821
  "src/server/graph/parsers/static/static-values.ts"() {
2813
2822
  "use strict";
2814
- import_node_fs10 = require("node:fs");
2815
- import_node_path10 = require("node:path");
2823
+ import_node_fs11 = require("node:fs");
2824
+ import_node_path11 = require("node:path");
2816
2825
  parseCode = null;
2817
2826
  SHARED_MODELS = /* @__PURE__ */ new Set(["permission", "role", "tag"]);
2818
2827
  DB_MODELS = /* @__PURE__ */ new Set(["subscriptionPlan", "providerDefinition", "pipelineMasterTemplate"]);
@@ -2826,23 +2835,6 @@ var init_static_values = __esm({
2826
2835
  });
2827
2836
 
2828
2837
  // src/server/graph/parsers/crosslayer/static-ref-scanner.ts
2829
- function walk4(dir, exts) {
2830
- if (!(0, import_node_fs11.existsSync)(dir)) return [];
2831
- const results = [];
2832
- function recurse(d) {
2833
- for (const entry of (0, import_node_fs11.readdirSync)(d, { withFileTypes: true })) {
2834
- const full = (0, import_node_path11.join)(d, entry.name);
2835
- if (entry.isDirectory()) {
2836
- if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
2837
- recurse(full);
2838
- } else if (exts.some((ext) => entry.name.endsWith(ext))) {
2839
- results.push(full);
2840
- }
2841
- }
2842
- }
2843
- recurse(dir);
2844
- return results;
2845
- }
2846
2838
  function isInCommentOrType(node) {
2847
2839
  let current = node.parent;
2848
2840
  while (current) {
@@ -2927,14 +2919,15 @@ function collectStaticRefsRegex(content, valueLookup, allValues) {
2927
2919
  }
2928
2920
  return refs;
2929
2921
  }
2930
- var import_node_fs11, import_node_path11, MIN_VALUE_LENGTH, SKIP_VALUES, staticRefScannerParser;
2922
+ var import_node_fs12, import_node_path12, MIN_VALUE_LENGTH, SKIP_VALUES, staticRefScannerParser;
2931
2923
  var init_static_ref_scanner = __esm({
2932
2924
  "src/server/graph/parsers/crosslayer/static-ref-scanner.ts"() {
2933
2925
  "use strict";
2934
- import_node_fs11 = require("node:fs");
2935
- import_node_path11 = require("node:path");
2926
+ import_node_fs12 = require("node:fs");
2927
+ import_node_path12 = require("node:path");
2936
2928
  init_config();
2937
2929
  init_resolve_paths();
2930
+ init_walk();
2938
2931
  MIN_VALUE_LENGTH = 4;
2939
2932
  SKIP_VALUES = /* @__PURE__ */ new Set([
2940
2933
  "true",
@@ -2993,11 +2986,11 @@ var init_static_ref_scanner = __esm({
2993
2986
  if (!paths) return { cross_refs: [], flagged_edges: [], warnings: [] };
2994
2987
  const srcDir = paths.srcDir;
2995
2988
  const files = [
2996
- ...walk4((0, import_node_path11.join)(srcDir, "client"), [".ts", ".tsx"]),
2997
- ...walk4(paths.appDir, [".ts", ".tsx"]),
2998
- ...walk4((0, import_node_path11.join)(srcDir, "server"), [".ts", ".tsx"]),
2999
- ...walk4((0, import_node_path11.join)(srcDir, "lib"), [".ts", ".tsx"]),
3000
- ...walk4((0, import_node_path11.join)(srcDir, "config"), [".ts", ".tsx"])
2989
+ ...walkWithIgnore((0, import_node_path12.join)(srcDir, "client"), [".ts", ".tsx"]),
2990
+ ...walkWithIgnore(paths.appDir, [".ts", ".tsx"]),
2991
+ ...walkWithIgnore((0, import_node_path12.join)(srcDir, "server"), [".ts", ".tsx"]),
2992
+ ...walkWithIgnore((0, import_node_path12.join)(srcDir, "lib"), [".ts", ".tsx"]),
2993
+ ...walkWithIgnore((0, import_node_path12.join)(srcDir, "config"), [".ts", ".tsx"])
3001
2994
  ];
3002
2995
  const uiOutput = layerOutputs.get("ui");
3003
2996
  const apiOutput = layerOutputs.get("api");
@@ -3015,10 +3008,10 @@ var init_static_ref_scanner = __esm({
3015
3008
  const seen = /* @__PURE__ */ new Set();
3016
3009
  let filesScanned = 0;
3017
3010
  for (const absPath of files) {
3018
- const sourceId = (0, import_node_path11.relative)(srcDir, absPath).replace(/\\/g, "/");
3011
+ const sourceId = (0, import_node_path12.relative)(srcDir, absPath).replace(/\\/g, "/");
3019
3012
  const sourceLayer = uiNodeIds.has(sourceId) ? "ui" : apiNodeIds.has(sourceId) ? "api" : null;
3020
3013
  if (!sourceLayer) continue;
3021
- const content = (0, import_node_fs11.readFileSync)(absPath, "utf-8");
3014
+ const content = (0, import_node_fs12.readFileSync)(absPath, "utf-8");
3022
3015
  filesScanned++;
3023
3016
  let fileRefs;
3024
3017
  if (parseCode2) {
@@ -3084,7 +3077,7 @@ function registerBuiltins(registry, disabled) {
3084
3077
  function loadCustomParsers(registry, config, rootDir, disabled) {
3085
3078
  for (const entry of config.parsers?.custom ?? []) {
3086
3079
  try {
3087
- const absPath = (0, import_node_path12.resolve)(rootDir, entry.path);
3080
+ const absPath = (0, import_node_path13.resolve)(rootDir, entry.path);
3088
3081
  const mod = require(absPath);
3089
3082
  const parser = "default" in mod ? mod.default : mod;
3090
3083
  if (disabled.has(parser.id)) continue;
@@ -3111,11 +3104,11 @@ function createRegistry(config, rootDir) {
3111
3104
  loadCustomParsers(registry, config, rootDir, disabled);
3112
3105
  return registry;
3113
3106
  }
3114
- var import_node_path12, ParserRegistry;
3107
+ var import_node_path13, ParserRegistry;
3115
3108
  var init_parser_registry = __esm({
3116
3109
  "src/server/graph/core/parser-registry.ts"() {
3117
3110
  "use strict";
3118
- import_node_path12 = require("node:path");
3111
+ import_node_path13 = require("node:path");
3119
3112
  init_typescript_project();
3120
3113
  init_prisma_schema();
3121
3114
  init_sql_migrations();
@@ -3286,10 +3279,10 @@ var init_merge = __esm({
3286
3279
 
3287
3280
  // src/server/graph/core/graph-builder.ts
3288
3281
  function readGraphFromDisk(rootDir, layer) {
3289
- const filePath = (0, import_node_path13.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
3290
- if (!(0, import_node_fs12.existsSync)(filePath)) return null;
3282
+ const filePath = (0, import_node_path14.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
3283
+ if (!(0, import_node_fs13.existsSync)(filePath)) return null;
3291
3284
  try {
3292
- return JSON.parse((0, import_node_fs12.readFileSync)(filePath, "utf-8"));
3285
+ return JSON.parse((0, import_node_fs13.readFileSync)(filePath, "utf-8"));
3293
3286
  } catch {
3294
3287
  return null;
3295
3288
  }
@@ -3385,12 +3378,12 @@ function generateAll(rootDir) {
3385
3378
  const extras = [...byLayer.keys()].filter((l) => !wellKnownOrder.includes(l)).sort();
3386
3379
  return [...wellKnownOrder, ...extras].map((l) => byLayer.get(l)).filter((r) => !!r);
3387
3380
  }
3388
- var import_node_fs12, import_node_path13;
3381
+ var import_node_fs13, import_node_path14;
3389
3382
  var init_graph_builder = __esm({
3390
3383
  "src/server/graph/core/graph-builder.ts"() {
3391
3384
  "use strict";
3392
- import_node_fs12 = require("node:fs");
3393
- import_node_path13 = require("node:path");
3385
+ import_node_fs13 = require("node:fs");
3386
+ import_node_path14 = require("node:path");
3394
3387
  init_config();
3395
3388
  init_parser_registry();
3396
3389
  init_merge();
@@ -3429,18 +3422,18 @@ function detectConventionDirs(rootDir, extraConventionDirs = []) {
3429
3422
  const conventionDirs = [...CONVENTION_DIRS_BUILTIN, ...extraConventionDirs];
3430
3423
  const searchDirs = [
3431
3424
  rootDir,
3432
- (0, import_node_path14.join)(rootDir, "src"),
3433
- (0, import_node_path14.join)(rootDir, "app"),
3434
- (0, import_node_path14.join)(rootDir, "lib")
3425
+ (0, import_node_path15.join)(rootDir, "src"),
3426
+ (0, import_node_path15.join)(rootDir, "app"),
3427
+ (0, import_node_path15.join)(rootDir, "lib")
3435
3428
  ];
3436
3429
  for (const base of searchDirs) {
3437
3430
  for (const convention of conventionDirs) {
3438
- const dir = (0, import_node_path14.join)(base, convention);
3439
- if (!(0, import_node_fs13.existsSync)(dir)) continue;
3431
+ const dir = (0, import_node_path15.join)(base, convention);
3432
+ if (!(0, import_node_fs14.existsSync)(dir)) continue;
3440
3433
  try {
3441
- const stat = (0, import_node_fs13.statSync)(dir);
3434
+ const stat = (0, import_node_fs14.statSync)(dir);
3442
3435
  if (!stat.isDirectory()) continue;
3443
- const entries = (0, import_node_fs13.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
3436
+ const entries = (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
3444
3437
  if (entries.length > 0) {
3445
3438
  const relPath = dir.replace(rootDir + "/", "").replace(rootDir + "\\", "");
3446
3439
  result.set(relPath, entries);
@@ -3512,12 +3505,12 @@ function extractModuleFromPath(id, extraTrivial, extraSkipSegments) {
3512
3505
  }
3513
3506
  return "root";
3514
3507
  }
3515
- var import_node_fs13, import_node_path14, CONVENTION_DIRS_BUILTIN, GENERIC_ROLE_NAMES_BUILTIN, SKIP_SEGMENTS_BUILTIN, TRIVIAL_GROUPS, cachedRootDir, cachedConventionDirs, moduleTagger;
3508
+ var import_node_fs14, import_node_path15, CONVENTION_DIRS_BUILTIN, GENERIC_ROLE_NAMES_BUILTIN, SKIP_SEGMENTS_BUILTIN, TRIVIAL_GROUPS, cachedRootDir, cachedConventionDirs, moduleTagger;
3516
3509
  var init_module_tagger = __esm({
3517
3510
  "src/server/graph/taggers/module-tagger.ts"() {
3518
3511
  "use strict";
3519
- import_node_fs13 = require("node:fs");
3520
- import_node_path14 = require("node:path");
3512
+ import_node_fs14 = require("node:fs");
3513
+ import_node_path15 = require("node:path");
3521
3514
  CONVENTION_DIRS_BUILTIN = ["features", "modules", "domains", "areas"];
3522
3515
  GENERIC_ROLE_NAMES_BUILTIN = /* @__PURE__ */ new Set([
3523
3516
  // JS/TS
@@ -3729,7 +3722,7 @@ function loadCustomTaggers(registry, config, rootDir, disabled) {
3729
3722
  for (const entry of config.taggers?.custom ?? []) {
3730
3723
  if (disabled.has(entry.id)) continue;
3731
3724
  try {
3732
- const absPath = (0, import_node_path15.resolve)(rootDir, entry.path);
3725
+ const absPath = (0, import_node_path16.resolve)(rootDir, entry.path);
3733
3726
  const mod = require(absPath);
3734
3727
  const tagger = "default" in mod ? mod.default : mod;
3735
3728
  const override = config.taggers?.trackUntagged?.[tagger.id];
@@ -3750,11 +3743,11 @@ function createTaggerRegistry(config, rootDir) {
3750
3743
  loadCustomTaggers(registry, config, rootDir, disabled);
3751
3744
  return registry;
3752
3745
  }
3753
- var import_node_path15, TaggerRegistry, BUILTIN_TAGGERS;
3746
+ var import_node_path16, TaggerRegistry, BUILTIN_TAGGERS;
3754
3747
  var init_tagger_registry = __esm({
3755
3748
  "src/server/graph/core/tagger-registry.ts"() {
3756
3749
  "use strict";
3757
- import_node_path15 = require("node:path");
3750
+ import_node_path16 = require("node:path");
3758
3751
  init_module_tagger();
3759
3752
  init_screen_tagger();
3760
3753
  TaggerRegistry = class {
@@ -3782,18 +3775,18 @@ var init_tagger_registry = __esm({
3782
3775
 
3783
3776
  // src/server/graph/core/tag-store.ts
3784
3777
  function tagsFilePath(rootDir) {
3785
- return (0, import_node_path16.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
3778
+ return (0, import_node_path17.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
3786
3779
  }
3787
3780
  function readTagStore(rootDir) {
3788
3781
  const filePath = tagsFilePath(rootDir);
3789
- if (!(0, import_node_fs14.existsSync)(filePath)) return {};
3790
- const stat = (0, import_node_fs14.statSync)(filePath);
3782
+ if (!(0, import_node_fs15.existsSync)(filePath)) return {};
3783
+ const stat = (0, import_node_fs15.statSync)(filePath);
3791
3784
  const cached = tagCache.get(filePath);
3792
3785
  if (cached && cached.mtimeMs === stat.mtimeMs) {
3793
3786
  return cached.store;
3794
3787
  }
3795
3788
  try {
3796
- const content = (0, import_node_fs14.readFileSync)(filePath, "utf-8");
3789
+ const content = (0, import_node_fs15.readFileSync)(filePath, "utf-8");
3797
3790
  const store = JSON.parse(content);
3798
3791
  tagCache.set(filePath, { mtimeMs: stat.mtimeMs, store });
3799
3792
  return store;
@@ -3803,15 +3796,15 @@ function readTagStore(rootDir) {
3803
3796
  }
3804
3797
  function writeTagStore(rootDir, store) {
3805
3798
  const filePath = tagsFilePath(rootDir);
3806
- const dir = (0, import_node_path16.dirname)(filePath);
3807
- (0, import_node_fs14.mkdirSync)(dir, { recursive: true });
3799
+ const dir = (0, import_node_path17.dirname)(filePath);
3800
+ (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
3808
3801
  const cleaned = {};
3809
3802
  for (const [nodeId, tags] of Object.entries(store)) {
3810
3803
  if (Object.keys(tags).length > 0) {
3811
3804
  cleaned[nodeId] = tags;
3812
3805
  }
3813
3806
  }
3814
- (0, import_node_fs14.writeFileSync)(filePath, JSON.stringify(cleaned, null, 2) + "\n", "utf-8");
3807
+ (0, import_node_fs15.writeFileSync)(filePath, JSON.stringify(cleaned, null, 2) + "\n", "utf-8");
3815
3808
  tagCache.delete(filePath);
3816
3809
  }
3817
3810
  function setTag(rootDir, nodeId, key, value) {
@@ -3829,12 +3822,12 @@ function removeTag(rootDir, nodeId, key) {
3829
3822
  }
3830
3823
  writeTagStore(rootDir, store);
3831
3824
  }
3832
- var import_node_fs14, import_node_path16, TAGS_FILENAME, GRAPHS_DIR, tagCache;
3825
+ var import_node_fs15, import_node_path17, TAGS_FILENAME, GRAPHS_DIR, tagCache;
3833
3826
  var init_tag_store = __esm({
3834
3827
  "src/server/graph/core/tag-store.ts"() {
3835
3828
  "use strict";
3836
- import_node_fs14 = require("node:fs");
3837
- import_node_path16 = require("node:path");
3829
+ import_node_fs15 = require("node:fs");
3830
+ import_node_path17 = require("node:path");
3838
3831
  TAGS_FILENAME = "tags.json";
3839
3832
  GRAPHS_DIR = ".launchsecure/graphs";
3840
3833
  tagCache = /* @__PURE__ */ new Map();
@@ -3843,22 +3836,22 @@ var init_tag_store = __esm({
3843
3836
 
3844
3837
  // src/server/graph/index.ts
3845
3838
  function getAvailableLayers(rootDir) {
3846
- const dir = (0, import_node_path17.join)(rootDir, GRAPHS_DIR2);
3847
- if (!(0, import_node_fs15.existsSync)(dir)) return [];
3848
- return (0, import_node_fs15.readdirSync)(dir).filter((f) => f.endsWith(".json") && f !== "tags.json").map((f) => f.replace(".json", ""));
3839
+ const dir = (0, import_node_path18.join)(rootDir, GRAPHS_DIR2);
3840
+ if (!(0, import_node_fs16.existsSync)(dir)) return [];
3841
+ return (0, import_node_fs16.readdirSync)(dir).filter((f) => f.endsWith(".json") && f !== "tags.json").map((f) => f.replace(".json", ""));
3849
3842
  }
3850
3843
  function graphsDir(rootDir) {
3851
- return (0, import_node_path17.join)(rootDir, GRAPHS_DIR2);
3844
+ return (0, import_node_path18.join)(rootDir, GRAPHS_DIR2);
3852
3845
  }
3853
3846
  function graphFilePath(rootDir, layer) {
3854
- return (0, import_node_path17.join)(graphsDir(rootDir), `${layer}.json`);
3847
+ return (0, import_node_path18.join)(graphsDir(rootDir), `${layer}.json`);
3855
3848
  }
3856
3849
  function tagsFilePath2(rootDir) {
3857
- return (0, import_node_path17.join)(graphsDir(rootDir), "tags.json");
3850
+ return (0, import_node_path18.join)(graphsDir(rootDir), "tags.json");
3858
3851
  }
3859
3852
  function getMtimeMs(filePath) {
3860
- if (!(0, import_node_fs15.existsSync)(filePath)) return 0;
3861
- return (0, import_node_fs15.statSync)(filePath).mtimeMs;
3853
+ if (!(0, import_node_fs16.existsSync)(filePath)) return 0;
3854
+ return (0, import_node_fs16.statSync)(filePath).mtimeMs;
3862
3855
  }
3863
3856
  function invalidateCache(filePath) {
3864
3857
  graphCache.delete(filePath);
@@ -3897,20 +3890,20 @@ function applyTags(graph, layer, rootDir) {
3897
3890
  }
3898
3891
  function readGraphRaw(rootDir, layer) {
3899
3892
  const filePath = graphFilePath(rootDir, layer);
3900
- if (!(0, import_node_fs15.existsSync)(filePath)) return null;
3901
- const stat = (0, import_node_fs15.statSync)(filePath);
3893
+ if (!(0, import_node_fs16.existsSync)(filePath)) return null;
3894
+ const stat = (0, import_node_fs16.statSync)(filePath);
3902
3895
  const cached = graphCache.get(filePath);
3903
3896
  if (cached && cached.mtimeMs === stat.mtimeMs) {
3904
3897
  return cached.graph;
3905
3898
  }
3906
- const content = (0, import_node_fs15.readFileSync)(filePath, "utf-8");
3899
+ const content = (0, import_node_fs16.readFileSync)(filePath, "utf-8");
3907
3900
  const graph = JSON.parse(content);
3908
3901
  graphCache.set(filePath, { mtimeMs: stat.mtimeMs, graph });
3909
3902
  return graph;
3910
3903
  }
3911
3904
  function readGraph(rootDir, layer) {
3912
3905
  const rawFilePath = graphFilePath(rootDir, layer);
3913
- if (!(0, import_node_fs15.existsSync)(rawFilePath)) return null;
3906
+ if (!(0, import_node_fs16.existsSync)(rawFilePath)) return null;
3914
3907
  const rawMtime = getMtimeMs(rawFilePath);
3915
3908
  const tagsMtime = getMtimeMs(tagsFilePath2(rootDir));
3916
3909
  const cacheKey = `${rootDir}:${layer}`;
@@ -3940,22 +3933,22 @@ async function generateGraph(rootDir, layer) {
3940
3933
  mutationMethods: config.parsers?.patterns?.mutationMethods
3941
3934
  });
3942
3935
  const dir = graphsDir(rootDir);
3943
- (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
3936
+ (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
3944
3937
  const results = layer ? [generateLayer(rootDir, layer)].filter((r) => r !== null) : generateAll(rootDir);
3945
3938
  for (const result of results) {
3946
3939
  const filePath = graphFilePath(rootDir, result.layer);
3947
- (0, import_node_fs15.writeFileSync)(filePath, JSON.stringify(result.output, null, 2) + "\n", "utf-8");
3940
+ (0, import_node_fs16.writeFileSync)(filePath, JSON.stringify(result.output, null, 2) + "\n", "utf-8");
3948
3941
  invalidateCache(filePath);
3949
3942
  invalidateTaggedCache(rootDir, result.layer);
3950
3943
  }
3951
3944
  return results;
3952
3945
  }
3953
- var import_node_fs15, import_node_path17, GRAPHS_DIR2, graphCache, taggedCache;
3946
+ var import_node_fs16, import_node_path18, GRAPHS_DIR2, graphCache, taggedCache;
3954
3947
  var init_graph = __esm({
3955
3948
  "src/server/graph/index.ts"() {
3956
3949
  "use strict";
3957
- import_node_fs15 = require("node:fs");
3958
- import_node_path17 = require("node:path");
3950
+ import_node_fs16 = require("node:fs");
3951
+ import_node_path18 = require("node:path");
3959
3952
  init_graph_builder();
3960
3953
  init_config();
3961
3954
  init_tagger_registry();
@@ -3970,10 +3963,10 @@ var init_graph = __esm({
3970
3963
 
3971
3964
  // src/server/graph/core/audit-core.ts
3972
3965
  function readGraphFile(rootDir, layer) {
3973
- const filePath = (0, import_node_path18.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
3974
- if (!(0, import_node_fs16.existsSync)(filePath)) return null;
3966
+ const filePath = (0, import_node_path19.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
3967
+ if (!(0, import_node_fs17.existsSync)(filePath)) return null;
3975
3968
  try {
3976
- return JSON.parse((0, import_node_fs16.readFileSync)(filePath, "utf-8"));
3969
+ return JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
3977
3970
  } catch {
3978
3971
  return null;
3979
3972
  }
@@ -4017,10 +4010,10 @@ function checkUnprotectedRoutes(rootDir) {
4017
4010
  const api = readGraphFile(rootDir, "api");
4018
4011
  const staticGraph = readGraphFile(rootDir, "static");
4019
4012
  if (!api) return buildReport("api", "unprotected_routes", findings);
4020
- const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
4013
+ const routePermsPath = (0, import_node_path19.join)(rootDir, "src", "config", "route-permissions.ts");
4021
4014
  let routePermsContent = "";
4022
- if ((0, import_node_fs16.existsSync)(routePermsPath)) {
4023
- routePermsContent = (0, import_node_fs16.readFileSync)(routePermsPath, "utf-8");
4015
+ if ((0, import_node_fs17.existsSync)(routePermsPath)) {
4016
+ routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
4024
4017
  }
4025
4018
  const registeredRoutes = /* @__PURE__ */ new Set();
4026
4019
  const routeEntryRe = /path:\s*'([^']+)'/g;
@@ -4097,10 +4090,10 @@ function checkUnenforcedPermissions(rootDir) {
4097
4090
  const staticGraph = readGraphFile(rootDir, "static");
4098
4091
  if (!staticGraph) return buildReport("static", "unenforced_permissions", findings);
4099
4092
  const permissions = staticGraph.nodes.filter((n) => n.type === "seed_permission").map((n) => ({ id: n.id, key: n.value, name: n.name }));
4100
- const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
4093
+ const routePermsPath = (0, import_node_path19.join)(rootDir, "src", "config", "route-permissions.ts");
4101
4094
  let routePermsContent = "";
4102
- if ((0, import_node_fs16.existsSync)(routePermsPath)) {
4103
- routePermsContent = (0, import_node_fs16.readFileSync)(routePermsPath, "utf-8");
4095
+ if ((0, import_node_fs17.existsSync)(routePermsPath)) {
4096
+ routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
4104
4097
  }
4105
4098
  for (const perm of permissions) {
4106
4099
  const regex = new RegExp(`permission:\\s*['"]${perm.key}['"]`);
@@ -4130,9 +4123,9 @@ function checkHardcodedValues(rootDir) {
4130
4123
  const seen = /* @__PURE__ */ new Set();
4131
4124
  for (const node of api.nodes) {
4132
4125
  if (node.type !== "endpoint") continue;
4133
- const filePath = (0, import_node_path18.join)(rootDir, "src", node.id);
4134
- if (!(0, import_node_fs16.existsSync)(filePath)) continue;
4135
- const content = (0, import_node_fs16.readFileSync)(filePath, "utf-8");
4126
+ const filePath = (0, import_node_path19.join)(rootDir, "src", node.id);
4127
+ if (!(0, import_node_fs17.existsSync)(filePath)) continue;
4128
+ const content = (0, import_node_fs17.readFileSync)(filePath, "utf-8");
4136
4129
  let m;
4137
4130
  allCapsRe.lastIndex = 0;
4138
4131
  while ((m = allCapsRe.exec(content)) !== null) {
@@ -4226,12 +4219,12 @@ function formatAsPrompt(reports) {
4226
4219
  if (lines.length === 0) return "No audit findings.";
4227
4220
  return lines.join("\n");
4228
4221
  }
4229
- var import_node_fs16, import_node_path18, CHECKS;
4222
+ var import_node_fs17, import_node_path19, CHECKS;
4230
4223
  var init_audit_core = __esm({
4231
4224
  "src/server/graph/core/audit-core.ts"() {
4232
4225
  "use strict";
4233
- import_node_fs16 = require("node:fs");
4234
- import_node_path18 = require("node:path");
4226
+ import_node_fs17 = require("node:fs");
4227
+ import_node_path19 = require("node:path");
4235
4228
  CHECKS = {
4236
4229
  db: {
4237
4230
  schema_drift: checkSchemaDrift,
@@ -4263,16 +4256,16 @@ function randomPort() {
4263
4256
  function findProjectRoot(startDir) {
4264
4257
  let dir = startDir;
4265
4258
  for (let i = 0; i < 8; i++) {
4266
- const graphsDir2 = import_node_path19.default.join(dir, ".launchsecure", "graphs");
4267
- if (import_node_fs17.default.existsSync(import_node_path19.default.join(graphsDir2, "ui.json")) || import_node_fs17.default.existsSync(import_node_path19.default.join(graphsDir2, "api.json")) || import_node_fs17.default.existsSync(import_node_path19.default.join(graphsDir2, "db.json"))) return dir;
4268
- const parent = import_node_path19.default.dirname(dir);
4259
+ const graphsDir2 = import_node_path20.default.join(dir, ".launchsecure", "graphs");
4260
+ if (import_node_fs18.default.existsSync(import_node_path20.default.join(graphsDir2, "ui.json")) || import_node_fs18.default.existsSync(import_node_path20.default.join(graphsDir2, "api.json")) || import_node_fs18.default.existsSync(import_node_path20.default.join(graphsDir2, "db.json"))) return dir;
4261
+ const parent = import_node_path20.default.dirname(dir);
4269
4262
  if (parent === dir) break;
4270
4263
  dir = parent;
4271
4264
  }
4272
4265
  dir = startDir;
4273
4266
  for (let i = 0; i < 8; i++) {
4274
- if (import_node_fs17.default.existsSync(import_node_path19.default.join(dir, ".git"))) return dir;
4275
- const parent = import_node_path19.default.dirname(dir);
4267
+ if (import_node_fs18.default.existsSync(import_node_path20.default.join(dir, ".git"))) return dir;
4268
+ const parent = import_node_path20.default.dirname(dir);
4276
4269
  if (parent === dir) break;
4277
4270
  dir = parent;
4278
4271
  }
@@ -4281,7 +4274,7 @@ function findProjectRoot(startDir) {
4281
4274
  function resolveRequestRoot(url, monorepoRoot, projects) {
4282
4275
  const projectParam = url.searchParams.get("project");
4283
4276
  if (!projectParam || projects.length === 0) return monorepoRoot;
4284
- const resolved = import_node_path19.default.resolve(monorepoRoot, projectParam);
4277
+ const resolved = import_node_path20.default.resolve(monorepoRoot, projectParam);
4285
4278
  if (!resolved.startsWith(monorepoRoot)) {
4286
4279
  throw new Error("Project path outside monorepo root");
4287
4280
  }
@@ -4332,16 +4325,16 @@ async function buildMergedGraph(root) {
4332
4325
  };
4333
4326
  }
4334
4327
  function serveStatic(res, filePath) {
4335
- if (!import_node_fs17.default.existsSync(filePath) || !import_node_fs17.default.statSync(filePath).isFile()) return false;
4336
- const ext = import_node_path19.default.extname(filePath).toLowerCase();
4328
+ if (!import_node_fs18.default.existsSync(filePath) || !import_node_fs18.default.statSync(filePath).isFile()) return false;
4329
+ const ext = import_node_path20.default.extname(filePath).toLowerCase();
4337
4330
  const mime = MIME_TYPES[ext] ?? "application/octet-stream";
4338
4331
  res.writeHead(200, { "Content-Type": mime, "Cache-Control": "no-cache" });
4339
- import_node_fs17.default.createReadStream(filePath).pipe(res);
4332
+ import_node_fs18.default.createReadStream(filePath).pipe(res);
4340
4333
  return true;
4341
4334
  }
4342
4335
  function serveIndex(res, clientDir) {
4343
- const indexPath = import_node_path19.default.join(clientDir, "index.html");
4344
- if (!import_node_fs17.default.existsSync(indexPath)) {
4336
+ const indexPath = import_node_path20.default.join(clientDir, "index.html");
4337
+ if (!import_node_fs18.default.existsSync(indexPath)) {
4345
4338
  res.writeHead(500, { "Content-Type": "text/plain" });
4346
4339
  res.end(`LaunchChart client bundle not found at ${clientDir}. Run 'npm run build:chart-client'.`);
4347
4340
  return;
@@ -4393,7 +4386,7 @@ async function startChartServer(opts = {}) {
4393
4386
  }
4394
4387
  return { port: existing.port, url: existing.url };
4395
4388
  }
4396
- const clientDir = opts.clientDir ?? import_node_path19.default.join(__dirname, "..", "chart-client");
4389
+ const clientDir = opts.clientDir ?? import_node_path20.default.join(__dirname, "..", "chart-client");
4397
4390
  const rootConfig = loadConfig(projectRoot);
4398
4391
  const projects = rootConfig.projects ?? [];
4399
4392
  const server = import_node_http.default.createServer((req, res) => {
@@ -4409,11 +4402,11 @@ async function startChartServer(opts = {}) {
4409
4402
  }
4410
4403
  if (req.method === "GET" && url2.pathname === "/api/projects") {
4411
4404
  const projectList = projects.length > 0 ? projects.map((p) => {
4412
- const absRoot = import_node_path19.default.resolve(projectRoot, p.root);
4413
- const hasGraphs = import_node_fs17.default.existsSync(import_node_path19.default.join(absRoot, ".launchsecure", "graphs"));
4414
- const hasNextConfig2 = import_node_fs17.default.existsSync(import_node_path19.default.join(absRoot, "next.config.ts")) || import_node_fs17.default.existsSync(import_node_path19.default.join(absRoot, "next.config.js")) || import_node_fs17.default.existsSync(import_node_path19.default.join(absRoot, "next.config.mjs"));
4415
- return { name: p.name, root: p.root, hasGraphs, hasNextConfig: hasNextConfig2 };
4416
- }) : [{ name: import_node_path19.default.basename(projectRoot), root: ".", hasGraphs: import_node_fs17.default.existsSync(import_node_path19.default.join(projectRoot, ".launchsecure", "graphs")), hasNextConfig: true }];
4405
+ const absRoot = import_node_path20.default.resolve(projectRoot, p.root);
4406
+ const hasGraphs = import_node_fs18.default.existsSync(import_node_path20.default.join(absRoot, ".launchsecure", "graphs"));
4407
+ const hasNextConfig = import_node_fs18.default.existsSync(import_node_path20.default.join(absRoot, "next.config.ts")) || import_node_fs18.default.existsSync(import_node_path20.default.join(absRoot, "next.config.js")) || import_node_fs18.default.existsSync(import_node_path20.default.join(absRoot, "next.config.mjs"));
4408
+ return { name: p.name, root: p.root, hasGraphs, hasNextConfig };
4409
+ }) : [{ name: import_node_path20.default.basename(projectRoot), root: ".", hasGraphs: import_node_fs18.default.existsSync(import_node_path20.default.join(projectRoot, ".launchsecure", "graphs")), hasNextConfig: true }];
4417
4410
  res.writeHead(200, { "Content-Type": "application/json" });
4418
4411
  res.end(JSON.stringify({ projects: projectList, monorepoRoot: projectRoot }));
4419
4412
  return;
@@ -4459,20 +4452,20 @@ async function startChartServer(opts = {}) {
4459
4452
  }
4460
4453
  if (req.method === "GET" && url2.pathname === "/api/file-content") {
4461
4454
  const relPath = url2.searchParams.get("path");
4462
- if (!relPath || relPath.includes("..") || import_node_path19.default.isAbsolute(relPath)) {
4455
+ if (!relPath || relPath.includes("..") || import_node_path20.default.isAbsolute(relPath)) {
4463
4456
  res.writeHead(400, { "Content-Type": "application/json" });
4464
4457
  res.end(JSON.stringify({ error: "Invalid path" }));
4465
4458
  return;
4466
4459
  }
4467
- const filePath = import_node_path19.default.join(reqRoot, relPath);
4468
- if (!filePath.startsWith(reqRoot) || !import_node_fs17.default.existsSync(filePath) || !import_node_fs17.default.statSync(filePath).isFile()) {
4460
+ const filePath = import_node_path20.default.join(reqRoot, relPath);
4461
+ if (!filePath.startsWith(reqRoot) || !import_node_fs18.default.existsSync(filePath) || !import_node_fs18.default.statSync(filePath).isFile()) {
4469
4462
  res.writeHead(404, { "Content-Type": "application/json" });
4470
4463
  res.end(JSON.stringify({ error: "File not found" }));
4471
4464
  return;
4472
4465
  }
4473
- const ext = import_node_path19.default.extname(filePath).toLowerCase();
4466
+ const ext = import_node_path20.default.extname(filePath).toLowerCase();
4474
4467
  const langMap = { ".ts": "typescript", ".tsx": "tsx", ".js": "javascript", ".jsx": "jsx", ".prisma": "prisma", ".json": "json", ".css": "css" };
4475
- const content = import_node_fs17.default.readFileSync(filePath, "utf-8");
4468
+ const content = import_node_fs18.default.readFileSync(filePath, "utf-8");
4476
4469
  res.writeHead(200, { "Content-Type": "application/json" });
4477
4470
  res.end(JSON.stringify({ content, language: langMap[ext] ?? "text", path: relPath }));
4478
4471
  return;
@@ -4514,8 +4507,8 @@ async function startChartServer(opts = {}) {
4514
4507
  req.on("end", () => {
4515
4508
  try {
4516
4509
  const newConfig = JSON.parse(body);
4517
- const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
4518
- import_node_fs17.default.writeFileSync(configPath, JSON.stringify(newConfig, null, 2) + "\n", "utf-8");
4510
+ const configPath = import_node_path20.default.join(reqRoot, ".launchchart.json");
4511
+ import_node_fs18.default.writeFileSync(configPath, JSON.stringify(newConfig, null, 2) + "\n", "utf-8");
4519
4512
  res.writeHead(200, { "Content-Type": "application/json" });
4520
4513
  res.end(JSON.stringify({ ok: true }));
4521
4514
  } catch (err2) {
@@ -4548,8 +4541,8 @@ async function startChartServer(opts = {}) {
4548
4541
  const taggerConfig = JSON.parse(body);
4549
4542
  const config2 = loadConfig(reqRoot);
4550
4543
  config2.taggers = taggerConfig;
4551
- const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
4552
- import_node_fs17.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
4544
+ const configPath = import_node_path20.default.join(reqRoot, ".launchchart.json");
4545
+ import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
4553
4546
  res.writeHead(200, { "Content-Type": "application/json" });
4554
4547
  res.end(JSON.stringify({ ok: true }));
4555
4548
  } catch (err2) {
@@ -4622,10 +4615,10 @@ async function startChartServer(opts = {}) {
4622
4615
  res.end(JSON.stringify({
4623
4616
  projectRoot: reqRoot,
4624
4617
  detected: paths ? {
4625
- srcDir: import_node_path19.default.relative(reqRoot, paths.srcDir) || ".",
4626
- appDir: import_node_path19.default.relative(reqRoot, paths.appDir),
4627
- apiDir: import_node_path19.default.relative(reqRoot, paths.apiDir),
4628
- dbDir: paths.dbDir ? import_node_path19.default.relative(reqRoot, paths.dbDir) : null
4618
+ srcDir: import_node_path20.default.relative(reqRoot, paths.srcDir) || ".",
4619
+ appDir: import_node_path20.default.relative(reqRoot, paths.appDir),
4620
+ apiDir: import_node_path20.default.relative(reqRoot, paths.apiDir),
4621
+ dbDir: paths.dbDir ? import_node_path20.default.relative(reqRoot, paths.dbDir) : null
4629
4622
  } : null,
4630
4623
  overrides,
4631
4624
  isOverride: overrides.appDir
@@ -4634,19 +4627,19 @@ async function startChartServer(opts = {}) {
4634
4627
  }
4635
4628
  if (req.method === "GET" && url2.pathname === "/api/browse-dir") {
4636
4629
  const browsePath = url2.searchParams.get("path") || projectRoot;
4637
- const abs = import_node_path19.default.resolve(browsePath);
4638
- const twoUp = import_node_path19.default.resolve(projectRoot, "..", "..");
4630
+ const abs = import_node_path20.default.resolve(browsePath);
4631
+ const twoUp = import_node_path20.default.resolve(projectRoot, "..", "..");
4639
4632
  if (!abs.startsWith(twoUp)) {
4640
4633
  res.writeHead(403, { "Content-Type": "application/json" });
4641
4634
  res.end(JSON.stringify({ ok: false, error: "Path outside allowed range" }));
4642
4635
  return;
4643
4636
  }
4644
4637
  try {
4645
- const entries = import_node_fs17.default.readdirSync(abs, { withFileTypes: true });
4638
+ const entries = import_node_fs18.default.readdirSync(abs, { withFileTypes: true });
4646
4639
  const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules" && e.name !== "dist" && e.name !== ".next").map((e) => e.name).sort();
4647
- const parent = abs !== twoUp ? import_node_path19.default.dirname(abs) : null;
4640
+ const parent = abs !== twoUp ? import_node_path20.default.dirname(abs) : null;
4648
4641
  res.writeHead(200, { "Content-Type": "application/json" });
4649
- res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path19.default.relative(projectRoot, abs) || "." }));
4642
+ res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path20.default.relative(projectRoot, abs) || "." }));
4650
4643
  } catch (err2) {
4651
4644
  res.writeHead(400, { "Content-Type": "application/json" });
4652
4645
  res.end(JSON.stringify({ ok: false, error: String(err2) }));
@@ -4672,8 +4665,8 @@ async function startChartServer(opts = {}) {
4672
4665
  const { projects: newProjects } = JSON.parse(body);
4673
4666
  const config2 = loadConfig(projectRoot);
4674
4667
  config2.projects = newProjects.length > 0 ? newProjects : void 0;
4675
- const configPath = import_node_path19.default.join(projectRoot, ".launchchart.json");
4676
- import_node_fs17.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
4668
+ const configPath = import_node_path20.default.join(projectRoot, ".launchchart.json");
4669
+ import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
4677
4670
  projects.length = 0;
4678
4671
  if (config2.projects) projects.push(...config2.projects);
4679
4672
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -4686,7 +4679,7 @@ async function startChartServer(opts = {}) {
4686
4679
  return;
4687
4680
  }
4688
4681
  if (url2.pathname !== "/") {
4689
- const staticPath = import_node_path19.default.join(clientDir, url2.pathname);
4682
+ const staticPath = import_node_path20.default.join(clientDir, url2.pathname);
4690
4683
  if (serveStatic(res, staticPath)) return;
4691
4684
  }
4692
4685
  serveIndex(res, clientDir);
@@ -4746,13 +4739,13 @@ function runServeCli(argv) {
4746
4739
  process.exit(1);
4747
4740
  });
4748
4741
  }
4749
- var import_node_http, import_node_fs17, import_node_path19, MAX_PORT_SCAN, MIME_TYPES;
4742
+ var import_node_http, import_node_fs18, import_node_path20, MAX_PORT_SCAN, MIME_TYPES;
4750
4743
  var init_chart_serve = __esm({
4751
4744
  "src/server/chart-serve.ts"() {
4752
4745
  "use strict";
4753
4746
  import_node_http = __toESM(require("node:http"));
4754
- import_node_fs17 = __toESM(require("node:fs"));
4755
- import_node_path19 = __toESM(require("node:path"));
4747
+ import_node_fs18 = __toESM(require("node:fs"));
4748
+ import_node_path20 = __toESM(require("node:path"));
4756
4749
  init_graph();
4757
4750
  init_lockfile();
4758
4751
  init_config();
@@ -4774,214 +4767,6 @@ var init_chart_serve = __esm({
4774
4767
  }
4775
4768
  });
4776
4769
 
4777
- // src/server/blast-radius-builder.ts
4778
- function loadDefaults(rootDir) {
4779
- const filePath = (0, import_node_path20.join)(rootDir, ".launchsecure", "blast-radius-defaults.json");
4780
- try {
4781
- if (import_node_fs18.default.existsSync(filePath)) {
4782
- const raw = import_node_fs18.default.readFileSync(filePath, "utf-8");
4783
- return JSON.parse(raw);
4784
- }
4785
- } catch {
4786
- }
4787
- return FALLBACK_DEFAULTS;
4788
- }
4789
- function generateAcceptance(node, inspect) {
4790
- const criteria = [];
4791
- const t = node.type?.toLowerCase() ?? "";
4792
- if (t === "endpoint" || t === "mcp-tool") {
4793
- const methods = inspect?.methods ?? [];
4794
- const path3 = inspect?.path ?? node.id;
4795
- if (methods.length > 0) {
4796
- criteria.push(`${methods.join("/")} ${path3} still returns correct responses for authorized users`);
4797
- } else {
4798
- criteria.push(`${path3} still responds correctly`);
4799
- }
4800
- if (inspect?.auth && inspect.auth.includes("withAuth")) {
4801
- criteria.push("Authentication and authorization still enforced");
4802
- }
4803
- if (inspect?.db_models && inspect.db_models.length > 0) {
4804
- criteria.push(`DB operations on ${inspect.db_models.join(", ")} still work correctly`);
4805
- }
4806
- } else if (t === "page" || t === "component" || t === "layout") {
4807
- criteria.push(`${node.name} renders without errors`);
4808
- if (inspect?.stateVars && inspect.stateVars.length > 0) {
4809
- criteria.push("State management still works correctly");
4810
- }
4811
- if (inspect?.elements && inspect.elements.length > 5) {
4812
- criteria.push("All child components render correctly");
4813
- }
4814
- } else if (t === "table" || t === "enum") {
4815
- criteria.push(`${node.name} schema unchanged or migration applies cleanly`);
4816
- criteria.push("Existing queries against this table still work");
4817
- } else if (t === "hook") {
4818
- criteria.push(`${node.name} returns expected shape`);
4819
- if (inspect?.stateVars && inspect.stateVars.length > 0) {
4820
- criteria.push(`State variables [${inspect.stateVars.map((s) => s.name).join(", ")}] still returned`);
4821
- }
4822
- } else if (t === "context") {
4823
- criteria.push(`${node.name} provides correct context to consumers`);
4824
- } else if (t === "lib" || t === "config" || t === "types") {
4825
- criteria.push(`${node.name} exports still conform to expected interface`);
4826
- } else if (t === "seed" || t === "seed_role" || t === "seed_permission") {
4827
- criteria.push("Seed runs without errors");
4828
- criteria.push("Expected rows created in database");
4829
- } else {
4830
- criteria.push("Verify no regression");
4831
- }
4832
- return criteria;
4833
- }
4834
- function buildManifest(input) {
4835
- const { mode, title, description, subtitle, blastResults, createNodes, inspectData, defaults } = input;
4836
- const nodeMap = /* @__PURE__ */ new Map();
4837
- const centerNodeIds = /* @__PURE__ */ new Set();
4838
- for (const result of blastResults) {
4839
- centerNodeIds.add(result.center.id);
4840
- for (const node of result.affected) {
4841
- const existing = nodeMap.get(node.id);
4842
- if (!existing || node.hop < existing.hop) {
4843
- nodeMap.set(node.id, node);
4844
- }
4845
- }
4846
- }
4847
- for (const id of centerNodeIds) {
4848
- nodeMap.delete(id);
4849
- }
4850
- const manifestNodes = [];
4851
- for (const result of blastResults) {
4852
- const c = result.center;
4853
- if (manifestNodes.some((n) => n.id === c.id)) continue;
4854
- const inspect = inspectData[c.id];
4855
- manifestNodes.push({
4856
- id: c.id,
4857
- name: c.name,
4858
- layer: c.layer,
4859
- ring: "modify",
4860
- type: c.type,
4861
- reason: `Direct change target`,
4862
- acceptance: generateAcceptance(
4863
- { id: c.id, name: c.name, type: c.type, layer: c.layer, hop: 0 },
4864
- inspect
4865
- )
4866
- });
4867
- }
4868
- for (const [, node] of nodeMap) {
4869
- const ring = node.hop <= 1 ? "modify" : "ripple";
4870
- const inspect = inspectData[node.id];
4871
- const reason = node.hop <= 1 ? `Directly depends on changed node` : `Indirect dependency (${node.hop} hops away)`;
4872
- manifestNodes.push({
4873
- id: node.id,
4874
- name: node.name,
4875
- layer: node.layer,
4876
- ring,
4877
- type: node.type,
4878
- reason,
4879
- acceptance: generateAcceptance(node, inspect)
4880
- });
4881
- }
4882
- for (const cn of createNodes) {
4883
- manifestNodes.push({
4884
- id: cn.id,
4885
- name: cn.name,
4886
- layer: cn.layer,
4887
- ring: "create",
4888
- type: cn.type ?? "unknown",
4889
- reason: cn.reason,
4890
- acceptance: cn.acceptance ?? ["Verify implementation matches spec"]
4891
- });
4892
- }
4893
- const layerIds = /* @__PURE__ */ new Set();
4894
- for (const n of manifestNodes) {
4895
- layerIds.add(n.layer);
4896
- }
4897
- const layers = [];
4898
- for (const id of layerIds) {
4899
- const def = defaults.layers[id];
4900
- if (def) {
4901
- layers.push({ id, name: def.name, icon: def.icon, color: def.color });
4902
- } else {
4903
- layers.push({ id, name: id, icon: "box", color: "#cbd5e1" });
4904
- }
4905
- }
4906
- const edgeSet = /* @__PURE__ */ new Set();
4907
- const edges = [];
4908
- const allNodeIds = new Set(manifestNodes.map((n) => n.id));
4909
- for (const cId of centerNodeIds) {
4910
- for (const result of blastResults) {
4911
- for (const affected of result.affected) {
4912
- if (affected.hop === 1 && result.center.id === cId && allNodeIds.has(affected.id)) {
4913
- const key = `${cId}->${affected.id}`;
4914
- if (!edgeSet.has(key)) {
4915
- edgeSet.add(key);
4916
- edges.push({ source: cId, target: affected.id });
4917
- }
4918
- }
4919
- }
4920
- }
4921
- }
4922
- for (const result of blastResults) {
4923
- if (result.edges) {
4924
- for (const edge of result.edges) {
4925
- if (allNodeIds.has(edge.source) && allNodeIds.has(edge.target)) {
4926
- const key = `${edge.source}->${edge.target}`;
4927
- if (!edgeSet.has(key)) {
4928
- edgeSet.add(key);
4929
- edges.push({ source: edge.source, target: edge.target });
4930
- }
4931
- }
4932
- }
4933
- }
4934
- }
4935
- for (const cn of createNodes) {
4936
- edges.push({ source: "center", target: cn.id });
4937
- if (cn.connects_to) {
4938
- for (const targetId of cn.connects_to) {
4939
- if (allNodeIds.has(targetId) || createNodes.some((c) => c.id === targetId)) {
4940
- const key = `${cn.id}->${targetId}`;
4941
- if (!edgeSet.has(key)) {
4942
- edgeSet.add(key);
4943
- edges.push({ source: cn.id, target: targetId });
4944
- }
4945
- }
4946
- }
4947
- }
4948
- }
4949
- return {
4950
- mode,
4951
- title,
4952
- subtitle,
4953
- layers,
4954
- rings: defaults.rings,
4955
- center: { name: title, description },
4956
- nodes: manifestNodes,
4957
- edges
4958
- };
4959
- }
4960
- var import_node_fs18, import_node_path20, FALLBACK_DEFAULTS;
4961
- var init_blast_radius_builder = __esm({
4962
- "src/server/blast-radius-builder.ts"() {
4963
- "use strict";
4964
- import_node_fs18 = __toESM(require("node:fs"));
4965
- import_node_path20 = require("node:path");
4966
- FALLBACK_DEFAULTS = {
4967
- rings: [
4968
- { id: "modify", name: "Modify", color: "#ff6b00" },
4969
- { id: "ripple", name: "Ripple (verify)", color: "#ffff00" },
4970
- { id: "create", name: "Create", color: "#00ff00" }
4971
- ],
4972
- layers: {
4973
- db: { name: "Database", icon: "database", color: "#cbd5e1" },
4974
- api: { name: "API", icon: "server", color: "#cbd5e1" },
4975
- middleware: { name: "Middleware", icon: "shield", color: "#cbd5e1" },
4976
- ui: { name: "UI", icon: "layout-dashboard", color: "#cbd5e1" },
4977
- config: { name: "Config / Seed", icon: "settings", color: "#cbd5e1" },
4978
- shared: { name: "Shared Types", icon: "box", color: "#cbd5e1" }
4979
- },
4980
- center: { color: "#ff0000" }
4981
- };
4982
- }
4983
- });
4984
-
4985
4770
  // src/server/graph/core/language-detection.ts
4986
4771
  function walkForExtensions(dir, extCounts, depth = 0) {
4987
4772
  if (depth > 10) return;
@@ -5375,144 +5160,6 @@ function handleBlastPoints(args) {
5375
5160
  }
5376
5161
  });
5377
5162
  }
5378
- function handleGenerateBlastRadius(args) {
5379
- const rootDir = process.cwd();
5380
- const mode = args.mode ?? "structural";
5381
- const title = args.title;
5382
- const description = args.description ?? title;
5383
- const subtitle = args.subtitle;
5384
- const hops = args.hops ?? 2;
5385
- const defaults = loadDefaults(rootDir);
5386
- let centerNodeIds = [];
5387
- if (mode === "structural") {
5388
- const nodeId = args.node_id;
5389
- if (!nodeId) return err("structural mode requires node_id");
5390
- centerNodeIds = [nodeId];
5391
- } else {
5392
- centerNodeIds = args.center_nodes ?? [];
5393
- if (centerNodeIds.length === 0) return err("feature mode requires center_nodes[]");
5394
- }
5395
- const createNodes = args.create_nodes ?? [];
5396
- const blastResults = [];
5397
- for (const nodeId of centerNodeIds) {
5398
- let targetLayer;
5399
- const graphs = readAllGraphs(rootDir);
5400
- for (const [layer, graph2] of Object.entries(graphs)) {
5401
- if (graph2 && graph2.nodes.some((n) => n.id === nodeId)) {
5402
- targetLayer = layer;
5403
- break;
5404
- }
5405
- }
5406
- if (!targetLayer) continue;
5407
- const graph = readGraph(rootDir, targetLayer);
5408
- if (!graph) continue;
5409
- const center = graph.nodes.find((n) => n.id === nodeId);
5410
- if (!center) continue;
5411
- const result2 = reverseNeighborhood(graph, nodeId, hops, "reverse");
5412
- const affected = [];
5413
- for (const [id, { node, hop }] of result2.nodes) {
5414
- if (id === nodeId) continue;
5415
- const tags = node.tags;
5416
- affected.push({ id: node.id, name: node.name, type: node.type, layer: targetLayer, hop, module: tags?.module });
5417
- }
5418
- const otherLayers = getAvailableLayers(rootDir).filter((l) => l !== targetLayer && l !== "static");
5419
- for (const otherLayer of otherLayers) {
5420
- const otherGraph = readGraph(rootDir, otherLayer);
5421
- if (!otherGraph) continue;
5422
- for (const edge of otherGraph.edges) {
5423
- if (edge.target === nodeId || edge.source === nodeId) {
5424
- const dependentId = edge.target === nodeId ? edge.source : edge.target;
5425
- if (affected.some((a) => a.id === dependentId)) continue;
5426
- const depNode = otherGraph.nodes.find((n) => n.id === dependentId);
5427
- if (depNode) {
5428
- const tags = depNode.tags;
5429
- affected.push({ id: depNode.id, name: depNode.name, type: depNode.type, layer: otherLayer, hop: 1, module: tags?.module });
5430
- }
5431
- }
5432
- }
5433
- }
5434
- const centerTags = center.tags;
5435
- const edges = result2.edges.map((e) => ({ source: e.source, target: e.target }));
5436
- blastResults.push({
5437
- center: { id: center.id, name: center.name, type: center.type, layer: targetLayer, module: centerTags?.module },
5438
- affected,
5439
- edges
5440
- });
5441
- }
5442
- if (blastResults.length === 0) {
5443
- return err(`None of the center nodes were found in any graph layer: ${centerNodeIds.join(", ")}`);
5444
- }
5445
- const inspectData = {};
5446
- const allAffectedIds = /* @__PURE__ */ new Set();
5447
- for (const r of blastResults) {
5448
- allAffectedIds.add(r.center.id);
5449
- for (const a of r.affected) allAffectedIds.add(a.id);
5450
- }
5451
- const allGraphs = readAllGraphs(rootDir);
5452
- for (const id of allAffectedIds) {
5453
- for (const [, graph] of Object.entries(allGraphs)) {
5454
- if (!graph) continue;
5455
- const node = graph.nodes.find((n) => n.id === id);
5456
- if (node) {
5457
- inspectData[id] = {
5458
- type: node.type,
5459
- name: node.name,
5460
- methods: node.methods,
5461
- path: node.path ?? node.handler,
5462
- auth: node.auth,
5463
- db_models: node.db_models
5464
- };
5465
- break;
5466
- }
5467
- }
5468
- }
5469
- const manifest = buildManifest({
5470
- mode,
5471
- title,
5472
- description,
5473
- subtitle,
5474
- blastResults,
5475
- createNodes,
5476
- inspectData,
5477
- defaults
5478
- });
5479
- const pushToDeck = args.push_to_deck;
5480
- const session = args.session;
5481
- let deckResult;
5482
- if (pushToDeck) {
5483
- if (!session) return err("push_to_deck requires a session name");
5484
- const deckLockPath = (0, import_node_path22.join)(rootDir, ".launchsecure", "launch-deck.lock");
5485
- if (!(0, import_node_fs20.existsSync)(deckLockPath)) {
5486
- deckResult = { pushed: false, reason: "Deck server not running (no lock file). Push manually via deck tool." };
5487
- } else {
5488
- try {
5489
- const lock = JSON.parse((0, import_node_fs20.readFileSync)(deckLockPath, "utf-8"));
5490
- const deckUrl = lock.url;
5491
- const body = JSON.stringify({
5492
- session,
5493
- mode: "show",
5494
- blocks: [{ type: "blast-radius", label: title, manifest }]
5495
- });
5496
- (0, import_node_child_process2.execFileSync)("curl", [
5497
- "-s",
5498
- "-X",
5499
- "POST",
5500
- deckUrl + "/api/deck",
5501
- "-H",
5502
- "Content-Type: application/json",
5503
- "-d",
5504
- body
5505
- ], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] });
5506
- deckResult = { pushed: true, session, url: deckUrl };
5507
- } catch (e) {
5508
- deckResult = { pushed: false, reason: `Failed to push to deck: ${e}` };
5509
- }
5510
- }
5511
- }
5512
- const result = { ...manifest };
5513
- if (deckResult) result._deck = deckResult;
5514
- return okJson(result);
5515
- }
5516
5163
  function layerSummary(graph) {
5517
5164
  const typeCounts = {};
5518
5165
  const moduleCounts = {};
@@ -6214,10 +5861,6 @@ async function handleMessage(msg) {
6214
5861
  respond(id ?? null, handleBlastPoints(args));
6215
5862
  return;
6216
5863
  }
6217
- if (toolName === "generate_blast_radius") {
6218
- respond(id ?? null, handleGenerateBlastRadius(args));
6219
- return;
6220
- }
6221
5864
  respondError(id ?? null, -32601, `Unknown tool: ${toolName}`);
6222
5865
  return;
6223
5866
  }
@@ -6262,7 +5905,6 @@ var init_graph_mcp = __esm({
6262
5905
  import_node_child_process2 = require("node:child_process");
6263
5906
  import_node_os2 = require("node:os");
6264
5907
  init_graph();
6265
- init_blast_radius_builder();
6266
5908
  init_lockfile();
6267
5909
  init_config();
6268
5910
  init_parser_registry();
@@ -6579,81 +6221,6 @@ Example: blast_points(node_id: "server/auth/middleware.ts", hops: 2) \u2192 retu
6579
6221
  },
6580
6222
  required: ["node_id"]
6581
6223
  }
6582
- },
6583
- {
6584
- name: "generate_blast_radius",
6585
- description: `Generate a complete BlastRadiusManifest from graph data \u2014 ready to push to deck.
6586
-
6587
- Two modes:
6588
- - **Structural**: single node changed \u2192 auto-discover what's affected via reverse BFS
6589
- Example: generate_blast_radius({ mode: "structural", node_id: "CommentChannel", title: "CommentChannel refactor" })
6590
- - **Feature**: new feature \u2192 multiple starting nodes + new nodes to create
6591
- Example: generate_blast_radius({ mode: "feature", title: "Client Role", description: "...", center_nodes: ["CommentChannel", "ProjectMember"], create_nodes: [{ id: "ChannelMember", name: "ChannelMember table", layer: "db", reason: "..." }] })
6592
-
6593
- Output is a BlastRadiusManifest JSON that passes directly to the deck tool's blast-radius block.
6594
- Reads ring/layer/center colors from .launchsecure/blast-radius-defaults.json.
6595
- Auto-generates acceptance criteria per node using inspect_node AST data.`,
6596
- inputSchema: {
6597
- type: "object",
6598
- properties: {
6599
- mode: {
6600
- type: "string",
6601
- enum: ["structural", "feature"],
6602
- description: '"structural" = single node changed. "feature" = new feature with multiple nodes.'
6603
- },
6604
- title: {
6605
- type: "string",
6606
- description: "Title for the blast radius (shown in center node and header)."
6607
- },
6608
- description: {
6609
- type: "string",
6610
- description: "Description of the change or feature."
6611
- },
6612
- subtitle: {
6613
- type: "string",
6614
- description: "Optional subtitle shown above title in the viz."
6615
- },
6616
- node_id: {
6617
- type: "string",
6618
- description: "Structural mode only: the node being changed."
6619
- },
6620
- center_nodes: {
6621
- type: "array",
6622
- items: { type: "string" },
6623
- description: "Feature mode: existing graph node IDs that are the starting points for traversal."
6624
- },
6625
- create_nodes: {
6626
- type: "array",
6627
- items: {
6628
- type: "object",
6629
- properties: {
6630
- id: { type: "string" },
6631
- name: { type: "string" },
6632
- layer: { type: "string" },
6633
- type: { type: "string" },
6634
- reason: { type: "string" },
6635
- acceptance: { type: "array", items: { type: "string" } },
6636
- connects_to: { type: "array", items: { type: "string" }, description: "IDs of existing nodes this new node has FK/relationship edges to." }
6637
- },
6638
- required: ["id", "name", "layer", "reason"]
6639
- },
6640
- description: "Feature mode: new nodes that need to be created (not in graph yet)."
6641
- },
6642
- hops: {
6643
- type: "number",
6644
- description: "Max hops for traversal. Default 2. Hop 1 = modify ring, hop 2+ = ripple ring."
6645
- },
6646
- push_to_deck: {
6647
- type: "boolean",
6648
- description: "If true, pushes the manifest directly to LaunchDeck browser (requires deck server running). Default false."
6649
- },
6650
- session: {
6651
- type: "string",
6652
- description: "Session name for the deck tab. Required when push_to_deck is true."
6653
- }
6654
- },
6655
- required: ["title"]
6656
- }
6657
6224
  }
6658
6225
  ];
6659
6226
  COMPACT_SCHEMA = {