@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
@@ -155,48 +155,15 @@ var init_config = __esm({
155
155
  }
156
156
  });
157
157
 
158
- // src/server/graph/core/resolve-paths.ts
159
- function detectDbDir(rootDir, config) {
160
- if (config.paths?.dbDir) return (0, import_node_path3.join)(rootDir, config.paths.dbDir);
161
- const prismaDir = (0, import_node_path3.join)(rootDir, "prisma");
162
- if ((0, import_node_fs3.existsSync)(prismaDir)) return prismaDir;
163
- return null;
164
- }
165
- function resolveProjectPaths(rootDir, config) {
166
- const dbDir = detectDbDir(rootDir, config);
167
- if (config.paths?.appDir) {
168
- const appDir = (0, import_node_path3.join)(rootDir, config.paths.appDir);
169
- const srcDir = config.paths.srcDir ? (0, import_node_path3.join)(rootDir, config.paths.srcDir) : (0, import_node_path3.dirname)(appDir);
170
- return { srcDir, appDir, apiDir: (0, import_node_path3.join)(appDir, "api"), dbDir };
171
- }
172
- const srcApp = (0, import_node_path3.join)(rootDir, "src", "app");
173
- if ((0, import_node_fs3.existsSync)(srcApp)) {
174
- return { srcDir: (0, import_node_path3.join)(rootDir, "src"), appDir: srcApp, apiDir: (0, import_node_path3.join)(srcApp, "api"), dbDir };
175
- }
176
- const rootApp = (0, import_node_path3.join)(rootDir, "app");
177
- if ((0, import_node_fs3.existsSync)(rootApp)) {
178
- return { srcDir: rootDir, appDir: rootApp, apiDir: (0, import_node_path3.join)(rootApp, "api"), dbDir };
179
- }
180
- return null;
181
- }
182
- var import_node_fs3, import_node_path3;
183
- var init_resolve_paths = __esm({
184
- "src/server/graph/core/resolve-paths.ts"() {
185
- "use strict";
186
- import_node_fs3 = require("node:fs");
187
- import_node_path3 = require("node:path");
188
- }
189
- });
190
-
191
158
  // src/server/graph/core/walk.ts
192
159
  function walk(dir, exts) {
193
160
  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);
161
+ if (!(0, import_node_fs3.existsSync)(dir)) return results;
162
+ for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
163
+ const full = (0, import_node_path3.join)(dir, entry.name);
197
164
  if (entry.isDirectory()) {
198
165
  results.push(...walk(full, exts));
199
- } else if (exts.includes((0, import_node_path4.extname)(entry.name))) {
166
+ } else if (exts.includes((0, import_node_path3.extname)(entry.name))) {
200
167
  results.push(full);
201
168
  }
202
169
  }
@@ -204,24 +171,24 @@ function walk(dir, exts) {
204
171
  }
205
172
  function walkWithIgnore(dir, exts, opts = {}) {
206
173
  const results = [];
207
- if (!(0, import_node_fs4.existsSync)(dir)) return results;
174
+ if (!(0, import_node_fs3.existsSync)(dir)) return results;
208
175
  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 })) {
176
+ for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
210
177
  if (entry.isDirectory()) {
211
178
  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));
179
+ results.push(...walkWithIgnore((0, import_node_path3.join)(dir, entry.name), exts, opts));
180
+ } else if (exts.includes((0, import_node_path3.extname)(entry.name))) {
181
+ results.push((0, import_node_path3.join)(dir, entry.name));
215
182
  }
216
183
  }
217
184
  return results;
218
185
  }
219
- var import_node_fs4, import_node_path4, DEFAULT_IGNORE_DIRS;
186
+ var import_node_fs3, import_node_path3, DEFAULT_IGNORE_DIRS;
220
187
  var init_walk = __esm({
221
188
  "src/server/graph/core/walk.ts"() {
222
189
  "use strict";
223
- import_node_fs4 = require("node:fs");
224
- import_node_path4 = require("node:path");
190
+ import_node_fs3 = require("node:fs");
191
+ import_node_path3 = require("node:path");
225
192
  DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
226
193
  "node_modules",
227
194
  ".git",
@@ -238,6 +205,201 @@ var init_walk = __esm({
238
205
  }
239
206
  });
240
207
 
208
+ // src/server/graph/core/resolve-paths.ts
209
+ function hasSqlFiles(dir) {
210
+ if (!(0, import_node_fs4.existsSync)(dir)) return false;
211
+ try {
212
+ return (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true }).some(
213
+ (e) => e.isFile() && e.name.endsWith(".sql")
214
+ );
215
+ } catch {
216
+ return false;
217
+ }
218
+ }
219
+ function hasNestedMigrationSql(dir) {
220
+ if (!(0, import_node_fs4.existsSync)(dir)) return false;
221
+ try {
222
+ return (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true }).some(
223
+ (e) => e.isDirectory() && (0, import_node_fs4.existsSync)((0, import_node_path4.join)(dir, e.name, "migration.sql"))
224
+ );
225
+ } catch {
226
+ return false;
227
+ }
228
+ }
229
+ function resolveDbFromDir(dir) {
230
+ if (!(0, import_node_fs4.existsSync)(dir)) return { kind: "none", schemaPath: null, migrationsDir: null };
231
+ const schemaPath = (0, import_node_path4.join)(dir, "schema.prisma");
232
+ if ((0, import_node_fs4.existsSync)(schemaPath)) {
233
+ const migrationsDir2 = (0, import_node_path4.join)(dir, "migrations");
234
+ return {
235
+ kind: "prisma",
236
+ schemaPath,
237
+ migrationsDir: (0, import_node_fs4.existsSync)(migrationsDir2) ? migrationsDir2 : null
238
+ };
239
+ }
240
+ const migrationsDir = (0, import_node_path4.join)(dir, "migrations");
241
+ if (hasSqlFiles(migrationsDir) || hasNestedMigrationSql(migrationsDir)) {
242
+ return { kind: "sql-migrations", migrationsDir, schemaPath: null };
243
+ }
244
+ if (hasSqlFiles(dir) || hasNestedMigrationSql(dir)) {
245
+ return { kind: "sql-migrations", migrationsDir: dir, schemaPath: null };
246
+ }
247
+ return { kind: "none", schemaPath: null, migrationsDir: null };
248
+ }
249
+ function detectDbConfig(rootDir, config) {
250
+ if (config.paths?.dbDir) {
251
+ return resolveDbFromDir((0, import_node_path4.join)(rootDir, config.paths.dbDir));
252
+ }
253
+ const candidates = ["prisma", "supabase", "drizzle", (0, import_node_path4.join)("db", "migrations"), "migrations"];
254
+ for (const c of candidates) {
255
+ const dir = (0, import_node_path4.join)(rootDir, c);
256
+ const resolved = resolveDbFromDir(dir);
257
+ if (resolved.kind !== "none") return resolved;
258
+ }
259
+ return { kind: "none", schemaPath: null, migrationsDir: null };
260
+ }
261
+ function detectDbDir(rootDir, config, dbConfig) {
262
+ if (config.paths?.dbDir) return (0, import_node_path4.join)(rootDir, config.paths.dbDir);
263
+ if (dbConfig.kind === "prisma") return (0, import_node_path4.dirname)(dbConfig.schemaPath);
264
+ if (dbConfig.kind === "sql-migrations") return dbConfig.migrationsDir;
265
+ return null;
266
+ }
267
+ function dirHasTSFiles(dir) {
268
+ if (!(0, import_node_fs4.existsSync)(dir)) return false;
269
+ try {
270
+ const stack = [dir];
271
+ while (stack.length > 0) {
272
+ const cur = stack.pop();
273
+ const entries = (0, import_node_fs4.readdirSync)(cur, { withFileTypes: true });
274
+ for (const e of entries) {
275
+ if (e.isFile() && (e.name.endsWith(".ts") || e.name.endsWith(".tsx"))) return true;
276
+ if (e.isDirectory() && !e.name.startsWith(".") && !DEFAULT_IGNORE_DIRS.has(e.name)) {
277
+ stack.push((0, import_node_path4.join)(cur, e.name));
278
+ }
279
+ }
280
+ }
281
+ } catch {
282
+ }
283
+ return false;
284
+ }
285
+ function collectCodeBearingChildren(dir, extraSkip) {
286
+ if (!(0, import_node_fs4.existsSync)(dir)) return [];
287
+ const out = [];
288
+ try {
289
+ for (const entry of (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true })) {
290
+ if (!entry.isDirectory()) continue;
291
+ if (entry.name.startsWith(".")) continue;
292
+ if (NON_SOURCE_DIRS.has(entry.name)) continue;
293
+ if (extraSkip?.has(entry.name)) continue;
294
+ const full = (0, import_node_path4.join)(dir, entry.name);
295
+ if (dirHasTSFiles(full)) out.push(full);
296
+ }
297
+ } catch {
298
+ }
299
+ return out;
300
+ }
301
+ function detectSrcRoots(rootDir, srcDir, appDir, config) {
302
+ if (config.paths?.srcRoots && config.paths.srcRoots.length > 0) {
303
+ const roots2 = /* @__PURE__ */ new Set();
304
+ roots2.add(appDir);
305
+ for (const r of config.paths.srcRoots) {
306
+ const abs = (0, import_node_path4.isAbsolute)(r) ? r : (0, import_node_path4.resolve)(rootDir, r);
307
+ roots2.add(abs);
308
+ }
309
+ return [...roots2];
310
+ }
311
+ const roots = /* @__PURE__ */ new Set();
312
+ roots.add(appDir);
313
+ for (const c of collectCodeBearingChildren(srcDir)) roots.add(c);
314
+ if (srcDir !== rootDir) {
315
+ const skipSrcWrapper = /* @__PURE__ */ new Set([(0, import_node_path4.basename)(srcDir)]);
316
+ for (const c of collectCodeBearingChildren(rootDir, skipSrcWrapper)) roots.add(c);
317
+ }
318
+ return [...roots];
319
+ }
320
+ function detectConventionFiles(rootDir, srcDir) {
321
+ const out = [];
322
+ const seen = /* @__PURE__ */ new Set();
323
+ const dirs = srcDir === rootDir ? [rootDir] : [srcDir, rootDir];
324
+ for (const dir of dirs) {
325
+ for (const name of CONVENTION_NAMES) {
326
+ const full = (0, import_node_path4.join)(dir, name);
327
+ if (!seen.has(full) && (0, import_node_fs4.existsSync)(full)) {
328
+ try {
329
+ if ((0, import_node_fs4.statSync)(full).isFile()) {
330
+ seen.add(full);
331
+ out.push(full);
332
+ }
333
+ } catch {
334
+ }
335
+ }
336
+ }
337
+ }
338
+ return out;
339
+ }
340
+ function resolveProjectPaths(rootDir, config) {
341
+ let srcDir;
342
+ let appDir;
343
+ if (config.paths?.appDir) {
344
+ appDir = (0, import_node_path4.join)(rootDir, config.paths.appDir);
345
+ srcDir = config.paths.srcDir ? (0, import_node_path4.join)(rootDir, config.paths.srcDir) : (0, import_node_path4.dirname)(appDir);
346
+ } else {
347
+ const srcApp = (0, import_node_path4.join)(rootDir, "src", "app");
348
+ const rootApp = (0, import_node_path4.join)(rootDir, "app");
349
+ if ((0, import_node_fs4.existsSync)(srcApp)) {
350
+ srcDir = (0, import_node_path4.join)(rootDir, "src");
351
+ appDir = srcApp;
352
+ } else if ((0, import_node_fs4.existsSync)(rootApp)) {
353
+ srcDir = rootDir;
354
+ appDir = rootApp;
355
+ } else {
356
+ return null;
357
+ }
358
+ }
359
+ const apiDir = (0, import_node_path4.join)(appDir, "api");
360
+ const dbConfig = detectDbConfig(rootDir, config);
361
+ const dbDir = detectDbDir(rootDir, config, dbConfig);
362
+ const srcRoots = detectSrcRoots(rootDir, srcDir, appDir, config);
363
+ const conventionFiles = detectConventionFiles(rootDir, srcDir);
364
+ return { srcDir, appDir, apiDir, dbDir, srcRoots, conventionFiles, dbConfig };
365
+ }
366
+ var import_node_fs4, import_node_path4, NON_SOURCE_DIRS, CONVENTION_NAMES;
367
+ var init_resolve_paths = __esm({
368
+ "src/server/graph/core/resolve-paths.ts"() {
369
+ "use strict";
370
+ import_node_fs4 = require("node:fs");
371
+ import_node_path4 = require("node:path");
372
+ init_walk();
373
+ NON_SOURCE_DIRS = /* @__PURE__ */ new Set([
374
+ ...DEFAULT_IGNORE_DIRS,
375
+ // DB conventions (handled by db parsers)
376
+ "prisma",
377
+ "supabase",
378
+ "drizzle",
379
+ "migrations",
380
+ // Web assets
381
+ "public",
382
+ "static",
383
+ "assets",
384
+ // Docs
385
+ "docs",
386
+ "documentation",
387
+ // Test dirs (project tests aren't part of the structural graph)
388
+ "tests",
389
+ "__tests__",
390
+ "e2e",
391
+ "playwright",
392
+ "cypress",
393
+ // Monorepo workspace roots — separate graph projects per .launchchart.json
394
+ "packages",
395
+ "apps",
396
+ "services",
397
+ "libs"
398
+ ]);
399
+ CONVENTION_NAMES = ["middleware.ts", "middleware.tsx", "instrumentation.ts", "instrumentation.tsx"];
400
+ }
401
+ });
402
+
241
403
  // src/server/graph/core/ts-extractor.ts
242
404
  var ts_extractor_exports = {};
243
405
  __export(ts_extractor_exports, {
@@ -778,8 +940,12 @@ var init_ts_extractor = __esm({
778
940
  });
779
941
 
780
942
  // src/server/graph/parsers/ts/typescript-project.ts
781
- function toNodeId(srcDir, absPath) {
782
- return (0, import_node_path6.relative)(srcDir, absPath).replace(/\\/g, "/");
943
+ function toNodeId(srcDir, rootDir, absPath) {
944
+ const relFromSrc = (0, import_node_path6.relative)(srcDir, absPath).replace(/\\/g, "/");
945
+ if (relFromSrc.startsWith("..")) {
946
+ return (0, import_node_path6.relative)(rootDir, absPath).replace(/\\/g, "/");
947
+ }
948
+ return relFromSrc;
783
949
  }
784
950
  function resolveImport(srcDir, specifier) {
785
951
  if (!specifier.startsWith("@/")) return null;
@@ -869,12 +1035,13 @@ function extractRoute(id) {
869
1035
  function nameFromFilename(absPath) {
870
1036
  return (0, import_node_path6.basename)(absPath, (0, import_node_path6.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
871
1037
  }
872
- function filePathToApiRoute(apiDir, absPath) {
873
- let route = "/" + (0, import_node_path6.relative)(apiDir, absPath).replace(/\\/g, "/").replace(/\/route\.tsx?$/, "");
1038
+ function filePathToAppRoute(appDir, absPath) {
1039
+ let route = ("/" + (0, import_node_path6.relative)(appDir, absPath).replace(/\\/g, "/")).replace(/\/route\.tsx?$/, "");
1040
+ route = route.replace(/\/\([^)]+\)/g, "");
1041
+ route = route.replace(/\[\.\.\.([^\]]+)\]/g, "*$1");
874
1042
  route = route.replace(/\[([^\]]+)\]/g, ":$1");
875
1043
  route = route.replace(/\/+/g, "/");
876
- if (route === "/") return "/api";
877
- return "/api" + route;
1044
+ return route === "" ? "/" : route;
878
1045
  }
879
1046
  function camelToPascal(s) {
880
1047
  if (!s) return s;
@@ -959,7 +1126,7 @@ function matchRouteToPage(route, routeToNodeId) {
959
1126
  if (routeToNodeId.has(normalized)) return routeToNodeId.get(normalized);
960
1127
  return null;
961
1128
  }
962
- function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
1129
+ function extractEdges(srcDir, rootDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
963
1130
  const edges = [];
964
1131
  const flagged = [];
965
1132
  const seen = /* @__PURE__ */ new Set();
@@ -987,7 +1154,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
987
1154
  for (const name of names) {
988
1155
  const targetAbs = barrelMap.get(name);
989
1156
  if (targetAbs) {
990
- const targetId = toNodeId(srcDir, targetAbs);
1157
+ const targetId = toNodeId(srcDir, rootDir, targetAbs);
991
1158
  if (nodeIdSet.has(targetId)) {
992
1159
  if (!byTarget.has(targetId)) byTarget.set(targetId, []);
993
1160
  byTarget.get(targetId).push(name);
@@ -1001,7 +1168,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
1001
1168
  } else {
1002
1169
  const resolved = resolveImport(srcDir, specifier);
1003
1170
  if (resolved) {
1004
- const targetId = toNodeId(srcDir, resolved);
1171
+ const targetId = toNodeId(srcDir, rootDir, resolved);
1005
1172
  if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
1006
1173
  addEdge(targetId, edgeTypeFor(isTypeOnly, names));
1007
1174
  }
@@ -1010,7 +1177,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
1010
1177
  } else if (specifier.startsWith(".")) {
1011
1178
  const resolved = resolveRelativeImport(absPath, specifier);
1012
1179
  if (resolved) {
1013
- const targetId = toNodeId(srcDir, resolved);
1180
+ const targetId = toNodeId(srcDir, rootDir, resolved);
1014
1181
  if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
1015
1182
  addEdge(targetId, edgeTypeFor(isTypeOnly, names));
1016
1183
  }
@@ -1062,13 +1229,22 @@ function generate(rootDir) {
1062
1229
  const config = loadConfig(rootDir);
1063
1230
  const paths = resolveProjectPaths(rootDir, config);
1064
1231
  const srcDir = paths.srcDir;
1065
- const apiDir = paths.apiDir;
1066
- const appFiles = walk(paths.appDir, [".tsx", ".ts"]);
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"]);
1071
- const allDiscovered = [...appFiles, ...clientFiles, ...serverFiles, ...libFiles, ...configFiles];
1232
+ const allDiscovered = [];
1233
+ const discoveredSet = /* @__PURE__ */ new Set();
1234
+ for (const root of paths.srcRoots) {
1235
+ for (const f of walk(root, [".tsx", ".ts"])) {
1236
+ if (!discoveredSet.has(f)) {
1237
+ discoveredSet.add(f);
1238
+ allDiscovered.push(f);
1239
+ }
1240
+ }
1241
+ }
1242
+ for (const conv of paths.conventionFiles) {
1243
+ if (!discoveredSet.has(conv)) {
1244
+ discoveredSet.add(conv);
1245
+ allDiscovered.push(conv);
1246
+ }
1247
+ }
1072
1248
  const parsedByPath = /* @__PURE__ */ new Map();
1073
1249
  for (const absPath of allDiscovered) {
1074
1250
  parsedByPath.set(absPath, parseFileTS(absPath));
@@ -1080,7 +1256,7 @@ function generate(rootDir) {
1080
1256
  const routeToNodeId = /* @__PURE__ */ new Map();
1081
1257
  const fileSet = allDiscovered.filter((f) => !(0, import_node_path6.basename)(f).startsWith("index."));
1082
1258
  for (const absPath of fileSet) {
1083
- const id = toNodeId(srcDir, absPath);
1259
+ const id = toNodeId(srcDir, rootDir, absPath);
1084
1260
  const type = classifyType(absPath, id);
1085
1261
  if (type === "test" || type === "story") continue;
1086
1262
  const parsed = parsedByPath.get(absPath);
@@ -1095,7 +1271,7 @@ function generate(rootDir) {
1095
1271
  const dbCalls = extractDbCallsTS(absPath);
1096
1272
  const authWrappers = extractAuthWrappersTS(absPath);
1097
1273
  const deep = extractDeep(absPath);
1098
- const routePath = (0, import_node_fs6.existsSync)(apiDir) ? filePathToApiRoute(apiDir, absPath) : `/api/${id.replace(/\/route\.tsx?$/, "")}`;
1274
+ const routePath = filePathToAppRoute(paths.appDir, absPath);
1099
1275
  const mutations = dbCalls.filter((c) => c.isMutation);
1100
1276
  const mutates = mutations.length > 0;
1101
1277
  const authStrategy = [...authWrappers];
@@ -1139,11 +1315,12 @@ function generate(rootDir) {
1139
1315
  const uiEdges = [];
1140
1316
  const uiFlagged = [];
1141
1317
  for (const absPath of fileSet) {
1142
- const id = toNodeId(srcDir, absPath);
1318
+ const id = toNodeId(srcDir, rootDir, absPath);
1143
1319
  if (!nodeIdSet.has(id)) continue;
1144
1320
  const parsed = parsedByPath.get(absPath);
1145
1321
  const { edges, flagged } = extractEdges(
1146
1322
  srcDir,
1323
+ rootDir,
1147
1324
  absPath,
1148
1325
  id,
1149
1326
  parsed,
@@ -1156,7 +1333,7 @@ function generate(rootDir) {
1156
1333
  }
1157
1334
  const fetchCallEntries = [];
1158
1335
  for (const absPath of fileSet) {
1159
- const sourceId = toNodeId(srcDir, absPath);
1336
+ const sourceId = toNodeId(srcDir, rootDir, absPath);
1160
1337
  if (!nodeIdSet.has(sourceId)) continue;
1161
1338
  const parsed = parsedByPath.get(absPath);
1162
1339
  if (parsed.fetchCalls.length === 0) continue;
@@ -1195,7 +1372,7 @@ function generate(rootDir) {
1195
1372
  for (const name of names) {
1196
1373
  const targetAbs = barrelMap.get(name);
1197
1374
  if (!targetAbs) continue;
1198
- const targetId2 = toNodeId(srcDir, targetAbs);
1375
+ const targetId2 = toNodeId(srcDir, rootDir, targetAbs);
1199
1376
  if (!nodeIdSet.has(targetId2)) continue;
1200
1377
  const key2 = `${externalId}\u2192${targetId2}`;
1201
1378
  if (seen.has(key2)) continue;
@@ -1209,7 +1386,7 @@ function generate(rootDir) {
1209
1386
  resolved = resolveRelativeImport(absPath, specifier);
1210
1387
  }
1211
1388
  if (!resolved) continue;
1212
- const targetId = toNodeId(srcDir, resolved);
1389
+ const targetId = toNodeId(srcDir, rootDir, resolved);
1213
1390
  if (!nodeIdSet.has(targetId)) continue;
1214
1391
  if (targetId.endsWith("/index.ts") || targetId.endsWith("/index.tsx")) continue;
1215
1392
  const key = `${externalId}\u2192${targetId}`;
@@ -1502,10 +1679,24 @@ function parseEnums(content) {
1502
1679
  return nodes;
1503
1680
  }
1504
1681
  function detect2(rootDir) {
1505
- return (0, import_node_fs7.existsSync)((0, import_node_path7.join)(rootDir, "prisma", "schema.prisma"));
1682
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
1683
+ return paths?.dbConfig.kind === "prisma" && (0, import_node_fs7.existsSync)(paths.dbConfig.schemaPath);
1506
1684
  }
1507
1685
  function generate2(rootDir) {
1508
- const schemaPath = (0, import_node_path7.join)(rootDir, "prisma", "schema.prisma");
1686
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
1687
+ if (paths.dbConfig.kind !== "prisma") {
1688
+ return {
1689
+ metadata: { generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), layer: "db", source: "none" },
1690
+ nodes: [],
1691
+ edges: [],
1692
+ cross_refs: [],
1693
+ contradictions: [],
1694
+ warnings: [],
1695
+ flagged_edges: [],
1696
+ patterns: { total_tables: 0, total_enums: 0, total_relations: 0 }
1697
+ };
1698
+ }
1699
+ const schemaPath = paths.dbConfig.schemaPath;
1509
1700
  const content = (0, import_node_fs7.readFileSync)(schemaPath, "utf-8");
1510
1701
  const { nodes: modelNodes, relations } = parseModels(content);
1511
1702
  const enumNodes = parseEnums(content);
@@ -1526,7 +1717,7 @@ function generate2(rootDir) {
1526
1717
  metadata: {
1527
1718
  generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
1528
1719
  scope: "prisma-schema",
1529
- source: "prisma/schema.prisma",
1720
+ source: schemaPath,
1530
1721
  provider: "postgresql",
1531
1722
  layer: "db",
1532
1723
  total_models: modelNodes.length,
@@ -1555,12 +1746,13 @@ function generate2(rootDir) {
1555
1746
  }
1556
1747
  };
1557
1748
  }
1558
- var import_node_fs7, import_node_path7, prismaSchemaParser;
1749
+ var import_node_fs7, prismaSchemaParser;
1559
1750
  var init_prisma_schema = __esm({
1560
1751
  "src/server/graph/parsers/db/prisma-schema.ts"() {
1561
1752
  "use strict";
1562
1753
  import_node_fs7 = require("node:fs");
1563
- import_node_path7 = require("node:path");
1754
+ init_config();
1755
+ init_resolve_paths();
1564
1756
  prismaSchemaParser = {
1565
1757
  id: "prisma-schema",
1566
1758
  layer: "db",
@@ -1575,51 +1767,147 @@ function pgTypeToPrisma(pgType) {
1575
1767
  const upper = pgType.toUpperCase().trim();
1576
1768
  return PG_TO_PRISMA[upper] ?? upper;
1577
1769
  }
1770
+ function bareName(captured) {
1771
+ const parts = captured.split(".");
1772
+ const last = parts[parts.length - 1];
1773
+ return last.replace(/^"(.*)"$/, "$1").trim();
1774
+ }
1578
1775
  function parseCreateTable(sql, state) {
1579
- const re = /CREATE\s+TABLE\s+"(\w+)"\s*\(([\s\S]*?)\);/gi;
1776
+ const re = new RegExp(
1777
+ `CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
1778
+ "gi"
1779
+ );
1580
1780
  let m;
1581
1781
  while ((m = re.exec(sql)) !== null) {
1582
- const tableName = m[1];
1782
+ const tableName = bareName(m[1]);
1583
1783
  const body = m[2];
1584
1784
  const columns = /* @__PURE__ */ new Map();
1585
1785
  let primaryCol = null;
1586
- for (const line of body.split("\n")) {
1587
- const trimmed = line.trim().replace(/,\s*$/, "");
1786
+ const inlineFks = [];
1787
+ const lines = splitTopLevelCommas(body);
1788
+ for (const raw of lines) {
1789
+ const trimmed = raw.trim().replace(/,\s*$/, "");
1588
1790
  if (!trimmed || trimmed.startsWith("--")) continue;
1589
- const pkMatch = trimmed.match(/CONSTRAINT\s+"[^"]+"\s+PRIMARY\s+KEY\s*\("(\w+)"\)/i);
1590
- if (pkMatch) {
1591
- primaryCol = pkMatch[1];
1791
+ const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
1792
+ if (namedPk) {
1793
+ primaryCol = bareName(namedPk[1]);
1794
+ continue;
1795
+ }
1796
+ const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
1797
+ if (tablePk) {
1798
+ primaryCol = bareName(tablePk[1]);
1799
+ continue;
1800
+ }
1801
+ if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
1802
+ const namedFk = trimmed.match(new RegExp(
1803
+ `^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+)?))?`,
1804
+ "i"
1805
+ ));
1806
+ if (namedFk) {
1807
+ inlineFks.push({
1808
+ constraintName: bareName(namedFk[1]),
1809
+ sourceTable: tableName,
1810
+ sourceColumn: bareName(namedFk[2]),
1811
+ targetTable: bareName(namedFk[3]),
1812
+ targetColumn: bareName(namedFk[4]),
1813
+ onDelete: namedFk[5] ?? null
1814
+ });
1592
1815
  continue;
1593
1816
  }
1594
- if (/^\s*CONSTRAINT\s/i.test(trimmed)) continue;
1595
- const colMatch = trimmed.match(/^"(\w+)"\s+(.+)/);
1817
+ const bareFk = trimmed.match(new RegExp(
1818
+ `^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1819
+ "i"
1820
+ ));
1821
+ if (bareFk) {
1822
+ inlineFks.push({
1823
+ constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
1824
+ sourceTable: tableName,
1825
+ sourceColumn: bareName(bareFk[1]),
1826
+ targetTable: bareName(bareFk[2]),
1827
+ targetColumn: bareName(bareFk[3]),
1828
+ onDelete: bareFk[4] ?? null
1829
+ });
1830
+ continue;
1831
+ }
1832
+ if (/^CONSTRAINT\s/i.test(trimmed)) continue;
1833
+ const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
1596
1834
  if (!colMatch) continue;
1597
- const colName = colMatch[1];
1835
+ const colName = bareName(colMatch[1]);
1598
1836
  let rest = colMatch[2];
1837
+ const inlineRefMatch = rest.match(new RegExp(
1838
+ `\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1839
+ "i"
1840
+ ));
1841
+ if (inlineRefMatch) {
1842
+ inlineFks.push({
1843
+ constraintName: `${tableName}_${colName}_fkey`,
1844
+ sourceTable: tableName,
1845
+ sourceColumn: colName,
1846
+ targetTable: bareName(inlineRefMatch[1]),
1847
+ targetColumn: bareName(inlineRefMatch[2]),
1848
+ onDelete: inlineRefMatch[3] ?? null
1849
+ });
1850
+ rest = rest.replace(inlineRefMatch[0], "").trim();
1851
+ }
1599
1852
  const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
1853
+ const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
1854
+ const isUnique = /\bUNIQUE\b/i.test(rest);
1600
1855
  const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
1601
1856
  const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
1602
- let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
1857
+ 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();
1603
1858
  columns.set(colName, {
1604
1859
  name: colName,
1605
1860
  type: colType,
1606
- nullable: !isNotNull,
1607
- primary: false,
1608
- unique: false,
1861
+ nullable: !isNotNull && !isPrimaryKey,
1862
+ primary: isPrimaryKey,
1863
+ unique: isUnique,
1609
1864
  default: defaultVal
1610
1865
  });
1866
+ if (isPrimaryKey) primaryCol = colName;
1611
1867
  }
1612
1868
  if (primaryCol && columns.has(primaryCol)) {
1613
1869
  columns.get(primaryCol).primary = true;
1614
1870
  }
1615
1871
  state.tables.set(tableName, { name: tableName, columns });
1872
+ state.fks.push(...inlineFks);
1616
1873
  }
1617
1874
  }
1875
+ function splitTopLevelCommas(body) {
1876
+ const out = [];
1877
+ let depth = 0;
1878
+ let buf = "";
1879
+ let inString = null;
1880
+ for (const ch of body) {
1881
+ if (inString) {
1882
+ buf += ch;
1883
+ if (ch === inString) inString = null;
1884
+ continue;
1885
+ }
1886
+ if (ch === "'" || ch === '"') {
1887
+ inString = ch;
1888
+ buf += ch;
1889
+ continue;
1890
+ }
1891
+ if (ch === "(") depth++;
1892
+ else if (ch === ")") depth--;
1893
+ if (ch === "," && depth === 0) {
1894
+ out.push(buf);
1895
+ buf = "";
1896
+ continue;
1897
+ }
1898
+ buf += ch;
1899
+ }
1900
+ if (buf.trim()) out.push(buf);
1901
+ return out;
1902
+ }
1618
1903
  function parseCreateEnum(sql, state) {
1619
- const re = /CREATE\s+TYPE\s+"(\w+)"\s+AS\s+ENUM\s*\(([^)]+)\)/gi;
1904
+ const re = new RegExp(
1905
+ `CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
1906
+ "gi"
1907
+ );
1620
1908
  let m;
1621
1909
  while ((m = re.exec(sql)) !== null) {
1622
- const enumName = m[1];
1910
+ const enumName = bareName(m[1]);
1623
1911
  const valuesStr = m[2];
1624
1912
  const values = new Set(
1625
1913
  valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
@@ -1628,11 +1916,14 @@ function parseCreateEnum(sql, state) {
1628
1916
  }
1629
1917
  }
1630
1918
  function parseAlterTable(sql, state) {
1631
- const addColRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+COLUMN\s+"(\w+)"\s+(.+?);/gi;
1919
+ const addColRe = new RegExp(
1920
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
1921
+ "gi"
1922
+ );
1632
1923
  let m;
1633
1924
  while ((m = addColRe.exec(sql)) !== null) {
1634
- const tableName = m[1];
1635
- const colName = m[2];
1925
+ const tableName = bareName(m[1]);
1926
+ const colName = bareName(m[2]);
1636
1927
  let rest = m[3];
1637
1928
  const table = state.tables.get(tableName);
1638
1929
  if (!table) continue;
@@ -1649,63 +1940,91 @@ function parseAlterTable(sql, state) {
1649
1940
  default: defaultVal
1650
1941
  });
1651
1942
  }
1652
- const dropColRe = /ALTER\s+TABLE\s+"(\w+)"\s+DROP\s+COLUMN\s+"(\w+)"/gi;
1943
+ const dropColRe = new RegExp(
1944
+ `ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
1945
+ "gi"
1946
+ );
1653
1947
  while ((m = dropColRe.exec(sql)) !== null) {
1654
- const table = state.tables.get(m[1]);
1655
- if (table) table.columns.delete(m[2]);
1948
+ const table = state.tables.get(bareName(m[1]));
1949
+ if (table) table.columns.delete(bareName(m[2]));
1656
1950
  }
1657
- 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;
1951
+ const fkRe = new RegExp(
1952
+ `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+)?))?`,
1953
+ "gi"
1954
+ );
1658
1955
  while ((m = fkRe.exec(sql)) !== null) {
1659
1956
  state.fks.push({
1660
- constraintName: m[2],
1661
- sourceTable: m[1],
1662
- sourceColumn: m[3],
1663
- targetTable: m[4],
1664
- targetColumn: m[5],
1957
+ constraintName: bareName(m[2]),
1958
+ sourceTable: bareName(m[1]),
1959
+ sourceColumn: bareName(m[3]),
1960
+ targetTable: bareName(m[4]),
1961
+ targetColumn: bareName(m[5]),
1665
1962
  onDelete: m[6] ?? null
1666
1963
  });
1667
1964
  }
1668
1965
  }
1669
1966
  function parseAlterEnum(sql, state) {
1670
- const re = /ALTER\s+TYPE\s+"(\w+)"\s+ADD\s+VALUE\s+'([^']+)'/gi;
1967
+ const re = new RegExp(
1968
+ `ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
1969
+ "gi"
1970
+ );
1671
1971
  let m;
1672
1972
  while ((m = re.exec(sql)) !== null) {
1673
- const en = state.enums.get(m[1]);
1973
+ const en = state.enums.get(bareName(m[1]));
1674
1974
  if (en) en.values.add(m[2]);
1675
1975
  }
1676
1976
  }
1677
1977
  function parseDropTable(sql, state) {
1678
- const re = /DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?"(\w+)"/gi;
1978
+ const re = new RegExp(
1979
+ `DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
1980
+ "gi"
1981
+ );
1679
1982
  let m;
1680
1983
  while ((m = re.exec(sql)) !== null) {
1681
- state.tables.delete(m[1]);
1682
- state.fks = state.fks.filter((fk) => fk.sourceTable !== m[1] && fk.targetTable !== m[1]);
1984
+ const dropped = bareName(m[1]);
1985
+ state.tables.delete(dropped);
1986
+ state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
1683
1987
  }
1684
1988
  }
1685
1989
  function parseUniqueIndex(sql, state) {
1686
- const re = /CREATE\s+UNIQUE\s+INDEX\s+"[^"]+"\s+ON\s+"(\w+)"\("(\w+)"\)/gi;
1990
+ const re = new RegExp(
1991
+ `CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
1992
+ "gi"
1993
+ );
1687
1994
  let m;
1688
1995
  while ((m = re.exec(sql)) !== null) {
1689
- const table = state.tables.get(m[1]);
1690
- const col = table?.columns.get(m[2]);
1996
+ const tableName = bareName(m[1]);
1997
+ const colName = bareName(m[2]);
1998
+ const table = state.tables.get(tableName);
1999
+ const col = table?.columns.get(colName);
1691
2000
  if (col) col.unique = true;
1692
- if (!state.uniqueIndexes.has(m[1])) state.uniqueIndexes.set(m[1], /* @__PURE__ */ new Set());
1693
- state.uniqueIndexes.get(m[1]).add(m[2]);
2001
+ if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
2002
+ state.uniqueIndexes.get(tableName).add(colName);
1694
2003
  }
1695
2004
  }
1696
- function parseMigrations(rootDir) {
1697
- const migrationsDir = (0, import_node_path8.join)(rootDir, "prisma", "migrations");
2005
+ function discoverMigrationFiles(migrationsDir) {
2006
+ if (!(0, import_node_fs8.existsSync)(migrationsDir)) return [];
2007
+ const out = [];
2008
+ const entries = (0, import_node_fs8.readdirSync)(migrationsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
2009
+ for (const entry of entries) {
2010
+ if (entry.isDirectory()) {
2011
+ const sqlPath = (0, import_node_path7.join)(migrationsDir, entry.name, "migration.sql");
2012
+ if ((0, import_node_fs8.existsSync)(sqlPath)) out.push(sqlPath);
2013
+ } else if (entry.isFile() && entry.name.endsWith(".sql")) {
2014
+ out.push((0, import_node_path7.join)(migrationsDir, entry.name));
2015
+ }
2016
+ }
2017
+ return out;
2018
+ }
2019
+ function parseMigrations(migrationsDir) {
1698
2020
  const state = {
1699
2021
  tables: /* @__PURE__ */ new Map(),
1700
2022
  enums: /* @__PURE__ */ new Map(),
1701
2023
  fks: [],
1702
2024
  uniqueIndexes: /* @__PURE__ */ new Map()
1703
2025
  };
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();
1706
- for (const dir of dirs) {
1707
- const sqlPath = (0, import_node_path8.join)(migrationsDir, dir, "migration.sql");
1708
- if (!(0, import_node_fs8.existsSync)(sqlPath)) continue;
2026
+ if (!migrationsDir) return state;
2027
+ for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
1709
2028
  const sql = (0, import_node_fs8.readFileSync)(sqlPath, "utf-8");
1710
2029
  parseCreateEnum(sql, state);
1711
2030
  parseCreateTable(sql, state);
@@ -1716,9 +2035,8 @@ function parseMigrations(rootDir) {
1716
2035
  }
1717
2036
  return state;
1718
2037
  }
1719
- function loadPrismaState(rootDir) {
1720
- const schemaPath = (0, import_node_path8.join)(rootDir, "prisma", "schema.prisma");
1721
- if (!(0, import_node_fs8.existsSync)(schemaPath)) return null;
2038
+ function loadPrismaState(schemaPath) {
2039
+ if (!schemaPath || !(0, import_node_fs8.existsSync)(schemaPath)) return null;
1722
2040
  const content = (0, import_node_fs8.readFileSync)(schemaPath, "utf-8");
1723
2041
  const tables = /* @__PURE__ */ new Map();
1724
2042
  const enums = /* @__PURE__ */ new Map();
@@ -1883,14 +2201,28 @@ function verify(sqlState, prisma) {
1883
2201
  }
1884
2202
  return { contradictions, flaggedEdges };
1885
2203
  }
2204
+ function migrationsDirFor(rootDir) {
2205
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
2206
+ if (!paths) return null;
2207
+ if (paths.dbConfig.kind === "prisma" || paths.dbConfig.kind === "sql-migrations") {
2208
+ return paths.dbConfig.migrationsDir;
2209
+ }
2210
+ return null;
2211
+ }
2212
+ function schemaPathFor(rootDir) {
2213
+ const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
2214
+ if (!paths) return null;
2215
+ return paths.dbConfig.kind === "prisma" ? paths.dbConfig.schemaPath : null;
2216
+ }
1886
2217
  function detect3(rootDir) {
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")));
2218
+ const dir = migrationsDirFor(rootDir);
2219
+ if (!dir) return false;
2220
+ return discoverMigrationFiles(dir).length > 0;
1890
2221
  }
1891
2222
  function generate3(rootDir) {
1892
- const sqlState = parseMigrations(rootDir);
1893
- const prisma = loadPrismaState(rootDir);
2223
+ const migrationsDir = migrationsDirFor(rootDir);
2224
+ const sqlState = parseMigrations(migrationsDir);
2225
+ const prisma = loadPrismaState(schemaPathFor(rootDir));
1894
2226
  const prismaTableIds = prisma ? new Set(prisma.tables.keys()) : /* @__PURE__ */ new Set();
1895
2227
  const prismaEnumIds = prisma ? new Set(prisma.enums.keys()) : /* @__PURE__ */ new Set();
1896
2228
  const nodes = [];
@@ -1936,7 +2268,7 @@ function generate3(rootDir) {
1936
2268
  metadata: {
1937
2269
  generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
1938
2270
  scope: "sql-migrations",
1939
- source: "prisma/migrations/",
2271
+ source: migrationsDir ?? "none",
1940
2272
  layer: "db",
1941
2273
  sql_tables: sqlState.tables.size,
1942
2274
  sql_enums: sqlState.enums.size,
@@ -1953,12 +2285,14 @@ function generate3(rootDir) {
1953
2285
  flagged_edges: flaggedEdges
1954
2286
  };
1955
2287
  }
1956
- var import_node_fs8, import_node_path8, PG_TO_PRISMA, sqlMigrationsParser;
2288
+ var import_node_fs8, import_node_path7, PG_TO_PRISMA, ID, QID, sqlMigrationsParser;
1957
2289
  var init_sql_migrations = __esm({
1958
2290
  "src/server/graph/parsers/db/sql-migrations.ts"() {
1959
2291
  "use strict";
1960
2292
  import_node_fs8 = require("node:fs");
1961
- import_node_path8 = require("node:path");
2293
+ import_node_path7 = require("node:path");
2294
+ init_config();
2295
+ init_resolve_paths();
1962
2296
  PG_TO_PRISMA = {
1963
2297
  "TEXT": "String",
1964
2298
  "VARCHAR": "String",
@@ -1985,6 +2319,8 @@ var init_sql_migrations = __esm({
1985
2319
  "UUID": "String",
1986
2320
  "TEXT[]": "String[]"
1987
2321
  };
2322
+ ID = `(?:"[\\w$]+"|[\\w$]+)`;
2323
+ QID = `(?:${ID}\\.)?${ID}`;
1988
2324
  sqlMigrationsParser = {
1989
2325
  id: "sql-migrations",
1990
2326
  layer: "db",
@@ -2225,24 +2561,24 @@ function walk2(dir, exts) {
2225
2561
  const results = [];
2226
2562
  for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
2227
2563
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
2228
- const full = (0, import_node_path9.join)(dir, entry.name);
2564
+ const full = (0, import_node_path8.join)(dir, entry.name);
2229
2565
  if (entry.isDirectory()) {
2230
2566
  results.push(...walk2(full, exts));
2231
- } else if (exts.includes((0, import_node_path9.extname)(entry.name))) {
2567
+ } else if (exts.includes((0, import_node_path8.extname)(entry.name))) {
2232
2568
  results.push(full);
2233
2569
  }
2234
2570
  }
2235
2571
  return results;
2236
2572
  }
2237
2573
  function toNodeId2(srcDir, absPath) {
2238
- return (0, import_node_path9.relative)(srcDir, absPath).replace(/\\/g, "/");
2574
+ return (0, import_node_path8.relative)(srcDir, absPath).replace(/\\/g, "/");
2239
2575
  }
2240
- var import_node_fs9, import_node_path9, API_ANNOTATION_RE, apiAnnotationsParser;
2576
+ var import_node_fs9, import_node_path8, API_ANNOTATION_RE, apiAnnotationsParser;
2241
2577
  var init_api_annotations = __esm({
2242
2578
  "src/server/graph/parsers/crosslayer/api-annotations.ts"() {
2243
2579
  "use strict";
2244
2580
  import_node_fs9 = require("node:fs");
2245
- import_node_path9 = require("node:path");
2581
+ import_node_path8 = require("node:path");
2246
2582
  init_api_route_matching();
2247
2583
  API_ANNOTATION_RE = /@api\s+(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/\S+)/g;
2248
2584
  apiAnnotationsParser = {
@@ -2250,7 +2586,7 @@ var init_api_annotations = __esm({
2250
2586
  layer: "crosslayer",
2251
2587
  concern: "api-binding",
2252
2588
  detect(rootDir) {
2253
- return (0, import_node_fs9.existsSync)((0, import_node_path9.join)(rootDir, "src"));
2589
+ return (0, import_node_fs9.existsSync)((0, import_node_path8.join)(rootDir, "src"));
2254
2590
  },
2255
2591
  generate(rootDir, layerOutputs) {
2256
2592
  const apiOutput = layerOutputs.get("api");
@@ -2261,7 +2597,7 @@ var init_api_annotations = __esm({
2261
2597
  const uiNodeIds = new Set(uiOutput?.nodes.map((n) => n.id) ?? []);
2262
2598
  const apiRoutes = loadApiRoutesFromOutput(apiOutput);
2263
2599
  const apiPathMap = buildApiPathMap(apiRoutes);
2264
- const srcDir = (0, import_node_path9.join)(rootDir, "src");
2600
+ const srcDir = (0, import_node_path8.join)(rootDir, "src");
2265
2601
  const files = walk2(srcDir, [".ts", ".tsx"]);
2266
2602
  const crossRefs = [];
2267
2603
  const flaggedEdges = [];
@@ -2318,24 +2654,24 @@ function walk3(dir, exts) {
2318
2654
  const results = [];
2319
2655
  for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true })) {
2320
2656
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
2321
- const full = (0, import_node_path10.join)(dir, entry.name);
2657
+ const full = (0, import_node_path9.join)(dir, entry.name);
2322
2658
  if (entry.isDirectory()) {
2323
2659
  results.push(...walk3(full, exts));
2324
- } else if (exts.includes((0, import_node_path10.extname)(entry.name))) {
2660
+ } else if (exts.includes((0, import_node_path9.extname)(entry.name))) {
2325
2661
  results.push(full);
2326
2662
  }
2327
2663
  }
2328
2664
  return results;
2329
2665
  }
2330
2666
  function toNodeId3(srcDir, absPath) {
2331
- return (0, import_node_path10.relative)(srcDir, absPath).replace(/\\/g, "/");
2667
+ return (0, import_node_path9.relative)(srcDir, absPath).replace(/\\/g, "/");
2332
2668
  }
2333
- var import_node_fs10, import_node_path10, URL_LITERAL_RE, urlLiteralScannerParser;
2669
+ var import_node_fs10, import_node_path9, URL_LITERAL_RE, urlLiteralScannerParser;
2334
2670
  var init_url_literal_scanner = __esm({
2335
2671
  "src/server/graph/parsers/crosslayer/url-literal-scanner.ts"() {
2336
2672
  "use strict";
2337
2673
  import_node_fs10 = require("node:fs");
2338
- import_node_path10 = require("node:path");
2674
+ import_node_path9 = require("node:path");
2339
2675
  init_api_route_matching();
2340
2676
  init_config();
2341
2677
  init_resolve_paths();
@@ -2359,7 +2695,7 @@ var init_url_literal_scanner = __esm({
2359
2695
  const apiPathMap = buildApiPathMap(apiRoutes);
2360
2696
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
2361
2697
  const srcDir = paths.srcDir;
2362
- const clientDir = (0, import_node_path10.join)(srcDir, "client");
2698
+ const clientDir = (0, import_node_path9.join)(srcDir, "client");
2363
2699
  const files = [
2364
2700
  ...walk3(clientDir, [".ts", ".tsx"]),
2365
2701
  ...walk3(paths.appDir, [".ts", ".tsx"])
@@ -2431,8 +2767,8 @@ function extractEnumValues(rootDir) {
2431
2767
  const nodes = [];
2432
2768
  const edges = [];
2433
2769
  const schemaPaths = [
2434
- (0, import_node_path11.join)(rootDir, "prisma", "schema.prisma"),
2435
- (0, import_node_path11.join)(rootDir, "prisma", "schema")
2770
+ (0, import_node_path10.join)(rootDir, "prisma", "schema.prisma"),
2771
+ (0, import_node_path10.join)(rootDir, "prisma", "schema")
2436
2772
  ];
2437
2773
  let content = "";
2438
2774
  for (const p of schemaPaths) {
@@ -2443,7 +2779,7 @@ function extractEnumValues(rootDir) {
2443
2779
  content = (0, import_node_fs11.readFileSync)(p, "utf-8");
2444
2780
  } else if (stat.isDirectory()) {
2445
2781
  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");
2782
+ content = files.map((f) => (0, import_node_fs11.readFileSync)((0, import_node_path10.join)(p, f), "utf-8")).join("\n");
2447
2783
  }
2448
2784
  } catch {
2449
2785
  continue;
@@ -2599,14 +2935,14 @@ function extractSeedData(rootDir) {
2599
2935
  const nodes = [];
2600
2936
  const edges = [];
2601
2937
  const seedFiles = [
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")
2938
+ (0, import_node_path10.join)(rootDir, "prisma", "seed.ts"),
2939
+ (0, import_node_path10.join)(rootDir, "prisma", "seed.js"),
2940
+ (0, import_node_path10.join)(rootDir, "src", "server", "lib", "system-tags.ts")
2605
2941
  ].filter(import_node_fs11.existsSync);
2606
2942
  const useTreeSitter = tryLoadTreeSitter();
2607
2943
  for (const filePath of seedFiles) {
2608
2944
  const content = (0, import_node_fs11.readFileSync)(filePath, "utf-8");
2609
- const relPath = (0, import_node_path11.relative)(rootDir, filePath);
2945
+ const relPath = (0, import_node_path10.relative)(rootDir, filePath);
2610
2946
  const seeded = detectSeededArrays(content, relPath);
2611
2947
  let astRoot = null;
2612
2948
  if (useTreeSitter && parseCode) {
@@ -2704,7 +3040,7 @@ function walkDir(dir, exts) {
2704
3040
  const results = [];
2705
3041
  for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
2706
3042
  if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
2707
- const full = (0, import_node_path11.join)(dir, entry.name);
3043
+ const full = (0, import_node_path10.join)(dir, entry.name);
2708
3044
  if (entry.isDirectory()) results.push(...walkDir(full, exts));
2709
3045
  else if (exts.some((ext) => entry.name.endsWith(ext))) results.push(full);
2710
3046
  }
@@ -2712,11 +3048,11 @@ function walkDir(dir, exts) {
2712
3048
  }
2713
3049
  function extractConstants(rootDir) {
2714
3050
  const nodes = [];
2715
- const srcDir = (0, import_node_path11.join)(rootDir, "src");
3051
+ const srcDir = (0, import_node_path10.join)(rootDir, "src");
2716
3052
  if (!(0, import_node_fs11.existsSync)(srcDir)) return { nodes };
2717
3053
  for (const filePath of walkDir(srcDir, [".ts", ".tsx"])) {
2718
3054
  const content = (0, import_node_fs11.readFileSync)(filePath, "utf-8");
2719
- const relPath = (0, import_node_path11.relative)(rootDir, filePath);
3055
+ const relPath = (0, import_node_path10.relative)(rootDir, filePath);
2720
3056
  const constArrayRe = /export\s+const\s+([A-Z][A-Z_0-9]+)\s*(?::[^=]+)?\s*=\s*\[/g;
2721
3057
  let cm;
2722
3058
  while ((cm = constArrayRe.exec(content)) !== null) {
@@ -2749,7 +3085,7 @@ function extractConstants(rootDir) {
2749
3085
  return { nodes };
2750
3086
  }
2751
3087
  function detect4(rootDir) {
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"));
3088
+ return (0, import_node_fs11.existsSync)((0, import_node_path10.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs11.existsSync)((0, import_node_path10.join)(rootDir, "prisma", "seed.ts"));
2753
3089
  }
2754
3090
  function generate4(rootDir) {
2755
3091
  const enumResult = extractEnumValues(rootDir);
@@ -2816,12 +3152,12 @@ function generate4(rootDir) {
2816
3152
  }
2817
3153
  };
2818
3154
  }
2819
- var import_node_fs11, import_node_path11, parseCode, SHARED_MODELS, DB_MODELS, staticValuesParser;
3155
+ var import_node_fs11, import_node_path10, parseCode, SHARED_MODELS, DB_MODELS, staticValuesParser;
2820
3156
  var init_static_values = __esm({
2821
3157
  "src/server/graph/parsers/static/static-values.ts"() {
2822
3158
  "use strict";
2823
3159
  import_node_fs11 = require("node:fs");
2824
- import_node_path11 = require("node:path");
3160
+ import_node_path10 = require("node:path");
2825
3161
  parseCode = null;
2826
3162
  SHARED_MODELS = /* @__PURE__ */ new Set(["permission", "role", "tag"]);
2827
3163
  DB_MODELS = /* @__PURE__ */ new Set(["subscriptionPlan", "providerDefinition", "pipelineMasterTemplate"]);
@@ -2919,12 +3255,12 @@ function collectStaticRefsRegex(content, valueLookup, allValues) {
2919
3255
  }
2920
3256
  return refs;
2921
3257
  }
2922
- var import_node_fs12, import_node_path12, MIN_VALUE_LENGTH, SKIP_VALUES, staticRefScannerParser;
3258
+ var import_node_fs12, import_node_path11, MIN_VALUE_LENGTH, SKIP_VALUES, staticRefScannerParser;
2923
3259
  var init_static_ref_scanner = __esm({
2924
3260
  "src/server/graph/parsers/crosslayer/static-ref-scanner.ts"() {
2925
3261
  "use strict";
2926
3262
  import_node_fs12 = require("node:fs");
2927
- import_node_path12 = require("node:path");
3263
+ import_node_path11 = require("node:path");
2928
3264
  init_config();
2929
3265
  init_resolve_paths();
2930
3266
  init_walk();
@@ -2986,11 +3322,11 @@ var init_static_ref_scanner = __esm({
2986
3322
  if (!paths) return { cross_refs: [], flagged_edges: [], warnings: [] };
2987
3323
  const srcDir = paths.srcDir;
2988
3324
  const files = [
2989
- ...walkWithIgnore((0, import_node_path12.join)(srcDir, "client"), [".ts", ".tsx"]),
3325
+ ...walkWithIgnore((0, import_node_path11.join)(srcDir, "client"), [".ts", ".tsx"]),
2990
3326
  ...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"])
3327
+ ...walkWithIgnore((0, import_node_path11.join)(srcDir, "server"), [".ts", ".tsx"]),
3328
+ ...walkWithIgnore((0, import_node_path11.join)(srcDir, "lib"), [".ts", ".tsx"]),
3329
+ ...walkWithIgnore((0, import_node_path11.join)(srcDir, "config"), [".ts", ".tsx"])
2994
3330
  ];
2995
3331
  const uiOutput = layerOutputs.get("ui");
2996
3332
  const apiOutput = layerOutputs.get("api");
@@ -3008,7 +3344,7 @@ var init_static_ref_scanner = __esm({
3008
3344
  const seen = /* @__PURE__ */ new Set();
3009
3345
  let filesScanned = 0;
3010
3346
  for (const absPath of files) {
3011
- const sourceId = (0, import_node_path12.relative)(srcDir, absPath).replace(/\\/g, "/");
3347
+ const sourceId = (0, import_node_path11.relative)(srcDir, absPath).replace(/\\/g, "/");
3012
3348
  const sourceLayer = uiNodeIds.has(sourceId) ? "ui" : apiNodeIds.has(sourceId) ? "api" : null;
3013
3349
  if (!sourceLayer) continue;
3014
3350
  const content = (0, import_node_fs12.readFileSync)(absPath, "utf-8");
@@ -3077,7 +3413,7 @@ function registerBuiltins(registry, disabled) {
3077
3413
  function loadCustomParsers(registry, config, rootDir, disabled) {
3078
3414
  for (const entry of config.parsers?.custom ?? []) {
3079
3415
  try {
3080
- const absPath = (0, import_node_path13.resolve)(rootDir, entry.path);
3416
+ const absPath = (0, import_node_path12.resolve)(rootDir, entry.path);
3081
3417
  const mod = require(absPath);
3082
3418
  const parser = "default" in mod ? mod.default : mod;
3083
3419
  if (disabled.has(parser.id)) continue;
@@ -3104,11 +3440,11 @@ function createRegistry(config, rootDir) {
3104
3440
  loadCustomParsers(registry, config, rootDir, disabled);
3105
3441
  return registry;
3106
3442
  }
3107
- var import_node_path13, ParserRegistry;
3443
+ var import_node_path12, ParserRegistry;
3108
3444
  var init_parser_registry = __esm({
3109
3445
  "src/server/graph/core/parser-registry.ts"() {
3110
3446
  "use strict";
3111
- import_node_path13 = require("node:path");
3447
+ import_node_path12 = require("node:path");
3112
3448
  init_typescript_project();
3113
3449
  init_prisma_schema();
3114
3450
  init_sql_migrations();
@@ -3279,7 +3615,7 @@ var init_merge = __esm({
3279
3615
 
3280
3616
  // src/server/graph/core/graph-builder.ts
3281
3617
  function readGraphFromDisk(rootDir, layer) {
3282
- const filePath = (0, import_node_path14.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
3618
+ const filePath = (0, import_node_path13.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
3283
3619
  if (!(0, import_node_fs13.existsSync)(filePath)) return null;
3284
3620
  try {
3285
3621
  return JSON.parse((0, import_node_fs13.readFileSync)(filePath, "utf-8"));
@@ -3378,12 +3714,12 @@ function generateAll(rootDir) {
3378
3714
  const extras = [...byLayer.keys()].filter((l) => !wellKnownOrder.includes(l)).sort();
3379
3715
  return [...wellKnownOrder, ...extras].map((l) => byLayer.get(l)).filter((r) => !!r);
3380
3716
  }
3381
- var import_node_fs13, import_node_path14;
3717
+ var import_node_fs13, import_node_path13;
3382
3718
  var init_graph_builder = __esm({
3383
3719
  "src/server/graph/core/graph-builder.ts"() {
3384
3720
  "use strict";
3385
3721
  import_node_fs13 = require("node:fs");
3386
- import_node_path14 = require("node:path");
3722
+ import_node_path13 = require("node:path");
3387
3723
  init_config();
3388
3724
  init_parser_registry();
3389
3725
  init_merge();
@@ -3422,13 +3758,13 @@ function detectConventionDirs(rootDir, extraConventionDirs = []) {
3422
3758
  const conventionDirs = [...CONVENTION_DIRS_BUILTIN, ...extraConventionDirs];
3423
3759
  const searchDirs = [
3424
3760
  rootDir,
3425
- (0, import_node_path15.join)(rootDir, "src"),
3426
- (0, import_node_path15.join)(rootDir, "app"),
3427
- (0, import_node_path15.join)(rootDir, "lib")
3761
+ (0, import_node_path14.join)(rootDir, "src"),
3762
+ (0, import_node_path14.join)(rootDir, "app"),
3763
+ (0, import_node_path14.join)(rootDir, "lib")
3428
3764
  ];
3429
3765
  for (const base of searchDirs) {
3430
3766
  for (const convention of conventionDirs) {
3431
- const dir = (0, import_node_path15.join)(base, convention);
3767
+ const dir = (0, import_node_path14.join)(base, convention);
3432
3768
  if (!(0, import_node_fs14.existsSync)(dir)) continue;
3433
3769
  try {
3434
3770
  const stat = (0, import_node_fs14.statSync)(dir);
@@ -3505,12 +3841,12 @@ function extractModuleFromPath(id, extraTrivial, extraSkipSegments) {
3505
3841
  }
3506
3842
  return "root";
3507
3843
  }
3508
- var import_node_fs14, import_node_path15, CONVENTION_DIRS_BUILTIN, GENERIC_ROLE_NAMES_BUILTIN, SKIP_SEGMENTS_BUILTIN, TRIVIAL_GROUPS, cachedRootDir, cachedConventionDirs, moduleTagger;
3844
+ var import_node_fs14, import_node_path14, CONVENTION_DIRS_BUILTIN, GENERIC_ROLE_NAMES_BUILTIN, SKIP_SEGMENTS_BUILTIN, TRIVIAL_GROUPS, cachedRootDir, cachedConventionDirs, moduleTagger;
3509
3845
  var init_module_tagger = __esm({
3510
3846
  "src/server/graph/taggers/module-tagger.ts"() {
3511
3847
  "use strict";
3512
3848
  import_node_fs14 = require("node:fs");
3513
- import_node_path15 = require("node:path");
3849
+ import_node_path14 = require("node:path");
3514
3850
  CONVENTION_DIRS_BUILTIN = ["features", "modules", "domains", "areas"];
3515
3851
  GENERIC_ROLE_NAMES_BUILTIN = /* @__PURE__ */ new Set([
3516
3852
  // JS/TS
@@ -3722,7 +4058,7 @@ function loadCustomTaggers(registry, config, rootDir, disabled) {
3722
4058
  for (const entry of config.taggers?.custom ?? []) {
3723
4059
  if (disabled.has(entry.id)) continue;
3724
4060
  try {
3725
- const absPath = (0, import_node_path16.resolve)(rootDir, entry.path);
4061
+ const absPath = (0, import_node_path15.resolve)(rootDir, entry.path);
3726
4062
  const mod = require(absPath);
3727
4063
  const tagger = "default" in mod ? mod.default : mod;
3728
4064
  const override = config.taggers?.trackUntagged?.[tagger.id];
@@ -3743,11 +4079,11 @@ function createTaggerRegistry(config, rootDir) {
3743
4079
  loadCustomTaggers(registry, config, rootDir, disabled);
3744
4080
  return registry;
3745
4081
  }
3746
- var import_node_path16, TaggerRegistry, BUILTIN_TAGGERS;
4082
+ var import_node_path15, TaggerRegistry, BUILTIN_TAGGERS;
3747
4083
  var init_tagger_registry = __esm({
3748
4084
  "src/server/graph/core/tagger-registry.ts"() {
3749
4085
  "use strict";
3750
- import_node_path16 = require("node:path");
4086
+ import_node_path15 = require("node:path");
3751
4087
  init_module_tagger();
3752
4088
  init_screen_tagger();
3753
4089
  TaggerRegistry = class {
@@ -3775,7 +4111,7 @@ var init_tagger_registry = __esm({
3775
4111
 
3776
4112
  // src/server/graph/core/tag-store.ts
3777
4113
  function tagsFilePath(rootDir) {
3778
- return (0, import_node_path17.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
4114
+ return (0, import_node_path16.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
3779
4115
  }
3780
4116
  function readTagStore(rootDir) {
3781
4117
  const filePath = tagsFilePath(rootDir);
@@ -3796,7 +4132,7 @@ function readTagStore(rootDir) {
3796
4132
  }
3797
4133
  function writeTagStore(rootDir, store) {
3798
4134
  const filePath = tagsFilePath(rootDir);
3799
- const dir = (0, import_node_path17.dirname)(filePath);
4135
+ const dir = (0, import_node_path16.dirname)(filePath);
3800
4136
  (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
3801
4137
  const cleaned = {};
3802
4138
  for (const [nodeId, tags] of Object.entries(store)) {
@@ -3822,12 +4158,12 @@ function removeTag(rootDir, nodeId, key) {
3822
4158
  }
3823
4159
  writeTagStore(rootDir, store);
3824
4160
  }
3825
- var import_node_fs15, import_node_path17, TAGS_FILENAME, GRAPHS_DIR, tagCache;
4161
+ var import_node_fs15, import_node_path16, TAGS_FILENAME, GRAPHS_DIR, tagCache;
3826
4162
  var init_tag_store = __esm({
3827
4163
  "src/server/graph/core/tag-store.ts"() {
3828
4164
  "use strict";
3829
4165
  import_node_fs15 = require("node:fs");
3830
- import_node_path17 = require("node:path");
4166
+ import_node_path16 = require("node:path");
3831
4167
  TAGS_FILENAME = "tags.json";
3832
4168
  GRAPHS_DIR = ".launchsecure/graphs";
3833
4169
  tagCache = /* @__PURE__ */ new Map();
@@ -3836,18 +4172,18 @@ var init_tag_store = __esm({
3836
4172
 
3837
4173
  // src/server/graph/index.ts
3838
4174
  function getAvailableLayers(rootDir) {
3839
- const dir = (0, import_node_path18.join)(rootDir, GRAPHS_DIR2);
4175
+ const dir = (0, import_node_path17.join)(rootDir, GRAPHS_DIR2);
3840
4176
  if (!(0, import_node_fs16.existsSync)(dir)) return [];
3841
4177
  return (0, import_node_fs16.readdirSync)(dir).filter((f) => f.endsWith(".json") && f !== "tags.json").map((f) => f.replace(".json", ""));
3842
4178
  }
3843
4179
  function graphsDir(rootDir) {
3844
- return (0, import_node_path18.join)(rootDir, GRAPHS_DIR2);
4180
+ return (0, import_node_path17.join)(rootDir, GRAPHS_DIR2);
3845
4181
  }
3846
4182
  function graphFilePath(rootDir, layer) {
3847
- return (0, import_node_path18.join)(graphsDir(rootDir), `${layer}.json`);
4183
+ return (0, import_node_path17.join)(graphsDir(rootDir), `${layer}.json`);
3848
4184
  }
3849
4185
  function tagsFilePath2(rootDir) {
3850
- return (0, import_node_path18.join)(graphsDir(rootDir), "tags.json");
4186
+ return (0, import_node_path17.join)(graphsDir(rootDir), "tags.json");
3851
4187
  }
3852
4188
  function getMtimeMs(filePath) {
3853
4189
  if (!(0, import_node_fs16.existsSync)(filePath)) return 0;
@@ -3943,12 +4279,12 @@ async function generateGraph(rootDir, layer) {
3943
4279
  }
3944
4280
  return results;
3945
4281
  }
3946
- var import_node_fs16, import_node_path18, GRAPHS_DIR2, graphCache, taggedCache;
4282
+ var import_node_fs16, import_node_path17, GRAPHS_DIR2, graphCache, taggedCache;
3947
4283
  var init_graph = __esm({
3948
4284
  "src/server/graph/index.ts"() {
3949
4285
  "use strict";
3950
4286
  import_node_fs16 = require("node:fs");
3951
- import_node_path18 = require("node:path");
4287
+ import_node_path17 = require("node:path");
3952
4288
  init_graph_builder();
3953
4289
  init_config();
3954
4290
  init_tagger_registry();
@@ -3963,7 +4299,7 @@ var init_graph = __esm({
3963
4299
 
3964
4300
  // src/server/graph/core/audit-core.ts
3965
4301
  function readGraphFile(rootDir, layer) {
3966
- const filePath = (0, import_node_path19.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
4302
+ const filePath = (0, import_node_path18.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
3967
4303
  if (!(0, import_node_fs17.existsSync)(filePath)) return null;
3968
4304
  try {
3969
4305
  return JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
@@ -4010,7 +4346,7 @@ function checkUnprotectedRoutes(rootDir) {
4010
4346
  const api = readGraphFile(rootDir, "api");
4011
4347
  const staticGraph = readGraphFile(rootDir, "static");
4012
4348
  if (!api) return buildReport("api", "unprotected_routes", findings);
4013
- const routePermsPath = (0, import_node_path19.join)(rootDir, "src", "config", "route-permissions.ts");
4349
+ const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
4014
4350
  let routePermsContent = "";
4015
4351
  if ((0, import_node_fs17.existsSync)(routePermsPath)) {
4016
4352
  routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
@@ -4090,7 +4426,7 @@ function checkUnenforcedPermissions(rootDir) {
4090
4426
  const staticGraph = readGraphFile(rootDir, "static");
4091
4427
  if (!staticGraph) return buildReport("static", "unenforced_permissions", findings);
4092
4428
  const permissions = staticGraph.nodes.filter((n) => n.type === "seed_permission").map((n) => ({ id: n.id, key: n.value, name: n.name }));
4093
- const routePermsPath = (0, import_node_path19.join)(rootDir, "src", "config", "route-permissions.ts");
4429
+ const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
4094
4430
  let routePermsContent = "";
4095
4431
  if ((0, import_node_fs17.existsSync)(routePermsPath)) {
4096
4432
  routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
@@ -4123,7 +4459,7 @@ function checkHardcodedValues(rootDir) {
4123
4459
  const seen = /* @__PURE__ */ new Set();
4124
4460
  for (const node of api.nodes) {
4125
4461
  if (node.type !== "endpoint") continue;
4126
- const filePath = (0, import_node_path19.join)(rootDir, "src", node.id);
4462
+ const filePath = (0, import_node_path18.join)(rootDir, "src", node.id);
4127
4463
  if (!(0, import_node_fs17.existsSync)(filePath)) continue;
4128
4464
  const content = (0, import_node_fs17.readFileSync)(filePath, "utf-8");
4129
4465
  let m;
@@ -4219,12 +4555,12 @@ function formatAsPrompt(reports) {
4219
4555
  if (lines.length === 0) return "No audit findings.";
4220
4556
  return lines.join("\n");
4221
4557
  }
4222
- var import_node_fs17, import_node_path19, CHECKS;
4558
+ var import_node_fs17, import_node_path18, CHECKS;
4223
4559
  var init_audit_core = __esm({
4224
4560
  "src/server/graph/core/audit-core.ts"() {
4225
4561
  "use strict";
4226
4562
  import_node_fs17 = require("node:fs");
4227
- import_node_path19 = require("node:path");
4563
+ import_node_path18 = require("node:path");
4228
4564
  CHECKS = {
4229
4565
  db: {
4230
4566
  schema_drift: checkSchemaDrift,
@@ -4256,16 +4592,16 @@ function randomPort() {
4256
4592
  function findProjectRoot(startDir) {
4257
4593
  let dir = startDir;
4258
4594
  for (let i = 0; i < 8; i++) {
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);
4595
+ const graphsDir2 = import_node_path19.default.join(dir, ".launchsecure", "graphs");
4596
+ if (import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "ui.json")) || import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "api.json")) || import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "db.json"))) return dir;
4597
+ const parent = import_node_path19.default.dirname(dir);
4262
4598
  if (parent === dir) break;
4263
4599
  dir = parent;
4264
4600
  }
4265
4601
  dir = startDir;
4266
4602
  for (let i = 0; i < 8; i++) {
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);
4603
+ if (import_node_fs18.default.existsSync(import_node_path19.default.join(dir, ".git"))) return dir;
4604
+ const parent = import_node_path19.default.dirname(dir);
4269
4605
  if (parent === dir) break;
4270
4606
  dir = parent;
4271
4607
  }
@@ -4274,7 +4610,7 @@ function findProjectRoot(startDir) {
4274
4610
  function resolveRequestRoot(url, monorepoRoot, projects) {
4275
4611
  const projectParam = url.searchParams.get("project");
4276
4612
  if (!projectParam || projects.length === 0) return monorepoRoot;
4277
- const resolved = import_node_path20.default.resolve(monorepoRoot, projectParam);
4613
+ const resolved = import_node_path19.default.resolve(monorepoRoot, projectParam);
4278
4614
  if (!resolved.startsWith(monorepoRoot)) {
4279
4615
  throw new Error("Project path outside monorepo root");
4280
4616
  }
@@ -4326,14 +4662,14 @@ async function buildMergedGraph(root) {
4326
4662
  }
4327
4663
  function serveStatic(res, filePath) {
4328
4664
  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();
4665
+ const ext = import_node_path19.default.extname(filePath).toLowerCase();
4330
4666
  const mime = MIME_TYPES[ext] ?? "application/octet-stream";
4331
4667
  res.writeHead(200, { "Content-Type": mime, "Cache-Control": "no-cache" });
4332
4668
  import_node_fs18.default.createReadStream(filePath).pipe(res);
4333
4669
  return true;
4334
4670
  }
4335
4671
  function serveIndex(res, clientDir) {
4336
- const indexPath = import_node_path20.default.join(clientDir, "index.html");
4672
+ const indexPath = import_node_path19.default.join(clientDir, "index.html");
4337
4673
  if (!import_node_fs18.default.existsSync(indexPath)) {
4338
4674
  res.writeHead(500, { "Content-Type": "text/plain" });
4339
4675
  res.end(`LaunchChart client bundle not found at ${clientDir}. Run 'npm run build:chart-client'.`);
@@ -4342,14 +4678,14 @@ function serveIndex(res, clientDir) {
4342
4678
  serveStatic(res, indexPath);
4343
4679
  }
4344
4680
  function tryListen(server, port) {
4345
- return new Promise((resolve3, reject) => {
4681
+ return new Promise((resolve4, reject) => {
4346
4682
  const onError = (err2) => {
4347
4683
  server.off("listening", onListening);
4348
4684
  reject(err2);
4349
4685
  };
4350
4686
  const onListening = () => {
4351
4687
  server.off("error", onError);
4352
- resolve3(port);
4688
+ resolve4(port);
4353
4689
  };
4354
4690
  server.once("error", onError);
4355
4691
  server.once("listening", onListening);
@@ -4386,7 +4722,7 @@ async function startChartServer(opts = {}) {
4386
4722
  }
4387
4723
  return { port: existing.port, url: existing.url };
4388
4724
  }
4389
- const clientDir = opts.clientDir ?? import_node_path20.default.join(__dirname, "..", "chart-client");
4725
+ const clientDir = opts.clientDir ?? import_node_path19.default.join(__dirname, "..", "chart-client");
4390
4726
  const rootConfig = loadConfig(projectRoot);
4391
4727
  const projects = rootConfig.projects ?? [];
4392
4728
  const server = import_node_http.default.createServer((req, res) => {
@@ -4402,11 +4738,11 @@ async function startChartServer(opts = {}) {
4402
4738
  }
4403
4739
  if (req.method === "GET" && url2.pathname === "/api/projects") {
4404
4740
  const projectList = projects.length > 0 ? projects.map((p) => {
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"));
4741
+ const absRoot = import_node_path19.default.resolve(projectRoot, p.root);
4742
+ const hasGraphs = import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, ".launchsecure", "graphs"));
4743
+ const hasNextConfig = import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.ts")) || import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.js")) || import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.mjs"));
4408
4744
  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 }];
4745
+ }) : [{ name: import_node_path19.default.basename(projectRoot), root: ".", hasGraphs: import_node_fs18.default.existsSync(import_node_path19.default.join(projectRoot, ".launchsecure", "graphs")), hasNextConfig: true }];
4410
4746
  res.writeHead(200, { "Content-Type": "application/json" });
4411
4747
  res.end(JSON.stringify({ projects: projectList, monorepoRoot: projectRoot }));
4412
4748
  return;
@@ -4452,18 +4788,18 @@ async function startChartServer(opts = {}) {
4452
4788
  }
4453
4789
  if (req.method === "GET" && url2.pathname === "/api/file-content") {
4454
4790
  const relPath = url2.searchParams.get("path");
4455
- if (!relPath || relPath.includes("..") || import_node_path20.default.isAbsolute(relPath)) {
4791
+ if (!relPath || relPath.includes("..") || import_node_path19.default.isAbsolute(relPath)) {
4456
4792
  res.writeHead(400, { "Content-Type": "application/json" });
4457
4793
  res.end(JSON.stringify({ error: "Invalid path" }));
4458
4794
  return;
4459
4795
  }
4460
- const filePath = import_node_path20.default.join(reqRoot, relPath);
4796
+ const filePath = import_node_path19.default.join(reqRoot, relPath);
4461
4797
  if (!filePath.startsWith(reqRoot) || !import_node_fs18.default.existsSync(filePath) || !import_node_fs18.default.statSync(filePath).isFile()) {
4462
4798
  res.writeHead(404, { "Content-Type": "application/json" });
4463
4799
  res.end(JSON.stringify({ error: "File not found" }));
4464
4800
  return;
4465
4801
  }
4466
- const ext = import_node_path20.default.extname(filePath).toLowerCase();
4802
+ const ext = import_node_path19.default.extname(filePath).toLowerCase();
4467
4803
  const langMap = { ".ts": "typescript", ".tsx": "tsx", ".js": "javascript", ".jsx": "jsx", ".prisma": "prisma", ".json": "json", ".css": "css" };
4468
4804
  const content = import_node_fs18.default.readFileSync(filePath, "utf-8");
4469
4805
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -4507,7 +4843,7 @@ async function startChartServer(opts = {}) {
4507
4843
  req.on("end", () => {
4508
4844
  try {
4509
4845
  const newConfig = JSON.parse(body);
4510
- const configPath = import_node_path20.default.join(reqRoot, ".launchchart.json");
4846
+ const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
4511
4847
  import_node_fs18.default.writeFileSync(configPath, JSON.stringify(newConfig, null, 2) + "\n", "utf-8");
4512
4848
  res.writeHead(200, { "Content-Type": "application/json" });
4513
4849
  res.end(JSON.stringify({ ok: true }));
@@ -4541,7 +4877,7 @@ async function startChartServer(opts = {}) {
4541
4877
  const taggerConfig = JSON.parse(body);
4542
4878
  const config2 = loadConfig(reqRoot);
4543
4879
  config2.taggers = taggerConfig;
4544
- const configPath = import_node_path20.default.join(reqRoot, ".launchchart.json");
4880
+ const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
4545
4881
  import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
4546
4882
  res.writeHead(200, { "Content-Type": "application/json" });
4547
4883
  res.end(JSON.stringify({ ok: true }));
@@ -4609,16 +4945,23 @@ async function startChartServer(opts = {}) {
4609
4945
  const paths = resolveProjectPaths(reqRoot, config2);
4610
4946
  const overrides = {
4611
4947
  appDir: !!config2.paths?.appDir,
4612
- dbDir: !!config2.paths?.dbDir
4948
+ dbDir: !!config2.paths?.dbDir,
4949
+ srcRoots: !!(config2.paths?.srcRoots && config2.paths.srcRoots.length > 0)
4613
4950
  };
4951
+ const relFromRoot = (abs) => import_node_path19.default.relative(reqRoot, abs) || ".";
4614
4952
  res.writeHead(200, { "Content-Type": "application/json" });
4615
4953
  res.end(JSON.stringify({
4616
4954
  projectRoot: reqRoot,
4617
4955
  detected: paths ? {
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
4956
+ srcDir: relFromRoot(paths.srcDir),
4957
+ appDir: relFromRoot(paths.appDir),
4958
+ apiDir: relFromRoot(paths.apiDir),
4959
+ dbDir: paths.dbDir ? relFromRoot(paths.dbDir) : null,
4960
+ dbKind: paths.dbConfig.kind,
4961
+ dbSchemaPath: paths.dbConfig.schemaPath ? relFromRoot(paths.dbConfig.schemaPath) : null,
4962
+ dbMigrationsDir: paths.dbConfig.migrationsDir ? relFromRoot(paths.dbConfig.migrationsDir) : null,
4963
+ srcRoots: paths.srcRoots.map(relFromRoot),
4964
+ conventionFiles: paths.conventionFiles.map(relFromRoot)
4622
4965
  } : null,
4623
4966
  overrides,
4624
4967
  isOverride: overrides.appDir
@@ -4627,8 +4970,8 @@ async function startChartServer(opts = {}) {
4627
4970
  }
4628
4971
  if (req.method === "GET" && url2.pathname === "/api/browse-dir") {
4629
4972
  const browsePath = url2.searchParams.get("path") || projectRoot;
4630
- const abs = import_node_path20.default.resolve(browsePath);
4631
- const twoUp = import_node_path20.default.resolve(projectRoot, "..", "..");
4973
+ const abs = import_node_path19.default.resolve(browsePath);
4974
+ const twoUp = import_node_path19.default.resolve(projectRoot, "..", "..");
4632
4975
  if (!abs.startsWith(twoUp)) {
4633
4976
  res.writeHead(403, { "Content-Type": "application/json" });
4634
4977
  res.end(JSON.stringify({ ok: false, error: "Path outside allowed range" }));
@@ -4637,9 +4980,9 @@ async function startChartServer(opts = {}) {
4637
4980
  try {
4638
4981
  const entries = import_node_fs18.default.readdirSync(abs, { withFileTypes: true });
4639
4982
  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();
4640
- const parent = abs !== twoUp ? import_node_path20.default.dirname(abs) : null;
4983
+ const parent = abs !== twoUp ? import_node_path19.default.dirname(abs) : null;
4641
4984
  res.writeHead(200, { "Content-Type": "application/json" });
4642
- res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path20.default.relative(projectRoot, abs) || "." }));
4985
+ res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path19.default.relative(projectRoot, abs) || "." }));
4643
4986
  } catch (err2) {
4644
4987
  res.writeHead(400, { "Content-Type": "application/json" });
4645
4988
  res.end(JSON.stringify({ ok: false, error: String(err2) }));
@@ -4665,7 +5008,7 @@ async function startChartServer(opts = {}) {
4665
5008
  const { projects: newProjects } = JSON.parse(body);
4666
5009
  const config2 = loadConfig(projectRoot);
4667
5010
  config2.projects = newProjects.length > 0 ? newProjects : void 0;
4668
- const configPath = import_node_path20.default.join(projectRoot, ".launchchart.json");
5011
+ const configPath = import_node_path19.default.join(projectRoot, ".launchchart.json");
4669
5012
  import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
4670
5013
  projects.length = 0;
4671
5014
  if (config2.projects) projects.push(...config2.projects);
@@ -4679,7 +5022,7 @@ async function startChartServer(opts = {}) {
4679
5022
  return;
4680
5023
  }
4681
5024
  if (url2.pathname !== "/") {
4682
- const staticPath = import_node_path20.default.join(clientDir, url2.pathname);
5025
+ const staticPath = import_node_path19.default.join(clientDir, url2.pathname);
4683
5026
  if (serveStatic(res, staticPath)) return;
4684
5027
  }
4685
5028
  serveIndex(res, clientDir);
@@ -4739,13 +5082,13 @@ function runServeCli(argv) {
4739
5082
  process.exit(1);
4740
5083
  });
4741
5084
  }
4742
- var import_node_http, import_node_fs18, import_node_path20, MAX_PORT_SCAN, MIME_TYPES;
5085
+ var import_node_http, import_node_fs18, import_node_path19, MAX_PORT_SCAN, MIME_TYPES;
4743
5086
  var init_chart_serve = __esm({
4744
5087
  "src/server/chart-serve.ts"() {
4745
5088
  "use strict";
4746
5089
  import_node_http = __toESM(require("node:http"));
4747
5090
  import_node_fs18 = __toESM(require("node:fs"));
4748
- import_node_path20 = __toESM(require("node:path"));
5091
+ import_node_path19 = __toESM(require("node:path"));
4749
5092
  init_graph();
4750
5093
  init_lockfile();
4751
5094
  init_config();
@@ -4781,9 +5124,9 @@ function walkForExtensions(dir, extCounts, depth = 0) {
4781
5124
  if (entry.name.startsWith(".") && entry.isDirectory()) continue;
4782
5125
  if (entry.isDirectory()) {
4783
5126
  if (IGNORE_DIRS.has(entry.name)) continue;
4784
- walkForExtensions((0, import_node_path21.join)(dir, entry.name), extCounts, depth + 1);
5127
+ walkForExtensions((0, import_node_path20.join)(dir, entry.name), extCounts, depth + 1);
4785
5128
  } else {
4786
- const ext = (0, import_node_path21.extname)(entry.name).toLowerCase();
5129
+ const ext = (0, import_node_path20.extname)(entry.name).toLowerCase();
4787
5130
  if (ext && EXTENSION_TO_LANGUAGE[ext]) {
4788
5131
  extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
4789
5132
  }
@@ -4822,12 +5165,12 @@ function detectLanguages(rootDir, supportedLanguages) {
4822
5165
  });
4823
5166
  return results;
4824
5167
  }
4825
- var import_node_fs19, import_node_path21, EXTENSION_TO_LANGUAGE, IGNORE_DIRS, AUXILIARY_LANGUAGES;
5168
+ var import_node_fs19, import_node_path20, EXTENSION_TO_LANGUAGE, IGNORE_DIRS, AUXILIARY_LANGUAGES;
4826
5169
  var init_language_detection = __esm({
4827
5170
  "src/server/graph/core/language-detection.ts"() {
4828
5171
  "use strict";
4829
5172
  import_node_fs19 = require("node:fs");
4830
- import_node_path21 = require("node:path");
5173
+ import_node_path20 = require("node:path");
4831
5174
  EXTENSION_TO_LANGUAGE = {
4832
5175
  // Web / Frontend
4833
5176
  ".ts": "typescript",
@@ -5388,11 +5731,11 @@ function handleReadGraph(args) {
5388
5731
  return okJson(result);
5389
5732
  }
5390
5733
  function nodeToFilePath(rootDir, layer, nodeId) {
5391
- if (layer === "ui" || layer === "api") return (0, import_node_path22.join)(rootDir, "src", nodeId);
5392
- if (layer === "db") return (0, import_node_path22.join)(rootDir, "prisma", "schema.prisma");
5393
- const withSrc = (0, import_node_path22.join)(rootDir, "src", nodeId);
5734
+ if (layer === "ui" || layer === "api") return (0, import_node_path21.join)(rootDir, "src", nodeId);
5735
+ if (layer === "db") return (0, import_node_path21.join)(rootDir, "prisma", "schema.prisma");
5736
+ const withSrc = (0, import_node_path21.join)(rootDir, "src", nodeId);
5394
5737
  if ((0, import_node_fs20.existsSync)(withSrc)) return withSrc;
5395
- const direct = (0, import_node_path22.join)(rootDir, nodeId);
5738
+ const direct = (0, import_node_path21.join)(rootDir, nodeId);
5396
5739
  if ((0, import_node_fs20.existsSync)(direct)) return direct;
5397
5740
  return null;
5398
5741
  }
@@ -5605,9 +5948,9 @@ function handleStartChartServer(args) {
5605
5948
  });
5606
5949
  }
5607
5950
  const entryPath = process.argv[1];
5608
- const logDir = (0, import_node_path22.join)((0, import_node_os2.homedir)(), ".launchsecure");
5951
+ const logDir = (0, import_node_path21.join)((0, import_node_os2.homedir)(), ".launchsecure");
5609
5952
  (0, import_node_fs20.mkdirSync)(logDir, { recursive: true });
5610
- const logPath = (0, import_node_path22.join)(logDir, "launch-chart.log");
5953
+ const logPath = (0, import_node_path21.join)(logDir, "launch-chart.log");
5611
5954
  const out = (0, import_node_fs20.openSync)(logPath, "a");
5612
5955
  const err2 = (0, import_node_fs20.openSync)(logPath, "a");
5613
5956
  const portArgs = args.port ? ["--port", String(args.port)] : [];
@@ -5729,18 +6072,18 @@ function handleDetectProjectStack() {
5729
6072
  if (ref.type === "references_api") stats.references_api++;
5730
6073
  }
5731
6074
  }
5732
- const srcDir = (0, import_node_path22.join)(rootDir, "src");
6075
+ const srcDir = (0, import_node_path21.join)(rootDir, "src");
5733
6076
  if ((0, import_node_fs20.existsSync)(srcDir)) {
5734
6077
  const scanDir = (dir) => {
5735
6078
  if (!(0, import_node_fs20.existsSync)(dir)) return;
5736
6079
  for (const entry of (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true })) {
5737
6080
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
5738
- const full = (0, import_node_path22.join)(dir, entry.name);
6081
+ const full = (0, import_node_path21.join)(dir, entry.name);
5739
6082
  if (entry.isDirectory()) {
5740
6083
  scanDir(full);
5741
6084
  continue;
5742
6085
  }
5743
- if (![".ts", ".tsx"].includes((0, import_node_path22.extname)(entry.name))) continue;
6086
+ if (![".ts", ".tsx"].includes((0, import_node_path21.extname)(entry.name))) continue;
5744
6087
  try {
5745
6088
  const content = (0, import_node_fs20.readFileSync)(full, "utf-8");
5746
6089
  const matches = content.match(/@api\s+(GET|POST|PUT|DELETE|PATCH)\s+\/\S+/g);
@@ -5896,12 +6239,12 @@ function startGraphMcpServer() {
5896
6239
  process.stderr.write(`[launchsecure-graph] MCP server started (cwd: ${process.cwd()})
5897
6240
  `);
5898
6241
  }
5899
- var import_node_fs20, import_node_path22, import_node_child_process2, import_node_os2, SERVER_INFO, TOOLS, COMPACT_SCHEMA, COMPACT_NODE_KNOWN_KEYS, DEEP_FIELDS, EST_CHARS_PER_NODE_FULL, EST_CHARS_PER_NODE_MIN, EST_CHARS_PER_EDGE, DEFAULT_EST_NODE_FULL, DEFAULT_EST_NODE_MIN, DEFAULT_EST_EDGE, NEIGHBORHOOD_BUDGET_CHARS, BATCH_BUDGET_CHARS;
6242
+ var import_node_fs20, import_node_path21, import_node_child_process2, import_node_os2, SERVER_INFO, TOOLS, COMPACT_SCHEMA, COMPACT_NODE_KNOWN_KEYS, DEEP_FIELDS, EST_CHARS_PER_NODE_FULL, EST_CHARS_PER_NODE_MIN, EST_CHARS_PER_EDGE, DEFAULT_EST_NODE_FULL, DEFAULT_EST_NODE_MIN, DEFAULT_EST_EDGE, NEIGHBORHOOD_BUDGET_CHARS, BATCH_BUDGET_CHARS;
5900
6243
  var init_graph_mcp = __esm({
5901
6244
  "src/server/graph-mcp.ts"() {
5902
6245
  "use strict";
5903
6246
  import_node_fs20 = require("node:fs");
5904
- import_node_path22 = require("node:path");
6247
+ import_node_path21 = require("node:path");
5905
6248
  import_node_child_process2 = require("node:child_process");
5906
6249
  import_node_os2 = require("node:os");
5907
6250
  init_graph();
@@ -6288,7 +6631,7 @@ Example: blast_points(node_id: "server/auth/middleware.ts", hops: 2) \u2192 retu
6288
6631
  // src/server/graph-mcp-entry.ts
6289
6632
  var import_node_child_process3 = require("node:child_process");
6290
6633
  var import_node_fs21 = require("node:fs");
6291
- var import_node_path23 = __toESM(require("node:path"));
6634
+ var import_node_path22 = __toESM(require("node:path"));
6292
6635
  var import_node_os3 = require("node:os");
6293
6636
  var import_node_fs22 = require("node:fs");
6294
6637
  init_lockfile();
@@ -6306,9 +6649,9 @@ function maybeAutoServe() {
6306
6649
  return;
6307
6650
  }
6308
6651
  try {
6309
- const logDir = import_node_path23.default.join((0, import_node_os3.homedir)(), ".launchsecure");
6652
+ const logDir = import_node_path22.default.join((0, import_node_os3.homedir)(), ".launchsecure");
6310
6653
  (0, import_node_fs22.mkdirSync)(logDir, { recursive: true });
6311
- const logPath = import_node_path23.default.join(logDir, "launch-chart.log");
6654
+ const logPath = import_node_path22.default.join(logDir, "launch-chart.log");
6312
6655
  const out = (0, import_node_fs21.openSync)(logPath, "a");
6313
6656
  const err2 = (0, import_node_fs21.openSync)(logPath, "a");
6314
6657
  const entryPath = process.argv[1];