@launchsecure/launch-kit 0.0.18 → 0.0.20

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 (69) hide show
  1. package/dist/chart-client/assets/index-C8ANseEa.js +441 -0
  2. package/dist/chart-client/index.html +1 -1
  3. package/dist/deck-client/assets/{_baseUniq-2gclQXo7.js → _baseUniq-DsfOm3t_.js} +1 -1
  4. package/dist/deck-client/assets/{arc-DcMY5Wm0.js → arc-NJuvkBv1.js} +1 -1
  5. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-B8iirmmJ.js → architectureDiagram-Q4EWVU46-BgrcgZs0.js} +1 -1
  6. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-B4JBLjmJ.js → blockDiagram-DXYQGD6D-C3XoLi15.js} +1 -1
  7. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CojrJAk8.js → c4Diagram-AHTNJAMY-FX2PjLfb.js} +1 -1
  8. package/dist/deck-client/assets/channel-ChQjD1T1.js +1 -0
  9. package/dist/deck-client/assets/{chunk-4BX2VUAB-Bmb_BMDo.js → chunk-4BX2VUAB-D0aqsJV0.js} +1 -1
  10. package/dist/deck-client/assets/{chunk-4TB4RGXK-CumBy8qe.js → chunk-4TB4RGXK-7qRCCAgK.js} +1 -1
  11. package/dist/deck-client/assets/{chunk-55IACEB6-Ka8Hb1wD.js → chunk-55IACEB6-DfHG-iqb.js} +1 -1
  12. package/dist/deck-client/assets/{chunk-EDXVE4YY-B3sIPiQo.js → chunk-EDXVE4YY-DrR52j3B.js} +1 -1
  13. package/dist/deck-client/assets/{chunk-FMBD7UC4-C1tYkaqu.js → chunk-FMBD7UC4-D5KSGATB.js} +1 -1
  14. package/dist/deck-client/assets/{chunk-OYMX7WX6-D7Wacbky.js → chunk-OYMX7WX6-M7hsLRNU.js} +1 -1
  15. package/dist/deck-client/assets/{chunk-QZHKN3VN-ChXI0vO3.js → chunk-QZHKN3VN-1ynAWO2m.js} +1 -1
  16. package/dist/deck-client/assets/{chunk-YZCP3GAM-BXhiqf8u.js → chunk-YZCP3GAM-S2-nGw3D.js} +1 -1
  17. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-B_9iqK1S.js +1 -0
  18. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-B_9iqK1S.js +1 -0
  19. package/dist/deck-client/assets/clone-BYt1AMfz.js +1 -0
  20. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-Bqp3p68D.js → cose-bilkent-S5V4N54A-BcMwozS2.js} +1 -1
  21. package/dist/deck-client/assets/{dagre-KV5264BT-BS-rtyhZ.js → dagre-KV5264BT-DtKMhl_1.js} +1 -1
  22. package/dist/deck-client/assets/{diagram-5BDNPKRD-BIrj9YGI.js → diagram-5BDNPKRD-1plH69us.js} +1 -1
  23. package/dist/deck-client/assets/{diagram-G4DWMVQ6-noHWPIg4.js → diagram-G4DWMVQ6-D_o-BHO3.js} +1 -1
  24. package/dist/deck-client/assets/{diagram-MMDJMWI5-C2qHxvqV.js → diagram-MMDJMWI5-ClZ1LIx6.js} +1 -1
  25. package/dist/deck-client/assets/{diagram-TYMM5635-BytnGQr-.js → diagram-TYMM5635-B8dKHfRh.js} +1 -1
  26. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BfK5m2YQ.js → erDiagram-SMLLAGMA-CY2aCH7-.js} +1 -1
  27. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-Cq925G1Z.js → flowDiagram-DWJPFMVM-DZZWHti8.js} +1 -1
  28. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-DhhHPAmj.js → ganttDiagram-T4ZO3ILL-OwGGa6Lu.js} +1 -1
  29. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-B3Lc0h9q.js → gitGraphDiagram-UUTBAWPF-GKyWD4Qt.js} +1 -1
  30. package/dist/deck-client/assets/{graph-RTawgVWm.js → graph-CORzYQdB.js} +1 -1
  31. package/dist/deck-client/assets/{index-BfIfJXmS.js → index-hiIpM7EP.js} +3 -3
  32. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-BlR584kX.js → infoDiagram-42DDH7IO-DmgqJCcF.js} +1 -1
  33. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DygKoNGY.js → ishikawaDiagram-UXIWVN3A-D-1v7knu.js} +1 -1
  34. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-BnaiYp9N.js → journeyDiagram-VCZTEJTY-CYrGQE7b.js} +1 -1
  35. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BQBUBzJC.js → kanban-definition-6JOO6SKY-BJFDWiH-.js} +1 -1
  36. package/dist/deck-client/assets/{layout-DeZ8HI1T.js → layout-BTFFcaxF.js} +1 -1
  37. package/dist/deck-client/assets/{linear-C6roLi_9.js → linear-DAbl6COS.js} +1 -1
  38. package/dist/deck-client/assets/{min-CbUksbuI.js → min-oWHBrFBm.js} +1 -1
  39. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-iNxV62yN.js → mindmap-definition-QFDTVHPH-BTCB0VLO.js} +1 -1
  40. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-DHVA0jaG.js → pieDiagram-DEJITSTG-CUZChWNA.js} +1 -1
  41. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-DBeKKLUQ.js → quadrantDiagram-34T5L4WZ-4M1Um_e4.js} +1 -1
  42. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-CBwITx7p.js → requirementDiagram-MS252O5E-DLzQZ0B3.js} +1 -1
  43. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BtE-1YTU.js → sankeyDiagram-XADWPNL6-DcNgzV3E.js} +1 -1
  44. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-DN96yPP2.js → sequenceDiagram-FGHM5R23-CAcI2vC9.js} +1 -1
  45. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-VUkKC2uJ.js → stateDiagram-FHFEXIEX-CntjTTm5.js} +1 -1
  46. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-YiaphOU_.js +1 -0
  47. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-oUeZhRns.js → timeline-definition-GMOUNBTQ-D8zrit4U.js} +1 -1
  48. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-D87fK90n.js → vennDiagram-DHZGUBPP-C4SuFPgo.js} +1 -1
  49. package/dist/deck-client/assets/wardley-RL74JXVD-B3F-Olcq.js +162 -0
  50. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-Ca_i0QRA.js → wardleyDiagram-NUSXRM2D-kj73r6f-.js} +1 -1
  51. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CUOJVIvq.js → xychartDiagram-5P7HB3ND-CC_d_Ey3.js} +1 -1
  52. package/dist/deck-client/index.html +1 -1
  53. package/dist/server/chart-serve.js +549 -207
  54. package/dist/server/cli.js +541 -206
  55. package/dist/server/council-entry.js +0 -0
  56. package/dist/server/deck-server/deck-mcp-entry.js +0 -0
  57. package/dist/server/fb-wizard.js +0 -0
  58. package/dist/server/graph-mcp-entry.js +587 -244
  59. package/dist/server/server/cli.js +0 -0
  60. package/dist/server/server/fb-wizard.js +0 -0
  61. package/dist/server/server/graph-mcp-entry.js +0 -0
  62. package/package.json +18 -17
  63. package/dist/chart-client/assets/index-D7x8nz-H.js +0 -441
  64. package/dist/deck-client/assets/channel-ERh5jKXV.js +0 -1
  65. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CMi1Gaev.js +0 -1
  66. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CMi1Gaev.js +0 -1
  67. package/dist/deck-client/assets/clone-DfWhlD4X.js +0 -1
  68. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CA0IjulK.js +0 -1
  69. package/dist/deck-client/assets/wardley-RL74JXVD-DYbYcpDp.js +0 -162
@@ -1731,7 +1731,7 @@ var require_usage_reader = __commonJS({
1731
1731
  async readJsonlFile(filePath, cutoffTime) {
1732
1732
  const entries = [];
1733
1733
  const fileProcessedEntries = /* @__PURE__ */ new Set();
1734
- return new Promise((resolve3) => {
1734
+ return new Promise((resolve4) => {
1735
1735
  const rl = readline.createInterface({
1736
1736
  input: createReadStream(filePath),
1737
1737
  crlfDelay: Infinity
@@ -1789,11 +1789,11 @@ var require_usage_reader = __commonJS({
1789
1789
  }
1790
1790
  });
1791
1791
  rl.on("close", () => {
1792
- resolve3(entries);
1792
+ resolve4(entries);
1793
1793
  });
1794
1794
  rl.on("error", (error) => {
1795
1795
  console.error("Error reading file:", filePath, error);
1796
- resolve3(entries);
1796
+ resolve4(entries);
1797
1797
  });
1798
1798
  });
1799
1799
  }
@@ -3591,7 +3591,7 @@ var require_src = __commonJS({
3591
3591
  if (session.active) throw new Error(`Agent already running in session ${sessionId}`);
3592
3592
  const { command, args = [], env = {} } = options;
3593
3593
  if (!command) throw new Error("startScriptInSession requires a command");
3594
- return new Promise((resolve3, reject) => {
3594
+ return new Promise((resolve4, reject) => {
3595
3595
  this.scriptBridge.startSession(sessionId, {
3596
3596
  command,
3597
3597
  args,
@@ -3613,7 +3613,7 @@ var require_src = __commonJS({
3613
3613
  session.lastActivity = /* @__PURE__ */ new Date();
3614
3614
  this.broadcastToSession(sessionId, { type: "script_stopped", sessionId });
3615
3615
  if (exitCode === 0) {
3616
- resolve3({ code: exitCode, signal });
3616
+ resolve4({ code: exitCode, signal });
3617
3617
  } else {
3618
3618
  reject(new Error(`Script exited with code ${exitCode}`));
3619
3619
  }
@@ -5908,7 +5908,7 @@ var PostImplLaunchExecutor = class {
5908
5908
  return 3001;
5909
5909
  }
5910
5910
  startDevServer(port, databaseUrl) {
5911
- return new Promise((resolve3) => {
5911
+ return new Promise((resolve4) => {
5912
5912
  const env = { ...process.env, PORT: String(port), ...databaseUrl ? { DATABASE_URL: databaseUrl } : {} };
5913
5913
  this.devProcess = (0, import_child_process3.spawn)("npm", ["run", "dev"], {
5914
5914
  cwd: this.workingDir,
@@ -5920,7 +5920,7 @@ var PostImplLaunchExecutor = class {
5920
5920
  const timeout = setTimeout(() => {
5921
5921
  if (!resolved) {
5922
5922
  resolved = true;
5923
- this.healthCheck(port).then(resolve3);
5923
+ this.healthCheck(port).then(resolve4);
5924
5924
  }
5925
5925
  }, 15e3);
5926
5926
  const onData = (data) => {
@@ -5929,7 +5929,7 @@ var PostImplLaunchExecutor = class {
5929
5929
  if (!resolved) {
5930
5930
  resolved = true;
5931
5931
  clearTimeout(timeout);
5932
- resolve3(true);
5932
+ resolve4(true);
5933
5933
  }
5934
5934
  }
5935
5935
  };
@@ -5940,7 +5940,7 @@ var PostImplLaunchExecutor = class {
5940
5940
  if (!resolved) {
5941
5941
  resolved = true;
5942
5942
  clearTimeout(timeout);
5943
- resolve3(false);
5943
+ resolve4(false);
5944
5944
  }
5945
5945
  });
5946
5946
  this.devProcess.unref();
@@ -6963,15 +6963,15 @@ ${links}
6963
6963
 
6964
6964
  // src/server/graph/index.ts
6965
6965
  var import_node_fs15 = require("node:fs");
6966
- var import_node_path17 = require("node:path");
6966
+ var import_node_path16 = require("node:path");
6967
6967
 
6968
6968
  // src/server/graph/core/graph-builder.ts
6969
6969
  var import_node_fs12 = require("node:fs");
6970
- var import_node_path13 = require("node:path");
6970
+ var import_node_path12 = require("node:path");
6971
6971
  init_config();
6972
6972
 
6973
6973
  // src/server/graph/core/parser-registry.ts
6974
- var import_node_path12 = require("node:path");
6974
+ var import_node_path11 = require("node:path");
6975
6975
 
6976
6976
  // src/server/graph/parsers/ts/typescript-project.ts
6977
6977
  var import_node_fs5 = require("node:fs");
@@ -6979,35 +6979,12 @@ var import_node_path5 = require("node:path");
6979
6979
  init_config();
6980
6980
 
6981
6981
  // src/server/graph/core/resolve-paths.ts
6982
- var import_node_fs2 = require("node:fs");
6983
- var import_node_path2 = require("node:path");
6984
- function detectDbDir(rootDir, config) {
6985
- if (config.paths?.dbDir) return (0, import_node_path2.join)(rootDir, config.paths.dbDir);
6986
- const prismaDir = (0, import_node_path2.join)(rootDir, "prisma");
6987
- if ((0, import_node_fs2.existsSync)(prismaDir)) return prismaDir;
6988
- return null;
6989
- }
6990
- function resolveProjectPaths(rootDir, config) {
6991
- const dbDir = detectDbDir(rootDir, config);
6992
- if (config.paths?.appDir) {
6993
- const appDir = (0, import_node_path2.join)(rootDir, config.paths.appDir);
6994
- const srcDir = config.paths.srcDir ? (0, import_node_path2.join)(rootDir, config.paths.srcDir) : (0, import_node_path2.dirname)(appDir);
6995
- return { srcDir, appDir, apiDir: (0, import_node_path2.join)(appDir, "api"), dbDir };
6996
- }
6997
- const srcApp = (0, import_node_path2.join)(rootDir, "src", "app");
6998
- if ((0, import_node_fs2.existsSync)(srcApp)) {
6999
- return { srcDir: (0, import_node_path2.join)(rootDir, "src"), appDir: srcApp, apiDir: (0, import_node_path2.join)(srcApp, "api"), dbDir };
7000
- }
7001
- const rootApp = (0, import_node_path2.join)(rootDir, "app");
7002
- if ((0, import_node_fs2.existsSync)(rootApp)) {
7003
- return { srcDir: rootDir, appDir: rootApp, apiDir: (0, import_node_path2.join)(rootApp, "api"), dbDir };
7004
- }
7005
- return null;
7006
- }
7007
-
7008
- // src/server/graph/core/walk.ts
7009
6982
  var import_node_fs3 = require("node:fs");
7010
6983
  var import_node_path3 = require("node:path");
6984
+
6985
+ // src/server/graph/core/walk.ts
6986
+ var import_node_fs2 = require("node:fs");
6987
+ var import_node_path2 = require("node:path");
7011
6988
  var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
7012
6989
  "node_modules",
7013
6990
  ".git",
@@ -7023,12 +7000,12 @@ var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
7023
7000
  ]);
7024
7001
  function walk(dir, exts) {
7025
7002
  const results = [];
7026
- if (!(0, import_node_fs3.existsSync)(dir)) return results;
7027
- for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
7028
- const full = (0, import_node_path3.join)(dir, entry.name);
7003
+ if (!(0, import_node_fs2.existsSync)(dir)) return results;
7004
+ for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
7005
+ const full = (0, import_node_path2.join)(dir, entry.name);
7029
7006
  if (entry.isDirectory()) {
7030
7007
  results.push(...walk(full, exts));
7031
- } else if (exts.includes((0, import_node_path3.extname)(entry.name))) {
7008
+ } else if (exts.includes((0, import_node_path2.extname)(entry.name))) {
7032
7009
  results.push(full);
7033
7010
  }
7034
7011
  }
@@ -7036,19 +7013,205 @@ function walk(dir, exts) {
7036
7013
  }
7037
7014
  function walkWithIgnore(dir, exts, opts = {}) {
7038
7015
  const results = [];
7039
- if (!(0, import_node_fs3.existsSync)(dir)) return results;
7016
+ if (!(0, import_node_fs2.existsSync)(dir)) return results;
7040
7017
  const skip = opts.extraIgnore ? /* @__PURE__ */ new Set([...DEFAULT_IGNORE_DIRS, ...opts.extraIgnore]) : DEFAULT_IGNORE_DIRS;
7041
- for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
7018
+ for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
7042
7019
  if (entry.isDirectory()) {
7043
7020
  if (skip.has(entry.name)) continue;
7044
- results.push(...walkWithIgnore((0, import_node_path3.join)(dir, entry.name), exts, opts));
7045
- } else if (exts.includes((0, import_node_path3.extname)(entry.name))) {
7046
- results.push((0, import_node_path3.join)(dir, entry.name));
7021
+ results.push(...walkWithIgnore((0, import_node_path2.join)(dir, entry.name), exts, opts));
7022
+ } else if (exts.includes((0, import_node_path2.extname)(entry.name))) {
7023
+ results.push((0, import_node_path2.join)(dir, entry.name));
7047
7024
  }
7048
7025
  }
7049
7026
  return results;
7050
7027
  }
7051
7028
 
7029
+ // src/server/graph/core/resolve-paths.ts
7030
+ function hasSqlFiles(dir) {
7031
+ if (!(0, import_node_fs3.existsSync)(dir)) return false;
7032
+ try {
7033
+ return (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true }).some(
7034
+ (e) => e.isFile() && e.name.endsWith(".sql")
7035
+ );
7036
+ } catch {
7037
+ return false;
7038
+ }
7039
+ }
7040
+ function hasNestedMigrationSql(dir) {
7041
+ if (!(0, import_node_fs3.existsSync)(dir)) return false;
7042
+ try {
7043
+ return (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true }).some(
7044
+ (e) => e.isDirectory() && (0, import_node_fs3.existsSync)((0, import_node_path3.join)(dir, e.name, "migration.sql"))
7045
+ );
7046
+ } catch {
7047
+ return false;
7048
+ }
7049
+ }
7050
+ function resolveDbFromDir(dir) {
7051
+ if (!(0, import_node_fs3.existsSync)(dir)) return { kind: "none", schemaPath: null, migrationsDir: null };
7052
+ const schemaPath = (0, import_node_path3.join)(dir, "schema.prisma");
7053
+ if ((0, import_node_fs3.existsSync)(schemaPath)) {
7054
+ const migrationsDir2 = (0, import_node_path3.join)(dir, "migrations");
7055
+ return {
7056
+ kind: "prisma",
7057
+ schemaPath,
7058
+ migrationsDir: (0, import_node_fs3.existsSync)(migrationsDir2) ? migrationsDir2 : null
7059
+ };
7060
+ }
7061
+ const migrationsDir = (0, import_node_path3.join)(dir, "migrations");
7062
+ if (hasSqlFiles(migrationsDir) || hasNestedMigrationSql(migrationsDir)) {
7063
+ return { kind: "sql-migrations", migrationsDir, schemaPath: null };
7064
+ }
7065
+ if (hasSqlFiles(dir) || hasNestedMigrationSql(dir)) {
7066
+ return { kind: "sql-migrations", migrationsDir: dir, schemaPath: null };
7067
+ }
7068
+ return { kind: "none", schemaPath: null, migrationsDir: null };
7069
+ }
7070
+ function detectDbConfig(rootDir, config) {
7071
+ if (config.paths?.dbDir) {
7072
+ return resolveDbFromDir((0, import_node_path3.join)(rootDir, config.paths.dbDir));
7073
+ }
7074
+ const candidates = ["prisma", "supabase", "drizzle", (0, import_node_path3.join)("db", "migrations"), "migrations"];
7075
+ for (const c of candidates) {
7076
+ const dir = (0, import_node_path3.join)(rootDir, c);
7077
+ const resolved = resolveDbFromDir(dir);
7078
+ if (resolved.kind !== "none") return resolved;
7079
+ }
7080
+ return { kind: "none", schemaPath: null, migrationsDir: null };
7081
+ }
7082
+ function detectDbDir(rootDir, config, dbConfig) {
7083
+ if (config.paths?.dbDir) return (0, import_node_path3.join)(rootDir, config.paths.dbDir);
7084
+ if (dbConfig.kind === "prisma") return (0, import_node_path3.dirname)(dbConfig.schemaPath);
7085
+ if (dbConfig.kind === "sql-migrations") return dbConfig.migrationsDir;
7086
+ return null;
7087
+ }
7088
+ var NON_SOURCE_DIRS = /* @__PURE__ */ new Set([
7089
+ ...DEFAULT_IGNORE_DIRS,
7090
+ // DB conventions (handled by db parsers)
7091
+ "prisma",
7092
+ "supabase",
7093
+ "drizzle",
7094
+ "migrations",
7095
+ // Web assets
7096
+ "public",
7097
+ "static",
7098
+ "assets",
7099
+ // Docs
7100
+ "docs",
7101
+ "documentation",
7102
+ // Test dirs (project tests aren't part of the structural graph)
7103
+ "tests",
7104
+ "__tests__",
7105
+ "e2e",
7106
+ "playwright",
7107
+ "cypress",
7108
+ // Monorepo workspace roots — separate graph projects per .launchchart.json
7109
+ "packages",
7110
+ "apps",
7111
+ "services",
7112
+ "libs"
7113
+ ]);
7114
+ function dirHasTSFiles(dir) {
7115
+ if (!(0, import_node_fs3.existsSync)(dir)) return false;
7116
+ try {
7117
+ const stack = [dir];
7118
+ while (stack.length > 0) {
7119
+ const cur = stack.pop();
7120
+ const entries = (0, import_node_fs3.readdirSync)(cur, { withFileTypes: true });
7121
+ for (const e of entries) {
7122
+ if (e.isFile() && (e.name.endsWith(".ts") || e.name.endsWith(".tsx"))) return true;
7123
+ if (e.isDirectory() && !e.name.startsWith(".") && !DEFAULT_IGNORE_DIRS.has(e.name)) {
7124
+ stack.push((0, import_node_path3.join)(cur, e.name));
7125
+ }
7126
+ }
7127
+ }
7128
+ } catch {
7129
+ }
7130
+ return false;
7131
+ }
7132
+ function collectCodeBearingChildren(dir, extraSkip) {
7133
+ if (!(0, import_node_fs3.existsSync)(dir)) return [];
7134
+ const out = [];
7135
+ try {
7136
+ for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
7137
+ if (!entry.isDirectory()) continue;
7138
+ if (entry.name.startsWith(".")) continue;
7139
+ if (NON_SOURCE_DIRS.has(entry.name)) continue;
7140
+ if (extraSkip?.has(entry.name)) continue;
7141
+ const full = (0, import_node_path3.join)(dir, entry.name);
7142
+ if (dirHasTSFiles(full)) out.push(full);
7143
+ }
7144
+ } catch {
7145
+ }
7146
+ return out;
7147
+ }
7148
+ function detectSrcRoots(rootDir, srcDir, appDir, config) {
7149
+ if (config.paths?.srcRoots && config.paths.srcRoots.length > 0) {
7150
+ const roots2 = /* @__PURE__ */ new Set();
7151
+ roots2.add(appDir);
7152
+ for (const r of config.paths.srcRoots) {
7153
+ const abs = (0, import_node_path3.isAbsolute)(r) ? r : (0, import_node_path3.resolve)(rootDir, r);
7154
+ roots2.add(abs);
7155
+ }
7156
+ return [...roots2];
7157
+ }
7158
+ const roots = /* @__PURE__ */ new Set();
7159
+ roots.add(appDir);
7160
+ for (const c of collectCodeBearingChildren(srcDir)) roots.add(c);
7161
+ if (srcDir !== rootDir) {
7162
+ const skipSrcWrapper = /* @__PURE__ */ new Set([(0, import_node_path3.basename)(srcDir)]);
7163
+ for (const c of collectCodeBearingChildren(rootDir, skipSrcWrapper)) roots.add(c);
7164
+ }
7165
+ return [...roots];
7166
+ }
7167
+ var CONVENTION_NAMES = ["middleware.ts", "middleware.tsx", "instrumentation.ts", "instrumentation.tsx"];
7168
+ function detectConventionFiles(rootDir, srcDir) {
7169
+ const out = [];
7170
+ const seen = /* @__PURE__ */ new Set();
7171
+ const dirs = srcDir === rootDir ? [rootDir] : [srcDir, rootDir];
7172
+ for (const dir of dirs) {
7173
+ for (const name of CONVENTION_NAMES) {
7174
+ const full = (0, import_node_path3.join)(dir, name);
7175
+ if (!seen.has(full) && (0, import_node_fs3.existsSync)(full)) {
7176
+ try {
7177
+ if ((0, import_node_fs3.statSync)(full).isFile()) {
7178
+ seen.add(full);
7179
+ out.push(full);
7180
+ }
7181
+ } catch {
7182
+ }
7183
+ }
7184
+ }
7185
+ }
7186
+ return out;
7187
+ }
7188
+ function resolveProjectPaths(rootDir, config) {
7189
+ let srcDir;
7190
+ let appDir;
7191
+ if (config.paths?.appDir) {
7192
+ appDir = (0, import_node_path3.join)(rootDir, config.paths.appDir);
7193
+ srcDir = config.paths.srcDir ? (0, import_node_path3.join)(rootDir, config.paths.srcDir) : (0, import_node_path3.dirname)(appDir);
7194
+ } else {
7195
+ const srcApp = (0, import_node_path3.join)(rootDir, "src", "app");
7196
+ const rootApp = (0, import_node_path3.join)(rootDir, "app");
7197
+ if ((0, import_node_fs3.existsSync)(srcApp)) {
7198
+ srcDir = (0, import_node_path3.join)(rootDir, "src");
7199
+ appDir = srcApp;
7200
+ } else if ((0, import_node_fs3.existsSync)(rootApp)) {
7201
+ srcDir = rootDir;
7202
+ appDir = rootApp;
7203
+ } else {
7204
+ return null;
7205
+ }
7206
+ }
7207
+ const apiDir = (0, import_node_path3.join)(appDir, "api");
7208
+ const dbConfig = detectDbConfig(rootDir, config);
7209
+ const dbDir = detectDbDir(rootDir, config, dbConfig);
7210
+ const srcRoots = detectSrcRoots(rootDir, srcDir, appDir, config);
7211
+ const conventionFiles = detectConventionFiles(rootDir, srcDir);
7212
+ return { srcDir, appDir, apiDir, dbDir, srcRoots, conventionFiles, dbConfig };
7213
+ }
7214
+
7052
7215
  // src/server/graph/parsers/ts/typescript-project.ts
7053
7216
  init_ts_extractor();
7054
7217
  var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
@@ -7065,8 +7228,12 @@ var CLASSIFICATION_TO_LAYER = {
7065
7228
  "mcp-tool": "ui",
7066
7229
  external: "ui"
7067
7230
  };
7068
- function toNodeId(srcDir, absPath) {
7069
- return (0, import_node_path5.relative)(srcDir, absPath).replace(/\\/g, "/");
7231
+ function toNodeId(srcDir, rootDir, absPath) {
7232
+ const relFromSrc = (0, import_node_path5.relative)(srcDir, absPath).replace(/\\/g, "/");
7233
+ if (relFromSrc.startsWith("..")) {
7234
+ return (0, import_node_path5.relative)(rootDir, absPath).replace(/\\/g, "/");
7235
+ }
7236
+ return relFromSrc;
7070
7237
  }
7071
7238
  function resolveImport(srcDir, specifier) {
7072
7239
  if (!specifier.startsWith("@/")) return null;
@@ -7156,12 +7323,13 @@ function extractRoute(id) {
7156
7323
  function nameFromFilename(absPath) {
7157
7324
  return (0, import_node_path5.basename)(absPath, (0, import_node_path5.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
7158
7325
  }
7159
- function filePathToApiRoute(apiDir, absPath) {
7160
- let route = "/" + (0, import_node_path5.relative)(apiDir, absPath).replace(/\\/g, "/").replace(/\/route\.tsx?$/, "");
7326
+ function filePathToAppRoute(appDir, absPath) {
7327
+ let route = ("/" + (0, import_node_path5.relative)(appDir, absPath).replace(/\\/g, "/")).replace(/\/route\.tsx?$/, "");
7328
+ route = route.replace(/\/\([^)]+\)/g, "");
7329
+ route = route.replace(/\[\.\.\.([^\]]+)\]/g, "*$1");
7161
7330
  route = route.replace(/\[([^\]]+)\]/g, ":$1");
7162
7331
  route = route.replace(/\/+/g, "/");
7163
- if (route === "/") return "/api";
7164
- return "/api" + route;
7332
+ return route === "" ? "/" : route;
7165
7333
  }
7166
7334
  function camelToPascal(s) {
7167
7335
  if (!s) return s;
@@ -7246,7 +7414,7 @@ function matchRouteToPage(route, routeToNodeId) {
7246
7414
  if (routeToNodeId.has(normalized)) return routeToNodeId.get(normalized);
7247
7415
  return null;
7248
7416
  }
7249
- function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
7417
+ function extractEdges(srcDir, rootDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
7250
7418
  const edges = [];
7251
7419
  const flagged = [];
7252
7420
  const seen = /* @__PURE__ */ new Set();
@@ -7274,7 +7442,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
7274
7442
  for (const name of names) {
7275
7443
  const targetAbs = barrelMap.get(name);
7276
7444
  if (targetAbs) {
7277
- const targetId = toNodeId(srcDir, targetAbs);
7445
+ const targetId = toNodeId(srcDir, rootDir, targetAbs);
7278
7446
  if (nodeIdSet.has(targetId)) {
7279
7447
  if (!byTarget.has(targetId)) byTarget.set(targetId, []);
7280
7448
  byTarget.get(targetId).push(name);
@@ -7288,7 +7456,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
7288
7456
  } else {
7289
7457
  const resolved = resolveImport(srcDir, specifier);
7290
7458
  if (resolved) {
7291
- const targetId = toNodeId(srcDir, resolved);
7459
+ const targetId = toNodeId(srcDir, rootDir, resolved);
7292
7460
  if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
7293
7461
  addEdge(targetId, edgeTypeFor(isTypeOnly, names));
7294
7462
  }
@@ -7297,7 +7465,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
7297
7465
  } else if (specifier.startsWith(".")) {
7298
7466
  const resolved = resolveRelativeImport(absPath, specifier);
7299
7467
  if (resolved) {
7300
- const targetId = toNodeId(srcDir, resolved);
7468
+ const targetId = toNodeId(srcDir, rootDir, resolved);
7301
7469
  if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
7302
7470
  addEdge(targetId, edgeTypeFor(isTypeOnly, names));
7303
7471
  }
@@ -7349,13 +7517,22 @@ function generate(rootDir) {
7349
7517
  const config = loadConfig(rootDir);
7350
7518
  const paths = resolveProjectPaths(rootDir, config);
7351
7519
  const srcDir = paths.srcDir;
7352
- const apiDir = paths.apiDir;
7353
- const appFiles = walk(paths.appDir, [".tsx", ".ts"]);
7354
- const clientFiles = walk((0, import_node_path5.join)(srcDir, "client"), [".tsx", ".ts"]);
7355
- const serverFiles = walk((0, import_node_path5.join)(srcDir, "server"), [".ts", ".tsx"]);
7356
- const libFiles = walk((0, import_node_path5.join)(srcDir, "lib"), [".ts", ".tsx"]);
7357
- const configFiles = walk((0, import_node_path5.join)(srcDir, "config"), [".ts", ".tsx"]);
7358
- const allDiscovered = [...appFiles, ...clientFiles, ...serverFiles, ...libFiles, ...configFiles];
7520
+ const allDiscovered = [];
7521
+ const discoveredSet = /* @__PURE__ */ new Set();
7522
+ for (const root of paths.srcRoots) {
7523
+ for (const f of walk(root, [".tsx", ".ts"])) {
7524
+ if (!discoveredSet.has(f)) {
7525
+ discoveredSet.add(f);
7526
+ allDiscovered.push(f);
7527
+ }
7528
+ }
7529
+ }
7530
+ for (const conv of paths.conventionFiles) {
7531
+ if (!discoveredSet.has(conv)) {
7532
+ discoveredSet.add(conv);
7533
+ allDiscovered.push(conv);
7534
+ }
7535
+ }
7359
7536
  const parsedByPath = /* @__PURE__ */ new Map();
7360
7537
  for (const absPath of allDiscovered) {
7361
7538
  parsedByPath.set(absPath, parseFileTS(absPath));
@@ -7367,7 +7544,7 @@ function generate(rootDir) {
7367
7544
  const routeToNodeId = /* @__PURE__ */ new Map();
7368
7545
  const fileSet = allDiscovered.filter((f) => !(0, import_node_path5.basename)(f).startsWith("index."));
7369
7546
  for (const absPath of fileSet) {
7370
- const id = toNodeId(srcDir, absPath);
7547
+ const id = toNodeId(srcDir, rootDir, absPath);
7371
7548
  const type = classifyType(absPath, id);
7372
7549
  if (type === "test" || type === "story") continue;
7373
7550
  const parsed = parsedByPath.get(absPath);
@@ -7382,7 +7559,7 @@ function generate(rootDir) {
7382
7559
  const dbCalls = extractDbCallsTS(absPath);
7383
7560
  const authWrappers = extractAuthWrappersTS(absPath);
7384
7561
  const deep = extractDeep(absPath);
7385
- const routePath = (0, import_node_fs5.existsSync)(apiDir) ? filePathToApiRoute(apiDir, absPath) : `/api/${id.replace(/\/route\.tsx?$/, "")}`;
7562
+ const routePath = filePathToAppRoute(paths.appDir, absPath);
7386
7563
  const mutations = dbCalls.filter((c) => c.isMutation);
7387
7564
  const mutates = mutations.length > 0;
7388
7565
  const authStrategy = [...authWrappers];
@@ -7426,11 +7603,12 @@ function generate(rootDir) {
7426
7603
  const uiEdges = [];
7427
7604
  const uiFlagged = [];
7428
7605
  for (const absPath of fileSet) {
7429
- const id = toNodeId(srcDir, absPath);
7606
+ const id = toNodeId(srcDir, rootDir, absPath);
7430
7607
  if (!nodeIdSet.has(id)) continue;
7431
7608
  const parsed = parsedByPath.get(absPath);
7432
7609
  const { edges, flagged } = extractEdges(
7433
7610
  srcDir,
7611
+ rootDir,
7434
7612
  absPath,
7435
7613
  id,
7436
7614
  parsed,
@@ -7443,7 +7621,7 @@ function generate(rootDir) {
7443
7621
  }
7444
7622
  const fetchCallEntries = [];
7445
7623
  for (const absPath of fileSet) {
7446
- const sourceId = toNodeId(srcDir, absPath);
7624
+ const sourceId = toNodeId(srcDir, rootDir, absPath);
7447
7625
  if (!nodeIdSet.has(sourceId)) continue;
7448
7626
  const parsed = parsedByPath.get(absPath);
7449
7627
  if (parsed.fetchCalls.length === 0) continue;
@@ -7482,7 +7660,7 @@ function generate(rootDir) {
7482
7660
  for (const name of names) {
7483
7661
  const targetAbs = barrelMap.get(name);
7484
7662
  if (!targetAbs) continue;
7485
- const targetId2 = toNodeId(srcDir, targetAbs);
7663
+ const targetId2 = toNodeId(srcDir, rootDir, targetAbs);
7486
7664
  if (!nodeIdSet.has(targetId2)) continue;
7487
7665
  const key2 = `${externalId}\u2192${targetId2}`;
7488
7666
  if (seen.has(key2)) continue;
@@ -7496,7 +7674,7 @@ function generate(rootDir) {
7496
7674
  resolved = resolveRelativeImport(absPath, specifier);
7497
7675
  }
7498
7676
  if (!resolved) continue;
7499
- const targetId = toNodeId(srcDir, resolved);
7677
+ const targetId = toNodeId(srcDir, rootDir, resolved);
7500
7678
  if (!nodeIdSet.has(targetId)) continue;
7501
7679
  if (targetId.endsWith("/index.ts") || targetId.endsWith("/index.tsx")) continue;
7502
7680
  const key = `${externalId}\u2192${targetId}`;
@@ -7674,7 +7852,7 @@ var typescriptProjectParser = {
7674
7852
 
7675
7853
  // src/server/graph/parsers/db/prisma-schema.ts
7676
7854
  var import_node_fs6 = require("node:fs");
7677
- var import_node_path6 = require("node:path");
7855
+ init_config();
7678
7856
  function parseModels(content) {
7679
7857
  const nodes = [];
7680
7858
  const relations = [];
@@ -7765,10 +7943,24 @@ function parseEnums(content) {
7765
7943
  return nodes;
7766
7944
  }
7767
7945
  function detect2(rootDir) {
7768
- return (0, import_node_fs6.existsSync)((0, import_node_path6.join)(rootDir, "prisma", "schema.prisma"));
7946
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
7947
+ return paths?.dbConfig.kind === "prisma" && (0, import_node_fs6.existsSync)(paths.dbConfig.schemaPath);
7769
7948
  }
7770
7949
  function generate2(rootDir) {
7771
- const schemaPath = (0, import_node_path6.join)(rootDir, "prisma", "schema.prisma");
7950
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
7951
+ if (paths.dbConfig.kind !== "prisma") {
7952
+ return {
7953
+ metadata: { generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), layer: "db", source: "none" },
7954
+ nodes: [],
7955
+ edges: [],
7956
+ cross_refs: [],
7957
+ contradictions: [],
7958
+ warnings: [],
7959
+ flagged_edges: [],
7960
+ patterns: { total_tables: 0, total_enums: 0, total_relations: 0 }
7961
+ };
7962
+ }
7963
+ const schemaPath = paths.dbConfig.schemaPath;
7772
7964
  const content = (0, import_node_fs6.readFileSync)(schemaPath, "utf-8");
7773
7965
  const { nodes: modelNodes, relations } = parseModels(content);
7774
7966
  const enumNodes = parseEnums(content);
@@ -7789,7 +7981,7 @@ function generate2(rootDir) {
7789
7981
  metadata: {
7790
7982
  generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
7791
7983
  scope: "prisma-schema",
7792
- source: "prisma/schema.prisma",
7984
+ source: schemaPath,
7793
7985
  provider: "postgresql",
7794
7986
  layer: "db",
7795
7987
  total_models: modelNodes.length,
@@ -7827,7 +8019,8 @@ var prismaSchemaParser = {
7827
8019
 
7828
8020
  // src/server/graph/parsers/db/sql-migrations.ts
7829
8021
  var import_node_fs7 = require("node:fs");
7830
- var import_node_path7 = require("node:path");
8022
+ var import_node_path6 = require("node:path");
8023
+ init_config();
7831
8024
  var PG_TO_PRISMA = {
7832
8025
  "TEXT": "String",
7833
8026
  "VARCHAR": "String",
@@ -7858,51 +8051,149 @@ function pgTypeToPrisma(pgType) {
7858
8051
  const upper = pgType.toUpperCase().trim();
7859
8052
  return PG_TO_PRISMA[upper] ?? upper;
7860
8053
  }
8054
+ var ID = `(?:"[\\w$]+"|[\\w$]+)`;
8055
+ var QID = `(?:${ID}\\.)?${ID}`;
8056
+ function bareName(captured) {
8057
+ const parts = captured.split(".");
8058
+ const last = parts[parts.length - 1];
8059
+ return last.replace(/^"(.*)"$/, "$1").trim();
8060
+ }
7861
8061
  function parseCreateTable(sql, state) {
7862
- const re = /CREATE\s+TABLE\s+"(\w+)"\s*\(([\s\S]*?)\);/gi;
8062
+ const re = new RegExp(
8063
+ `CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
8064
+ "gi"
8065
+ );
7863
8066
  let m;
7864
8067
  while ((m = re.exec(sql)) !== null) {
7865
- const tableName = m[1];
8068
+ const tableName = bareName(m[1]);
7866
8069
  const body = m[2];
7867
8070
  const columns = /* @__PURE__ */ new Map();
7868
8071
  let primaryCol = null;
7869
- for (const line of body.split("\n")) {
7870
- const trimmed = line.trim().replace(/,\s*$/, "");
8072
+ const inlineFks = [];
8073
+ const lines = splitTopLevelCommas(body);
8074
+ for (const raw of lines) {
8075
+ const trimmed = raw.trim().replace(/,\s*$/, "");
7871
8076
  if (!trimmed || trimmed.startsWith("--")) continue;
7872
- const pkMatch = trimmed.match(/CONSTRAINT\s+"[^"]+"\s+PRIMARY\s+KEY\s*\("(\w+)"\)/i);
7873
- if (pkMatch) {
7874
- primaryCol = pkMatch[1];
8077
+ const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
8078
+ if (namedPk) {
8079
+ primaryCol = bareName(namedPk[1]);
8080
+ continue;
8081
+ }
8082
+ const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
8083
+ if (tablePk) {
8084
+ primaryCol = bareName(tablePk[1]);
8085
+ continue;
8086
+ }
8087
+ if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
8088
+ const namedFk = trimmed.match(new RegExp(
8089
+ `^CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8090
+ "i"
8091
+ ));
8092
+ if (namedFk) {
8093
+ inlineFks.push({
8094
+ constraintName: bareName(namedFk[1]),
8095
+ sourceTable: tableName,
8096
+ sourceColumn: bareName(namedFk[2]),
8097
+ targetTable: bareName(namedFk[3]),
8098
+ targetColumn: bareName(namedFk[4]),
8099
+ onDelete: namedFk[5] ?? null
8100
+ });
8101
+ continue;
8102
+ }
8103
+ const bareFk = trimmed.match(new RegExp(
8104
+ `^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8105
+ "i"
8106
+ ));
8107
+ if (bareFk) {
8108
+ inlineFks.push({
8109
+ constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
8110
+ sourceTable: tableName,
8111
+ sourceColumn: bareName(bareFk[1]),
8112
+ targetTable: bareName(bareFk[2]),
8113
+ targetColumn: bareName(bareFk[3]),
8114
+ onDelete: bareFk[4] ?? null
8115
+ });
7875
8116
  continue;
7876
8117
  }
7877
- if (/^\s*CONSTRAINT\s/i.test(trimmed)) continue;
7878
- const colMatch = trimmed.match(/^"(\w+)"\s+(.+)/);
8118
+ if (/^CONSTRAINT\s/i.test(trimmed)) continue;
8119
+ const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
7879
8120
  if (!colMatch) continue;
7880
- const colName = colMatch[1];
8121
+ const colName = bareName(colMatch[1]);
7881
8122
  let rest = colMatch[2];
8123
+ const inlineRefMatch = rest.match(new RegExp(
8124
+ `\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8125
+ "i"
8126
+ ));
8127
+ if (inlineRefMatch) {
8128
+ inlineFks.push({
8129
+ constraintName: `${tableName}_${colName}_fkey`,
8130
+ sourceTable: tableName,
8131
+ sourceColumn: colName,
8132
+ targetTable: bareName(inlineRefMatch[1]),
8133
+ targetColumn: bareName(inlineRefMatch[2]),
8134
+ onDelete: inlineRefMatch[3] ?? null
8135
+ });
8136
+ rest = rest.replace(inlineRefMatch[0], "").trim();
8137
+ }
7882
8138
  const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
8139
+ const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
8140
+ const isUnique = /\bUNIQUE\b/i.test(rest);
7883
8141
  const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
7884
8142
  const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
7885
- let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
8143
+ let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bPRIMARY\s+KEY\b/gi, "").replace(/\bUNIQUE\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
7886
8144
  columns.set(colName, {
7887
8145
  name: colName,
7888
8146
  type: colType,
7889
- nullable: !isNotNull,
7890
- primary: false,
7891
- unique: false,
8147
+ nullable: !isNotNull && !isPrimaryKey,
8148
+ primary: isPrimaryKey,
8149
+ unique: isUnique,
7892
8150
  default: defaultVal
7893
8151
  });
8152
+ if (isPrimaryKey) primaryCol = colName;
7894
8153
  }
7895
8154
  if (primaryCol && columns.has(primaryCol)) {
7896
8155
  columns.get(primaryCol).primary = true;
7897
8156
  }
7898
8157
  state.tables.set(tableName, { name: tableName, columns });
8158
+ state.fks.push(...inlineFks);
8159
+ }
8160
+ }
8161
+ function splitTopLevelCommas(body) {
8162
+ const out = [];
8163
+ let depth = 0;
8164
+ let buf = "";
8165
+ let inString = null;
8166
+ for (const ch of body) {
8167
+ if (inString) {
8168
+ buf += ch;
8169
+ if (ch === inString) inString = null;
8170
+ continue;
8171
+ }
8172
+ if (ch === "'" || ch === '"') {
8173
+ inString = ch;
8174
+ buf += ch;
8175
+ continue;
8176
+ }
8177
+ if (ch === "(") depth++;
8178
+ else if (ch === ")") depth--;
8179
+ if (ch === "," && depth === 0) {
8180
+ out.push(buf);
8181
+ buf = "";
8182
+ continue;
8183
+ }
8184
+ buf += ch;
7899
8185
  }
8186
+ if (buf.trim()) out.push(buf);
8187
+ return out;
7900
8188
  }
7901
8189
  function parseCreateEnum(sql, state) {
7902
- const re = /CREATE\s+TYPE\s+"(\w+)"\s+AS\s+ENUM\s*\(([^)]+)\)/gi;
8190
+ const re = new RegExp(
8191
+ `CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
8192
+ "gi"
8193
+ );
7903
8194
  let m;
7904
8195
  while ((m = re.exec(sql)) !== null) {
7905
- const enumName = m[1];
8196
+ const enumName = bareName(m[1]);
7906
8197
  const valuesStr = m[2];
7907
8198
  const values = new Set(
7908
8199
  valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
@@ -7911,11 +8202,14 @@ function parseCreateEnum(sql, state) {
7911
8202
  }
7912
8203
  }
7913
8204
  function parseAlterTable(sql, state) {
7914
- const addColRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+COLUMN\s+"(\w+)"\s+(.+?);/gi;
8205
+ const addColRe = new RegExp(
8206
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
8207
+ "gi"
8208
+ );
7915
8209
  let m;
7916
8210
  while ((m = addColRe.exec(sql)) !== null) {
7917
- const tableName = m[1];
7918
- const colName = m[2];
8211
+ const tableName = bareName(m[1]);
8212
+ const colName = bareName(m[2]);
7919
8213
  let rest = m[3];
7920
8214
  const table = state.tables.get(tableName);
7921
8215
  if (!table) continue;
@@ -7932,63 +8226,91 @@ function parseAlterTable(sql, state) {
7932
8226
  default: defaultVal
7933
8227
  });
7934
8228
  }
7935
- const dropColRe = /ALTER\s+TABLE\s+"(\w+)"\s+DROP\s+COLUMN\s+"(\w+)"/gi;
8229
+ const dropColRe = new RegExp(
8230
+ `ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
8231
+ "gi"
8232
+ );
7936
8233
  while ((m = dropColRe.exec(sql)) !== null) {
7937
- const table = state.tables.get(m[1]);
7938
- if (table) table.columns.delete(m[2]);
8234
+ const table = state.tables.get(bareName(m[1]));
8235
+ if (table) table.columns.delete(bareName(m[2]));
7939
8236
  }
7940
- const fkRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+CONSTRAINT\s+"([^"]+)"\s+FOREIGN\s+KEY\s*\("(\w+)"\)\s+REFERENCES\s+"(\w+)"\("(\w+)"\)(?:\s+ON\s+DELETE\s+(\w+(?:\s+\w+)?))?/gi;
8237
+ const fkRe = new RegExp(
8238
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8239
+ "gi"
8240
+ );
7941
8241
  while ((m = fkRe.exec(sql)) !== null) {
7942
8242
  state.fks.push({
7943
- constraintName: m[2],
7944
- sourceTable: m[1],
7945
- sourceColumn: m[3],
7946
- targetTable: m[4],
7947
- targetColumn: m[5],
8243
+ constraintName: bareName(m[2]),
8244
+ sourceTable: bareName(m[1]),
8245
+ sourceColumn: bareName(m[3]),
8246
+ targetTable: bareName(m[4]),
8247
+ targetColumn: bareName(m[5]),
7948
8248
  onDelete: m[6] ?? null
7949
8249
  });
7950
8250
  }
7951
8251
  }
7952
8252
  function parseAlterEnum(sql, state) {
7953
- const re = /ALTER\s+TYPE\s+"(\w+)"\s+ADD\s+VALUE\s+'([^']+)'/gi;
8253
+ const re = new RegExp(
8254
+ `ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
8255
+ "gi"
8256
+ );
7954
8257
  let m;
7955
8258
  while ((m = re.exec(sql)) !== null) {
7956
- const en = state.enums.get(m[1]);
8259
+ const en = state.enums.get(bareName(m[1]));
7957
8260
  if (en) en.values.add(m[2]);
7958
8261
  }
7959
8262
  }
7960
8263
  function parseDropTable(sql, state) {
7961
- const re = /DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?"(\w+)"/gi;
8264
+ const re = new RegExp(
8265
+ `DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
8266
+ "gi"
8267
+ );
7962
8268
  let m;
7963
8269
  while ((m = re.exec(sql)) !== null) {
7964
- state.tables.delete(m[1]);
7965
- state.fks = state.fks.filter((fk) => fk.sourceTable !== m[1] && fk.targetTable !== m[1]);
8270
+ const dropped = bareName(m[1]);
8271
+ state.tables.delete(dropped);
8272
+ state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
7966
8273
  }
7967
8274
  }
7968
8275
  function parseUniqueIndex(sql, state) {
7969
- const re = /CREATE\s+UNIQUE\s+INDEX\s+"[^"]+"\s+ON\s+"(\w+)"\("(\w+)"\)/gi;
8276
+ const re = new RegExp(
8277
+ `CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
8278
+ "gi"
8279
+ );
7970
8280
  let m;
7971
8281
  while ((m = re.exec(sql)) !== null) {
7972
- const table = state.tables.get(m[1]);
7973
- const col = table?.columns.get(m[2]);
8282
+ const tableName = bareName(m[1]);
8283
+ const colName = bareName(m[2]);
8284
+ const table = state.tables.get(tableName);
8285
+ const col = table?.columns.get(colName);
7974
8286
  if (col) col.unique = true;
7975
- if (!state.uniqueIndexes.has(m[1])) state.uniqueIndexes.set(m[1], /* @__PURE__ */ new Set());
7976
- state.uniqueIndexes.get(m[1]).add(m[2]);
8287
+ if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
8288
+ state.uniqueIndexes.get(tableName).add(colName);
8289
+ }
8290
+ }
8291
+ function discoverMigrationFiles(migrationsDir) {
8292
+ if (!(0, import_node_fs7.existsSync)(migrationsDir)) return [];
8293
+ const out = [];
8294
+ const entries = (0, import_node_fs7.readdirSync)(migrationsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
8295
+ for (const entry of entries) {
8296
+ if (entry.isDirectory()) {
8297
+ const sqlPath = (0, import_node_path6.join)(migrationsDir, entry.name, "migration.sql");
8298
+ if ((0, import_node_fs7.existsSync)(sqlPath)) out.push(sqlPath);
8299
+ } else if (entry.isFile() && entry.name.endsWith(".sql")) {
8300
+ out.push((0, import_node_path6.join)(migrationsDir, entry.name));
8301
+ }
7977
8302
  }
8303
+ return out;
7978
8304
  }
7979
- function parseMigrations(rootDir) {
7980
- const migrationsDir = (0, import_node_path7.join)(rootDir, "prisma", "migrations");
8305
+ function parseMigrations(migrationsDir) {
7981
8306
  const state = {
7982
8307
  tables: /* @__PURE__ */ new Map(),
7983
8308
  enums: /* @__PURE__ */ new Map(),
7984
8309
  fks: [],
7985
8310
  uniqueIndexes: /* @__PURE__ */ new Map()
7986
8311
  };
7987
- if (!(0, import_node_fs7.existsSync)(migrationsDir)) return state;
7988
- const dirs = (0, import_node_fs7.readdirSync)(migrationsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
7989
- for (const dir of dirs) {
7990
- const sqlPath = (0, import_node_path7.join)(migrationsDir, dir, "migration.sql");
7991
- if (!(0, import_node_fs7.existsSync)(sqlPath)) continue;
8312
+ if (!migrationsDir) return state;
8313
+ for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
7992
8314
  const sql = (0, import_node_fs7.readFileSync)(sqlPath, "utf-8");
7993
8315
  parseCreateEnum(sql, state);
7994
8316
  parseCreateTable(sql, state);
@@ -7999,9 +8321,8 @@ function parseMigrations(rootDir) {
7999
8321
  }
8000
8322
  return state;
8001
8323
  }
8002
- function loadPrismaState(rootDir) {
8003
- const schemaPath = (0, import_node_path7.join)(rootDir, "prisma", "schema.prisma");
8004
- if (!(0, import_node_fs7.existsSync)(schemaPath)) return null;
8324
+ function loadPrismaState(schemaPath) {
8325
+ if (!schemaPath || !(0, import_node_fs7.existsSync)(schemaPath)) return null;
8005
8326
  const content = (0, import_node_fs7.readFileSync)(schemaPath, "utf-8");
8006
8327
  const tables = /* @__PURE__ */ new Map();
8007
8328
  const enums = /* @__PURE__ */ new Map();
@@ -8166,14 +8487,28 @@ function verify(sqlState, prisma) {
8166
8487
  }
8167
8488
  return { contradictions, flaggedEdges };
8168
8489
  }
8490
+ function migrationsDirFor(rootDir) {
8491
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
8492
+ if (!paths) return null;
8493
+ if (paths.dbConfig.kind === "prisma" || paths.dbConfig.kind === "sql-migrations") {
8494
+ return paths.dbConfig.migrationsDir;
8495
+ }
8496
+ return null;
8497
+ }
8498
+ function schemaPathFor(rootDir) {
8499
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
8500
+ if (!paths) return null;
8501
+ return paths.dbConfig.kind === "prisma" ? paths.dbConfig.schemaPath : null;
8502
+ }
8169
8503
  function detect3(rootDir) {
8170
- const migrationsDir = (0, import_node_path7.join)(rootDir, "prisma", "migrations");
8171
- if (!(0, import_node_fs7.existsSync)(migrationsDir)) return false;
8172
- 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")));
8504
+ const dir = migrationsDirFor(rootDir);
8505
+ if (!dir) return false;
8506
+ return discoverMigrationFiles(dir).length > 0;
8173
8507
  }
8174
8508
  function generate3(rootDir) {
8175
- const sqlState = parseMigrations(rootDir);
8176
- const prisma = loadPrismaState(rootDir);
8509
+ const migrationsDir = migrationsDirFor(rootDir);
8510
+ const sqlState = parseMigrations(migrationsDir);
8511
+ const prisma = loadPrismaState(schemaPathFor(rootDir));
8177
8512
  const prismaTableIds = prisma ? new Set(prisma.tables.keys()) : /* @__PURE__ */ new Set();
8178
8513
  const prismaEnumIds = prisma ? new Set(prisma.enums.keys()) : /* @__PURE__ */ new Set();
8179
8514
  const nodes = [];
@@ -8219,7 +8554,7 @@ function generate3(rootDir) {
8219
8554
  metadata: {
8220
8555
  generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
8221
8556
  scope: "sql-migrations",
8222
- source: "prisma/migrations/",
8557
+ source: migrationsDir ?? "none",
8223
8558
  layer: "db",
8224
8559
  sql_tables: sqlState.tables.size,
8225
8560
  sql_enums: sqlState.enums.size,
@@ -8458,31 +8793,31 @@ var fetchResolverParser = {
8458
8793
 
8459
8794
  // src/server/graph/parsers/crosslayer/api-annotations.ts
8460
8795
  var import_node_fs8 = require("node:fs");
8461
- var import_node_path8 = require("node:path");
8796
+ var import_node_path7 = require("node:path");
8462
8797
  var API_ANNOTATION_RE = /@api\s+(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/\S+)/g;
8463
8798
  function walk2(dir, exts) {
8464
8799
  if (!(0, import_node_fs8.existsSync)(dir)) return [];
8465
8800
  const results = [];
8466
8801
  for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
8467
8802
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
8468
- const full = (0, import_node_path8.join)(dir, entry.name);
8803
+ const full = (0, import_node_path7.join)(dir, entry.name);
8469
8804
  if (entry.isDirectory()) {
8470
8805
  results.push(...walk2(full, exts));
8471
- } else if (exts.includes((0, import_node_path8.extname)(entry.name))) {
8806
+ } else if (exts.includes((0, import_node_path7.extname)(entry.name))) {
8472
8807
  results.push(full);
8473
8808
  }
8474
8809
  }
8475
8810
  return results;
8476
8811
  }
8477
8812
  function toNodeId2(srcDir, absPath) {
8478
- return (0, import_node_path8.relative)(srcDir, absPath).replace(/\\/g, "/");
8813
+ return (0, import_node_path7.relative)(srcDir, absPath).replace(/\\/g, "/");
8479
8814
  }
8480
8815
  var apiAnnotationsParser = {
8481
8816
  id: "api-annotations",
8482
8817
  layer: "crosslayer",
8483
8818
  concern: "api-binding",
8484
8819
  detect(rootDir) {
8485
- return (0, import_node_fs8.existsSync)((0, import_node_path8.join)(rootDir, "src"));
8820
+ return (0, import_node_fs8.existsSync)((0, import_node_path7.join)(rootDir, "src"));
8486
8821
  },
8487
8822
  generate(rootDir, layerOutputs) {
8488
8823
  const apiOutput = layerOutputs.get("api");
@@ -8493,7 +8828,7 @@ var apiAnnotationsParser = {
8493
8828
  const uiNodeIds = new Set(uiOutput?.nodes.map((n) => n.id) ?? []);
8494
8829
  const apiRoutes = loadApiRoutesFromOutput(apiOutput);
8495
8830
  const apiPathMap = buildApiPathMap(apiRoutes);
8496
- const srcDir = (0, import_node_path8.join)(rootDir, "src");
8831
+ const srcDir = (0, import_node_path7.join)(rootDir, "src");
8497
8832
  const files = walk2(srcDir, [".ts", ".tsx"]);
8498
8833
  const crossRefs = [];
8499
8834
  const flaggedEdges = [];
@@ -8544,7 +8879,7 @@ var apiAnnotationsParser = {
8544
8879
 
8545
8880
  // src/server/graph/parsers/crosslayer/url-literal-scanner.ts
8546
8881
  var import_node_fs9 = require("node:fs");
8547
- var import_node_path9 = require("node:path");
8882
+ var import_node_path8 = require("node:path");
8548
8883
  init_config();
8549
8884
  var URL_LITERAL_RE = /['"`](\/api\/[^'"`\s]+?)['"`]/g;
8550
8885
  function walk3(dir, exts) {
@@ -8552,17 +8887,17 @@ function walk3(dir, exts) {
8552
8887
  const results = [];
8553
8888
  for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
8554
8889
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
8555
- const full = (0, import_node_path9.join)(dir, entry.name);
8890
+ const full = (0, import_node_path8.join)(dir, entry.name);
8556
8891
  if (entry.isDirectory()) {
8557
8892
  results.push(...walk3(full, exts));
8558
- } else if (exts.includes((0, import_node_path9.extname)(entry.name))) {
8893
+ } else if (exts.includes((0, import_node_path8.extname)(entry.name))) {
8559
8894
  results.push(full);
8560
8895
  }
8561
8896
  }
8562
8897
  return results;
8563
8898
  }
8564
8899
  function toNodeId3(srcDir, absPath) {
8565
- return (0, import_node_path9.relative)(srcDir, absPath).replace(/\\/g, "/");
8900
+ return (0, import_node_path8.relative)(srcDir, absPath).replace(/\\/g, "/");
8566
8901
  }
8567
8902
  var urlLiteralScannerParser = {
8568
8903
  id: "url-literal-scanner",
@@ -8583,7 +8918,7 @@ var urlLiteralScannerParser = {
8583
8918
  const apiPathMap = buildApiPathMap(apiRoutes);
8584
8919
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
8585
8920
  const srcDir = paths.srcDir;
8586
- const clientDir = (0, import_node_path9.join)(srcDir, "client");
8921
+ const clientDir = (0, import_node_path8.join)(srcDir, "client");
8587
8922
  const files = [
8588
8923
  ...walk3(clientDir, [".ts", ".tsx"]),
8589
8924
  ...walk3(paths.appDir, [".ts", ".tsx"])
@@ -8625,7 +8960,7 @@ var urlLiteralScannerParser = {
8625
8960
 
8626
8961
  // src/server/graph/parsers/static/static-values.ts
8627
8962
  var import_node_fs10 = require("node:fs");
8628
- var import_node_path10 = require("node:path");
8963
+ var import_node_path9 = require("node:path");
8629
8964
  var parseCode = null;
8630
8965
  function tryLoadTreeSitter() {
8631
8966
  if (parseCode) return true;
@@ -8658,8 +8993,8 @@ function extractEnumValues(rootDir) {
8658
8993
  const nodes = [];
8659
8994
  const edges = [];
8660
8995
  const schemaPaths = [
8661
- (0, import_node_path10.join)(rootDir, "prisma", "schema.prisma"),
8662
- (0, import_node_path10.join)(rootDir, "prisma", "schema")
8996
+ (0, import_node_path9.join)(rootDir, "prisma", "schema.prisma"),
8997
+ (0, import_node_path9.join)(rootDir, "prisma", "schema")
8663
8998
  ];
8664
8999
  let content = "";
8665
9000
  for (const p of schemaPaths) {
@@ -8670,7 +9005,7 @@ function extractEnumValues(rootDir) {
8670
9005
  content = (0, import_node_fs10.readFileSync)(p, "utf-8");
8671
9006
  } else if (stat.isDirectory()) {
8672
9007
  const files = (0, import_node_fs10.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
8673
- content = files.map((f) => (0, import_node_fs10.readFileSync)((0, import_node_path10.join)(p, f), "utf-8")).join("\n");
9008
+ content = files.map((f) => (0, import_node_fs10.readFileSync)((0, import_node_path9.join)(p, f), "utf-8")).join("\n");
8674
9009
  }
8675
9010
  } catch {
8676
9011
  continue;
@@ -8826,14 +9161,14 @@ function extractSeedData(rootDir) {
8826
9161
  const nodes = [];
8827
9162
  const edges = [];
8828
9163
  const seedFiles = [
8829
- (0, import_node_path10.join)(rootDir, "prisma", "seed.ts"),
8830
- (0, import_node_path10.join)(rootDir, "prisma", "seed.js"),
8831
- (0, import_node_path10.join)(rootDir, "src", "server", "lib", "system-tags.ts")
9164
+ (0, import_node_path9.join)(rootDir, "prisma", "seed.ts"),
9165
+ (0, import_node_path9.join)(rootDir, "prisma", "seed.js"),
9166
+ (0, import_node_path9.join)(rootDir, "src", "server", "lib", "system-tags.ts")
8832
9167
  ].filter(import_node_fs10.existsSync);
8833
9168
  const useTreeSitter = tryLoadTreeSitter();
8834
9169
  for (const filePath of seedFiles) {
8835
9170
  const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
8836
- const relPath = (0, import_node_path10.relative)(rootDir, filePath);
9171
+ const relPath = (0, import_node_path9.relative)(rootDir, filePath);
8837
9172
  const seeded = detectSeededArrays(content, relPath);
8838
9173
  let astRoot = null;
8839
9174
  if (useTreeSitter && parseCode) {
@@ -8931,7 +9266,7 @@ function walkDir(dir, exts) {
8931
9266
  const results = [];
8932
9267
  for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true })) {
8933
9268
  if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
8934
- const full = (0, import_node_path10.join)(dir, entry.name);
9269
+ const full = (0, import_node_path9.join)(dir, entry.name);
8935
9270
  if (entry.isDirectory()) results.push(...walkDir(full, exts));
8936
9271
  else if (exts.some((ext) => entry.name.endsWith(ext))) results.push(full);
8937
9272
  }
@@ -8939,11 +9274,11 @@ function walkDir(dir, exts) {
8939
9274
  }
8940
9275
  function extractConstants(rootDir) {
8941
9276
  const nodes = [];
8942
- const srcDir = (0, import_node_path10.join)(rootDir, "src");
9277
+ const srcDir = (0, import_node_path9.join)(rootDir, "src");
8943
9278
  if (!(0, import_node_fs10.existsSync)(srcDir)) return { nodes };
8944
9279
  for (const filePath of walkDir(srcDir, [".ts", ".tsx"])) {
8945
9280
  const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
8946
- const relPath = (0, import_node_path10.relative)(rootDir, filePath);
9281
+ const relPath = (0, import_node_path9.relative)(rootDir, filePath);
8947
9282
  const constArrayRe = /export\s+const\s+([A-Z][A-Z_0-9]+)\s*(?::[^=]+)?\s*=\s*\[/g;
8948
9283
  let cm;
8949
9284
  while ((cm = constArrayRe.exec(content)) !== null) {
@@ -8976,7 +9311,7 @@ function extractConstants(rootDir) {
8976
9311
  return { nodes };
8977
9312
  }
8978
9313
  function detect4(rootDir) {
8979
- 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"));
9314
+ return (0, import_node_fs10.existsSync)((0, import_node_path9.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs10.existsSync)((0, import_node_path9.join)(rootDir, "prisma", "seed.ts"));
8980
9315
  }
8981
9316
  function generate4(rootDir) {
8982
9317
  const enumResult = extractEnumValues(rootDir);
@@ -9052,7 +9387,7 @@ var staticValuesParser = {
9052
9387
 
9053
9388
  // src/server/graph/parsers/crosslayer/static-ref-scanner.ts
9054
9389
  var import_node_fs11 = require("node:fs");
9055
- var import_node_path11 = require("node:path");
9390
+ var import_node_path10 = require("node:path");
9056
9391
  init_config();
9057
9392
  var MIN_VALUE_LENGTH = 4;
9058
9393
  var SKIP_VALUES = /* @__PURE__ */ new Set([
@@ -9196,11 +9531,11 @@ var staticRefScannerParser = {
9196
9531
  if (!paths) return { cross_refs: [], flagged_edges: [], warnings: [] };
9197
9532
  const srcDir = paths.srcDir;
9198
9533
  const files = [
9199
- ...walkWithIgnore((0, import_node_path11.join)(srcDir, "client"), [".ts", ".tsx"]),
9534
+ ...walkWithIgnore((0, import_node_path10.join)(srcDir, "client"), [".ts", ".tsx"]),
9200
9535
  ...walkWithIgnore(paths.appDir, [".ts", ".tsx"]),
9201
- ...walkWithIgnore((0, import_node_path11.join)(srcDir, "server"), [".ts", ".tsx"]),
9202
- ...walkWithIgnore((0, import_node_path11.join)(srcDir, "lib"), [".ts", ".tsx"]),
9203
- ...walkWithIgnore((0, import_node_path11.join)(srcDir, "config"), [".ts", ".tsx"])
9536
+ ...walkWithIgnore((0, import_node_path10.join)(srcDir, "server"), [".ts", ".tsx"]),
9537
+ ...walkWithIgnore((0, import_node_path10.join)(srcDir, "lib"), [".ts", ".tsx"]),
9538
+ ...walkWithIgnore((0, import_node_path10.join)(srcDir, "config"), [".ts", ".tsx"])
9204
9539
  ];
9205
9540
  const uiOutput = layerOutputs.get("ui");
9206
9541
  const apiOutput = layerOutputs.get("api");
@@ -9218,7 +9553,7 @@ var staticRefScannerParser = {
9218
9553
  const seen = /* @__PURE__ */ new Set();
9219
9554
  let filesScanned = 0;
9220
9555
  for (const absPath of files) {
9221
- const sourceId = (0, import_node_path11.relative)(srcDir, absPath).replace(/\\/g, "/");
9556
+ const sourceId = (0, import_node_path10.relative)(srcDir, absPath).replace(/\\/g, "/");
9222
9557
  const sourceLayer = uiNodeIds.has(sourceId) ? "ui" : apiNodeIds.has(sourceId) ? "api" : null;
9223
9558
  if (!sourceLayer) continue;
9224
9559
  const content = (0, import_node_fs11.readFileSync)(absPath, "utf-8");
@@ -9337,7 +9672,7 @@ function registerBuiltins(registry, disabled) {
9337
9672
  function loadCustomParsers(registry, config, rootDir, disabled) {
9338
9673
  for (const entry of config.parsers?.custom ?? []) {
9339
9674
  try {
9340
- const absPath = (0, import_node_path12.resolve)(rootDir, entry.path);
9675
+ const absPath = (0, import_node_path11.resolve)(rootDir, entry.path);
9341
9676
  const mod = require(absPath);
9342
9677
  const parser = "default" in mod ? mod.default : mod;
9343
9678
  if (disabled.has(parser.id)) continue;
@@ -9467,7 +9802,7 @@ function applyCrossLayerResults(uiOutput, results) {
9467
9802
 
9468
9803
  // src/server/graph/core/graph-builder.ts
9469
9804
  function readGraphFromDisk(rootDir, layer) {
9470
- const filePath = (0, import_node_path13.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
9805
+ const filePath = (0, import_node_path12.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
9471
9806
  if (!(0, import_node_fs12.existsSync)(filePath)) return null;
9472
9807
  try {
9473
9808
  return JSON.parse((0, import_node_fs12.readFileSync)(filePath, "utf-8"));
@@ -9571,11 +9906,11 @@ function generateAll(rootDir) {
9571
9906
  init_config();
9572
9907
 
9573
9908
  // src/server/graph/core/tagger-registry.ts
9574
- var import_node_path15 = require("node:path");
9909
+ var import_node_path14 = require("node:path");
9575
9910
 
9576
9911
  // src/server/graph/taggers/module-tagger.ts
9577
9912
  var import_node_fs13 = require("node:fs");
9578
- var import_node_path14 = require("node:path");
9913
+ var import_node_path13 = require("node:path");
9579
9914
  function matchGlob(pattern, id) {
9580
9915
  const patParts = pattern.split("/");
9581
9916
  const idParts = id.split("/");
@@ -9608,13 +9943,13 @@ function detectConventionDirs(rootDir, extraConventionDirs = []) {
9608
9943
  const conventionDirs = [...CONVENTION_DIRS_BUILTIN, ...extraConventionDirs];
9609
9944
  const searchDirs = [
9610
9945
  rootDir,
9611
- (0, import_node_path14.join)(rootDir, "src"),
9612
- (0, import_node_path14.join)(rootDir, "app"),
9613
- (0, import_node_path14.join)(rootDir, "lib")
9946
+ (0, import_node_path13.join)(rootDir, "src"),
9947
+ (0, import_node_path13.join)(rootDir, "app"),
9948
+ (0, import_node_path13.join)(rootDir, "lib")
9614
9949
  ];
9615
9950
  for (const base of searchDirs) {
9616
9951
  for (const convention of conventionDirs) {
9617
- const dir = (0, import_node_path14.join)(base, convention);
9952
+ const dir = (0, import_node_path13.join)(base, convention);
9618
9953
  if (!(0, import_node_fs13.existsSync)(dir)) continue;
9619
9954
  try {
9620
9955
  const stat = (0, import_node_fs13.statSync)(dir);
@@ -9913,7 +10248,7 @@ function loadCustomTaggers(registry, config, rootDir, disabled) {
9913
10248
  for (const entry of config.taggers?.custom ?? []) {
9914
10249
  if (disabled.has(entry.id)) continue;
9915
10250
  try {
9916
- const absPath = (0, import_node_path15.resolve)(rootDir, entry.path);
10251
+ const absPath = (0, import_node_path14.resolve)(rootDir, entry.path);
9917
10252
  const mod = require(absPath);
9918
10253
  const tagger = "default" in mod ? mod.default : mod;
9919
10254
  const override = config.taggers?.trackUntagged?.[tagger.id];
@@ -9937,12 +10272,12 @@ function createTaggerRegistry(config, rootDir) {
9937
10272
 
9938
10273
  // src/server/graph/core/tag-store.ts
9939
10274
  var import_node_fs14 = require("node:fs");
9940
- var import_node_path16 = require("node:path");
10275
+ var import_node_path15 = require("node:path");
9941
10276
  var TAGS_FILENAME = "tags.json";
9942
10277
  var GRAPHS_DIR = ".launchsecure/graphs";
9943
10278
  var tagCache = /* @__PURE__ */ new Map();
9944
10279
  function tagsFilePath(rootDir) {
9945
- return (0, import_node_path16.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
10280
+ return (0, import_node_path15.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
9946
10281
  }
9947
10282
  function readTagStore(rootDir) {
9948
10283
  const filePath = tagsFilePath(rootDir);
@@ -9963,7 +10298,7 @@ function readTagStore(rootDir) {
9963
10298
  }
9964
10299
  function writeTagStore(rootDir, store) {
9965
10300
  const filePath = tagsFilePath(rootDir);
9966
- const dir = (0, import_node_path16.dirname)(filePath);
10301
+ const dir = (0, import_node_path15.dirname)(filePath);
9967
10302
  (0, import_node_fs14.mkdirSync)(dir, { recursive: true });
9968
10303
  const cleaned = {};
9969
10304
  for (const [nodeId, tags] of Object.entries(store)) {
@@ -9994,20 +10329,20 @@ function removeTag(rootDir, nodeId, key) {
9994
10329
  init_ts_extractor();
9995
10330
  var GRAPHS_DIR2 = ".launchsecure/graphs";
9996
10331
  function getAvailableLayers(rootDir) {
9997
- const dir = (0, import_node_path17.join)(rootDir, GRAPHS_DIR2);
10332
+ const dir = (0, import_node_path16.join)(rootDir, GRAPHS_DIR2);
9998
10333
  if (!(0, import_node_fs15.existsSync)(dir)) return [];
9999
10334
  return (0, import_node_fs15.readdirSync)(dir).filter((f) => f.endsWith(".json") && f !== "tags.json").map((f) => f.replace(".json", ""));
10000
10335
  }
10001
10336
  var graphCache = /* @__PURE__ */ new Map();
10002
10337
  var taggedCache = /* @__PURE__ */ new Map();
10003
10338
  function graphsDir(rootDir) {
10004
- return (0, import_node_path17.join)(rootDir, GRAPHS_DIR2);
10339
+ return (0, import_node_path16.join)(rootDir, GRAPHS_DIR2);
10005
10340
  }
10006
10341
  function graphFilePath(rootDir, layer) {
10007
- return (0, import_node_path17.join)(graphsDir(rootDir), `${layer}.json`);
10342
+ return (0, import_node_path16.join)(graphsDir(rootDir), `${layer}.json`);
10008
10343
  }
10009
10344
  function tagsFilePath2(rootDir) {
10010
- return (0, import_node_path17.join)(graphsDir(rootDir), "tags.json");
10345
+ return (0, import_node_path16.join)(graphsDir(rootDir), "tags.json");
10011
10346
  }
10012
10347
  function getMtimeMs(filePath) {
10013
10348
  if (!(0, import_node_fs15.existsSync)(filePath)) return 0;
@@ -10160,7 +10495,7 @@ async function handleGraphCommand(subcommand, args) {
10160
10495
 
10161
10496
  // src/server/graph-mcp.ts
10162
10497
  var import_node_fs19 = require("node:fs");
10163
- var import_node_path21 = require("node:path");
10498
+ var import_node_path20 = require("node:path");
10164
10499
  var import_node_child_process2 = require("node:child_process");
10165
10500
  var import_node_os2 = require("node:os");
10166
10501
 
@@ -10168,15 +10503,15 @@ var import_node_os2 = require("node:os");
10168
10503
  var import_node_child_process = require("node:child_process");
10169
10504
  var import_node_fs16 = require("node:fs");
10170
10505
  var import_node_os = require("node:os");
10171
- var import_node_path18 = require("node:path");
10506
+ var import_node_path17 = require("node:path");
10172
10507
  function lockDir(projectRoot) {
10173
10508
  if (projectRoot) {
10174
- return (0, import_node_path18.join)(projectRoot, ".launchsecure");
10509
+ return (0, import_node_path17.join)(projectRoot, ".launchsecure");
10175
10510
  }
10176
- return (0, import_node_path18.join)((0, import_node_os.homedir)(), ".launchsecure");
10511
+ return (0, import_node_path17.join)((0, import_node_os.homedir)(), ".launchsecure");
10177
10512
  }
10178
10513
  function lockPath(projectRoot) {
10179
- return (0, import_node_path18.join)(lockDir(projectRoot), "launch-chart.lock");
10514
+ return (0, import_node_path17.join)(lockDir(projectRoot), "launch-chart.lock");
10180
10515
  }
10181
10516
  var _activeProjectRoot;
10182
10517
  function readLock(projectRoot) {
@@ -10255,7 +10590,7 @@ init_config();
10255
10590
 
10256
10591
  // src/server/graph/core/language-detection.ts
10257
10592
  var import_node_fs17 = require("node:fs");
10258
- var import_node_path19 = require("node:path");
10593
+ var import_node_path18 = require("node:path");
10259
10594
  var EXTENSION_TO_LANGUAGE = {
10260
10595
  // Web / Frontend
10261
10596
  ".ts": "typescript",
@@ -10378,9 +10713,9 @@ function walkForExtensions(dir, extCounts, depth = 0) {
10378
10713
  if (entry.name.startsWith(".") && entry.isDirectory()) continue;
10379
10714
  if (entry.isDirectory()) {
10380
10715
  if (IGNORE_DIRS.has(entry.name)) continue;
10381
- walkForExtensions((0, import_node_path19.join)(dir, entry.name), extCounts, depth + 1);
10716
+ walkForExtensions((0, import_node_path18.join)(dir, entry.name), extCounts, depth + 1);
10382
10717
  } else {
10383
- const ext = (0, import_node_path19.extname)(entry.name).toLowerCase();
10718
+ const ext = (0, import_node_path18.extname)(entry.name).toLowerCase();
10384
10719
  if (ext && EXTENSION_TO_LANGUAGE[ext]) {
10385
10720
  extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
10386
10721
  }
@@ -10422,9 +10757,9 @@ function detectLanguages(rootDir, supportedLanguages) {
10422
10757
 
10423
10758
  // src/server/graph/core/audit-core.ts
10424
10759
  var import_node_fs18 = require("node:fs");
10425
- var import_node_path20 = require("node:path");
10760
+ var import_node_path19 = require("node:path");
10426
10761
  function readGraphFile(rootDir, layer) {
10427
- const filePath = (0, import_node_path20.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
10762
+ const filePath = (0, import_node_path19.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
10428
10763
  if (!(0, import_node_fs18.existsSync)(filePath)) return null;
10429
10764
  try {
10430
10765
  return JSON.parse((0, import_node_fs18.readFileSync)(filePath, "utf-8"));
@@ -10471,7 +10806,7 @@ function checkUnprotectedRoutes(rootDir) {
10471
10806
  const api = readGraphFile(rootDir, "api");
10472
10807
  const staticGraph = readGraphFile(rootDir, "static");
10473
10808
  if (!api) return buildReport("api", "unprotected_routes", findings);
10474
- const routePermsPath = (0, import_node_path20.join)(rootDir, "src", "config", "route-permissions.ts");
10809
+ const routePermsPath = (0, import_node_path19.join)(rootDir, "src", "config", "route-permissions.ts");
10475
10810
  let routePermsContent = "";
10476
10811
  if ((0, import_node_fs18.existsSync)(routePermsPath)) {
10477
10812
  routePermsContent = (0, import_node_fs18.readFileSync)(routePermsPath, "utf-8");
@@ -10551,7 +10886,7 @@ function checkUnenforcedPermissions(rootDir) {
10551
10886
  const staticGraph = readGraphFile(rootDir, "static");
10552
10887
  if (!staticGraph) return buildReport("static", "unenforced_permissions", findings);
10553
10888
  const permissions = staticGraph.nodes.filter((n) => n.type === "seed_permission").map((n) => ({ id: n.id, key: n.value, name: n.name }));
10554
- const routePermsPath = (0, import_node_path20.join)(rootDir, "src", "config", "route-permissions.ts");
10889
+ const routePermsPath = (0, import_node_path19.join)(rootDir, "src", "config", "route-permissions.ts");
10555
10890
  let routePermsContent = "";
10556
10891
  if ((0, import_node_fs18.existsSync)(routePermsPath)) {
10557
10892
  routePermsContent = (0, import_node_fs18.readFileSync)(routePermsPath, "utf-8");
@@ -10584,7 +10919,7 @@ function checkHardcodedValues(rootDir) {
10584
10919
  const seen = /* @__PURE__ */ new Set();
10585
10920
  for (const node of api.nodes) {
10586
10921
  if (node.type !== "endpoint") continue;
10587
- const filePath = (0, import_node_path20.join)(rootDir, "src", node.id);
10922
+ const filePath = (0, import_node_path19.join)(rootDir, "src", node.id);
10588
10923
  if (!(0, import_node_fs18.existsSync)(filePath)) continue;
10589
10924
  const content = (0, import_node_fs18.readFileSync)(filePath, "utf-8");
10590
10925
  let m;
@@ -11489,11 +11824,11 @@ function handleReadGraph(args) {
11489
11824
  return okJson(result);
11490
11825
  }
11491
11826
  function nodeToFilePath(rootDir, layer, nodeId) {
11492
- if (layer === "ui" || layer === "api") return (0, import_node_path21.join)(rootDir, "src", nodeId);
11493
- if (layer === "db") return (0, import_node_path21.join)(rootDir, "prisma", "schema.prisma");
11494
- const withSrc = (0, import_node_path21.join)(rootDir, "src", nodeId);
11827
+ if (layer === "ui" || layer === "api") return (0, import_node_path20.join)(rootDir, "src", nodeId);
11828
+ if (layer === "db") return (0, import_node_path20.join)(rootDir, "prisma", "schema.prisma");
11829
+ const withSrc = (0, import_node_path20.join)(rootDir, "src", nodeId);
11495
11830
  if ((0, import_node_fs19.existsSync)(withSrc)) return withSrc;
11496
- const direct = (0, import_node_path21.join)(rootDir, nodeId);
11831
+ const direct = (0, import_node_path20.join)(rootDir, nodeId);
11497
11832
  if ((0, import_node_fs19.existsSync)(direct)) return direct;
11498
11833
  return null;
11499
11834
  }
@@ -11706,9 +12041,9 @@ function handleStartChartServer(args) {
11706
12041
  });
11707
12042
  }
11708
12043
  const entryPath = process.argv[1];
11709
- const logDir = (0, import_node_path21.join)((0, import_node_os2.homedir)(), ".launchsecure");
12044
+ const logDir = (0, import_node_path20.join)((0, import_node_os2.homedir)(), ".launchsecure");
11710
12045
  (0, import_node_fs19.mkdirSync)(logDir, { recursive: true });
11711
- const logPath = (0, import_node_path21.join)(logDir, "launch-chart.log");
12046
+ const logPath = (0, import_node_path20.join)(logDir, "launch-chart.log");
11712
12047
  const out = (0, import_node_fs19.openSync)(logPath, "a");
11713
12048
  const err2 = (0, import_node_fs19.openSync)(logPath, "a");
11714
12049
  const portArgs = args.port ? ["--port", String(args.port)] : [];
@@ -11830,18 +12165,18 @@ function handleDetectProjectStack() {
11830
12165
  if (ref.type === "references_api") stats.references_api++;
11831
12166
  }
11832
12167
  }
11833
- const srcDir = (0, import_node_path21.join)(rootDir, "src");
12168
+ const srcDir = (0, import_node_path20.join)(rootDir, "src");
11834
12169
  if ((0, import_node_fs19.existsSync)(srcDir)) {
11835
12170
  const scanDir = (dir) => {
11836
12171
  if (!(0, import_node_fs19.existsSync)(dir)) return;
11837
12172
  for (const entry of (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true })) {
11838
12173
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
11839
- const full = (0, import_node_path21.join)(dir, entry.name);
12174
+ const full = (0, import_node_path20.join)(dir, entry.name);
11840
12175
  if (entry.isDirectory()) {
11841
12176
  scanDir(full);
11842
12177
  continue;
11843
12178
  }
11844
- if (![".ts", ".tsx"].includes((0, import_node_path21.extname)(entry.name))) continue;
12179
+ if (![".ts", ".tsx"].includes((0, import_node_path20.extname)(entry.name))) continue;
11845
12180
  try {
11846
12181
  const content = (0, import_node_fs19.readFileSync)(full, "utf-8");
11847
12182
  const matches = content.match(/@api\s+(GET|POST|PUT|DELETE|PATCH)\s+\/\S+/g);
@@ -12062,7 +12397,7 @@ function parseArgs() {
12062
12397
  return { port, token, serverUrl: LAUNCHSECURE_URL, subcommand };
12063
12398
  }
12064
12399
  function tryListen(server, port, maxRetries = 10) {
12065
- return new Promise((resolve3, reject) => {
12400
+ return new Promise((resolve4, reject) => {
12066
12401
  let attempts = 0;
12067
12402
  function attempt(p) {
12068
12403
  server.once("error", (err2) => {
@@ -12073,7 +12408,7 @@ function tryListen(server, port, maxRetries = 10) {
12073
12408
  reject(err2);
12074
12409
  }
12075
12410
  });
12076
- server.listen(p, () => resolve3(p));
12411
+ server.listen(p, () => resolve4(p));
12077
12412
  }
12078
12413
  attempt(port);
12079
12414
  });
@@ -12094,7 +12429,7 @@ function saveCredentials(creds) {
12094
12429
  });
12095
12430
  }
12096
12431
  function verifyToken(serverUrl, token) {
12097
- return new Promise((resolve3) => {
12432
+ return new Promise((resolve4) => {
12098
12433
  const url = new URL("/api/mcp/verify", serverUrl);
12099
12434
  const body = JSON.stringify({ token });
12100
12435
  const mod = url.protocol === "https:" ? import_https.default : import_http.default;
@@ -12109,30 +12444,30 @@ function verifyToken(serverUrl, token) {
12109
12444
  res.on("data", (chunk) => data += chunk);
12110
12445
  res.on("end", () => {
12111
12446
  try {
12112
- resolve3(JSON.parse(data));
12447
+ resolve4(JSON.parse(data));
12113
12448
  } catch {
12114
- resolve3({ valid: false, error: "Invalid response from server" });
12449
+ resolve4({ valid: false, error: "Invalid response from server" });
12115
12450
  }
12116
12451
  });
12117
12452
  });
12118
12453
  req.on("error", (err2) => {
12119
- resolve3({ valid: false, error: `Cannot reach server: ${err2.message}` });
12454
+ resolve4({ valid: false, error: `Cannot reach server: ${err2.message}` });
12120
12455
  });
12121
12456
  req.setTimeout(1e4, () => {
12122
12457
  req.destroy();
12123
- resolve3({ valid: false, error: "Connection timed out" });
12458
+ resolve4({ valid: false, error: "Connection timed out" });
12124
12459
  });
12125
12460
  req.write(body);
12126
12461
  req.end();
12127
12462
  });
12128
12463
  }
12129
12464
  function httpRequest(reqUrl, options, body, timeout = 3e4) {
12130
- return new Promise((resolve3, reject) => {
12465
+ return new Promise((resolve4, reject) => {
12131
12466
  const mod = reqUrl.protocol === "https:" ? import_https.default : import_http.default;
12132
12467
  const r = mod.request(reqUrl, options, (resp) => {
12133
12468
  let data = "";
12134
12469
  resp.on("data", (chunk) => data += chunk);
12135
- resp.on("end", () => resolve3({ status: resp.statusCode || 0, headers: resp.headers, body: data }));
12470
+ resp.on("end", () => resolve4({ status: resp.statusCode || 0, headers: resp.headers, body: data }));
12136
12471
  });
12137
12472
  r.on("error", reject);
12138
12473
  r.setTimeout(timeout, () => {