@launchsecure/launch-kit 0.0.38 → 0.0.40

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 (101) hide show
  1. package/dist/beacon/beacon.mjs +308 -298
  2. package/dist/beacon/beacon.mjs.map +1 -1
  3. package/dist/beacon/beacon.umd.js +6 -6
  4. package/dist/beacon/beacon.umd.js.map +1 -1
  5. package/dist/beacon/types/internal/screenshot.d.ts.map +1 -1
  6. package/dist/chart-client/assets/index-CWJFFDPu.css +1 -0
  7. package/dist/chart-client/index.html +2 -2
  8. package/dist/client/assets/index-CTzFcfGV.css +32 -0
  9. package/dist/client/index.html +2 -2
  10. package/dist/council-client/assets/index-ArgRc5mN.css +1 -0
  11. package/dist/council-client/index.html +2 -2
  12. package/dist/deck-client/assets/{_baseUniq-CgW32Gdk.js → _baseUniq-BZP7n41F.js} +1 -1
  13. package/dist/deck-client/assets/{arc-D-Mg9gvM.js → arc-31biU3Az.js} +1 -1
  14. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-CdTsXsgl.js → architectureDiagram-Q4EWVU46-DHg6Ss--.js} +1 -1
  15. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-mwTneYyB.js → blockDiagram-DXYQGD6D-CUdblaWk.js} +1 -1
  16. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-C4R8IbjO.js → c4Diagram-AHTNJAMY-MfAO5lak.js} +1 -1
  17. package/dist/deck-client/assets/channel-BBkRLdnC.js +1 -0
  18. package/dist/deck-client/assets/{chunk-4BX2VUAB-ZWuRIUwb.js → chunk-4BX2VUAB-DQ1MrGgN.js} +1 -1
  19. package/dist/deck-client/assets/{chunk-4TB4RGXK-PNHX10sF.js → chunk-4TB4RGXK-BUJtZ7jO.js} +1 -1
  20. package/dist/deck-client/assets/{chunk-55IACEB6-CD9MUgPr.js → chunk-55IACEB6-BdSnXB6g.js} +1 -1
  21. package/dist/deck-client/assets/{chunk-EDXVE4YY-C_CpORb3.js → chunk-EDXVE4YY-94yZIUI8.js} +1 -1
  22. package/dist/deck-client/assets/{chunk-FMBD7UC4-Bg5RoVC-.js → chunk-FMBD7UC4-PnZ9v6ey.js} +1 -1
  23. package/dist/deck-client/assets/{chunk-OYMX7WX6-DhTwgQwd.js → chunk-OYMX7WX6-DXrWNOsV.js} +1 -1
  24. package/dist/deck-client/assets/{chunk-QZHKN3VN-C5VLMaFa.js → chunk-QZHKN3VN-CsIGIDKX.js} +1 -1
  25. package/dist/deck-client/assets/{chunk-YZCP3GAM-NAGHy4Sr.js → chunk-YZCP3GAM-DVkBO9tn.js} +1 -1
  26. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-DFCaeF-7.js +1 -0
  27. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-DFCaeF-7.js +1 -0
  28. package/dist/deck-client/assets/clone-GCEVRScB.js +1 -0
  29. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-CpUczjZk.js → cose-bilkent-S5V4N54A-m126Oh3b.js} +1 -1
  30. package/dist/deck-client/assets/{dagre-KV5264BT-BOvb07MG.js → dagre-KV5264BT-C2aig8U5.js} +1 -1
  31. package/dist/deck-client/assets/{diagram-5BDNPKRD-BPxwTiC-.js → diagram-5BDNPKRD-CKpoRfGn.js} +1 -1
  32. package/dist/deck-client/assets/{diagram-G4DWMVQ6-Dz_gsHgx.js → diagram-G4DWMVQ6-Cjh115Ep.js} +1 -1
  33. package/dist/deck-client/assets/{diagram-MMDJMWI5-B7z-oVTW.js → diagram-MMDJMWI5-DKlBv_2L.js} +1 -1
  34. package/dist/deck-client/assets/{diagram-TYMM5635-CAIAglLQ.js → diagram-TYMM5635-CdBh4cEn.js} +1 -1
  35. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BiViTWF3.js → erDiagram-SMLLAGMA-56pn_93p.js} +1 -1
  36. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-DYVemp0H.js → flowDiagram-DWJPFMVM-BtV3M5xJ.js} +1 -1
  37. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-Chc1Iyu1.js → ganttDiagram-T4ZO3ILL-DTIsC6Zg.js} +1 -1
  38. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-B7eFgaj5.js → gitGraphDiagram-UUTBAWPF-CJYeyCLe.js} +1 -1
  39. package/dist/deck-client/assets/{graph-CKaIoNwb.js → graph-BDvMu1Ss.js} +1 -1
  40. package/dist/deck-client/assets/index-D4eSxcBn.css +1 -0
  41. package/dist/deck-client/assets/{index-BRawc7RA.js → index-QnGVE9PZ.js} +83 -83
  42. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-BxsVq7vO.js → infoDiagram-42DDH7IO-BWyKJnpW.js} +1 -1
  43. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DAM7vPwa.js → ishikawaDiagram-UXIWVN3A-DXYkdO3T.js} +1 -1
  44. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-Xe20Nf7R.js → journeyDiagram-VCZTEJTY-C2zBr-J5.js} +1 -1
  45. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-DS8YguzB.js → kanban-definition-6JOO6SKY-CdoYLS4Z.js} +1 -1
  46. package/dist/deck-client/assets/{layout-DKMBpzR-.js → layout-vOnxnCQU.js} +1 -1
  47. package/dist/deck-client/assets/{linear-DTNtBg5h.js → linear-B0J0WCGz.js} +1 -1
  48. package/dist/deck-client/assets/{min-C4DrxCcA.js → min-B0AXlT9L.js} +1 -1
  49. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-B4nEtsw5.js → mindmap-definition-QFDTVHPH-oAybLedr.js} +1 -1
  50. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-BzHdGNu5.js → pieDiagram-DEJITSTG-BjHyHxGk.js} +1 -1
  51. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-CaX0SD4-.js → quadrantDiagram-34T5L4WZ-dtluDZXs.js} +1 -1
  52. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-QeG4p2ni.js → requirementDiagram-MS252O5E-Cq8l7bOl.js} +1 -1
  53. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BoAwgAj-.js → sankeyDiagram-XADWPNL6-C1Vih91z.js} +1 -1
  54. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-Dn4pYYgu.js → sequenceDiagram-FGHM5R23-CYkd7oQK.js} +1 -1
  55. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-Is6KRmQV.js → stateDiagram-FHFEXIEX-CtyG8wBK.js} +1 -1
  56. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BLyKWfcN.js +1 -0
  57. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-v64IZGuY.js → timeline-definition-GMOUNBTQ-DZIxSyd1.js} +1 -1
  58. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-noh9eouF.js → vennDiagram-DHZGUBPP-Ct4JVRDM.js} +1 -1
  59. package/dist/deck-client/assets/{wardley-RL74JXVD-cJ_1is2S.js → wardley-RL74JXVD-V29ycxOW.js} +1 -1
  60. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-DxR4j737.js → wardleyDiagram-NUSXRM2D-D-Ua6Cmi.js} +1 -1
  61. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-B26vodaL.js → xychartDiagram-5P7HB3ND-BPCOuRVl.js} +1 -1
  62. package/dist/deck-client/index.html +2 -2
  63. package/dist/server/beacon-monitor-entry.js +106 -24
  64. package/dist/server/chart-serve.js +544 -247
  65. package/dist/server/cli.js +743 -324
  66. package/dist/server/council-entry.js +16 -3
  67. package/dist/server/council-serve.js +15 -2
  68. package/dist/server/deck-mcp-entry.js +270 -108
  69. package/dist/server/deck-serve.js +101 -23
  70. package/dist/server/fb-wizard.js +0 -0
  71. package/dist/server/graph-mcp-entry.js +866 -357
  72. package/dist/server/init-entry.js +152 -25
  73. package/dist/server/orbit-entry.js +91 -7
  74. package/dist/server/radar-docker-init-entry.js +0 -0
  75. package/dist/server/radar-entrypoint-entry.js +0 -0
  76. package/dist/server/radar-teardown-entry.js +0 -0
  77. package/dist/server/recall-entry.js +94 -12
  78. package/dist/server/rover-entry.js +44 -1
  79. package/package.json +23 -22
  80. package/scaffolds/ls-marketplace/plugins/kit/commands/activate-statusline.md +8 -7
  81. package/scaffolds/ls-marketplace/plugins/kit/commands/deactivate-statusline.md +2 -2
  82. package/scaffolds/ls-marketplace/plugins/kit/skills/comms/SKILL.md +88 -0
  83. package/scaffolds/ls-marketplace/plugins/kit/skills/project-info/SKILL.md +88 -0
  84. package/scaffolds/ls-marketplace/plugins/kit/skills/slides/SKILL.md +118 -0
  85. package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
  86. package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
  87. package/scaffolds/statusline/statusline-base.sh +20 -0
  88. package/scaffolds/statusline/statusline-mcp.sh +68 -19
  89. package/scaffolds/statusline/statusline-wrapper.sh +12 -9
  90. package/dist/chart-client/assets/index-B6rR0CWx.css +0 -1
  91. package/dist/client/assets/index-D6uX1lQe.css +0 -32
  92. package/dist/council-client/assets/index-CleYLarJ.css +0 -1
  93. package/dist/deck-client/assets/channel-CuSee7GO.js +0 -1
  94. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-_kTisqzs.js +0 -1
  95. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-_kTisqzs.js +0 -1
  96. package/dist/deck-client/assets/clone-kb3zkY60.js +0 -1
  97. package/dist/deck-client/assets/index-55P73aS_.css +0 -1
  98. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-Cy45Ttqq.js +0 -1
  99. /package/dist/chart-client/assets/{index-C_xCi3gW.js → index-Dzlj-oCj.js} +0 -0
  100. /package/dist/client/assets/{index-CRecYFUA.js → index-tTg_ezUF.js} +0 -0
  101. /package/dist/council-client/assets/{index-DO-Vn15O.js → index-B1v46vTE.js} +0 -0
@@ -148,20 +148,20 @@ __export(config_exports, {
148
148
  loadConfig: () => loadConfig
149
149
  });
150
150
  function loadConfig(rootDir) {
151
- const configPath = (0, import_node_path2.join)(rootDir, LAUNCHCHART_CONFIG_FILE);
152
- if (!(0, import_node_fs2.existsSync)(configPath)) return {};
151
+ const configPath = (0, import_node_path3.join)(rootDir, LAUNCHCHART_CONFIG_FILE);
152
+ if (!(0, import_node_fs3.existsSync)(configPath)) return {};
153
153
  try {
154
- return JSON.parse((0, import_node_fs2.readFileSync)(configPath, "utf-8"));
154
+ return JSON.parse((0, import_node_fs3.readFileSync)(configPath, "utf-8"));
155
155
  } catch {
156
156
  return {};
157
157
  }
158
158
  }
159
- var import_node_fs2, import_node_path2;
159
+ var import_node_fs3, import_node_path3;
160
160
  var init_config = __esm({
161
161
  "src/server/graph/core/config.ts"() {
162
162
  "use strict";
163
- import_node_fs2 = require("node:fs");
164
- import_node_path2 = require("node:path");
163
+ import_node_fs3 = require("node:fs");
164
+ import_node_path3 = require("node:path");
165
165
  init_launch_kit_paths();
166
166
  }
167
167
  });
@@ -198,18 +198,18 @@ function detectConventionDirs(rootDir, extraConventionDirs = []) {
198
198
  const conventionDirs = [...CONVENTION_DIRS_BUILTIN, ...extraConventionDirs];
199
199
  const searchDirs = [
200
200
  rootDir,
201
- (0, import_node_path3.join)(rootDir, "src"),
202
- (0, import_node_path3.join)(rootDir, "app"),
203
- (0, import_node_path3.join)(rootDir, "lib")
201
+ (0, import_node_path4.join)(rootDir, "src"),
202
+ (0, import_node_path4.join)(rootDir, "app"),
203
+ (0, import_node_path4.join)(rootDir, "lib")
204
204
  ];
205
205
  for (const base of searchDirs) {
206
206
  for (const convention of conventionDirs) {
207
- const dir = (0, import_node_path3.join)(base, convention);
208
- if (!(0, import_node_fs3.existsSync)(dir)) continue;
207
+ const dir = (0, import_node_path4.join)(base, convention);
208
+ if (!(0, import_node_fs4.existsSync)(dir)) continue;
209
209
  try {
210
- const stat = (0, import_node_fs3.statSync)(dir);
210
+ const stat = (0, import_node_fs4.statSync)(dir);
211
211
  if (!stat.isDirectory()) continue;
212
- const entries = (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
212
+ const entries = (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
213
213
  if (entries.length > 0) {
214
214
  const relPath = dir.replace(rootDir + "/", "").replace(rootDir + "\\", "");
215
215
  result.set(relPath, entries);
@@ -285,12 +285,12 @@ function extractModuleFromPath(id, extraTrivial, extraSkipSegments, extraGeneric
285
285
  }
286
286
  return "root";
287
287
  }
288
- var import_node_fs3, import_node_path3, CONVENTION_DIRS_BUILTIN, GENERIC_ROLE_NAMES_BUILTIN, SKIP_SEGMENTS_BUILTIN, TRIVIAL_GROUPS, cachedRootDir, cachedConventionDirs, moduleTagger;
288
+ var import_node_fs4, import_node_path4, CONVENTION_DIRS_BUILTIN, GENERIC_ROLE_NAMES_BUILTIN, SKIP_SEGMENTS_BUILTIN, TRIVIAL_GROUPS, cachedRootDir, cachedConventionDirs, moduleTagger;
289
289
  var init_module_tagger = __esm({
290
290
  "src/server/graph/taggers/module-tagger.ts"() {
291
291
  "use strict";
292
- import_node_fs3 = require("node:fs");
293
- import_node_path3 = require("node:path");
292
+ import_node_fs4 = require("node:fs");
293
+ import_node_path4 = require("node:path");
294
294
  CONVENTION_DIRS_BUILTIN = ["features", "modules", "domains", "areas"];
295
295
  GENERIC_ROLE_NAMES_BUILTIN = /* @__PURE__ */ new Set([
296
296
  // JS/TS
@@ -505,7 +505,7 @@ function loadCustomTaggers(registry, config, rootDir, disabled) {
505
505
  for (const entry of config.taggers?.custom ?? []) {
506
506
  if (disabled.has(entry.id)) continue;
507
507
  try {
508
- const absPath = (0, import_node_path4.resolve)(rootDir, entry.path);
508
+ const absPath = (0, import_node_path5.resolve)(rootDir, entry.path);
509
509
  const mod = require(absPath);
510
510
  const tagger = "default" in mod ? mod.default : mod;
511
511
  const override = config.taggers?.trackUntagged?.[tagger.id];
@@ -526,11 +526,11 @@ function createTaggerRegistry(config, rootDir) {
526
526
  loadCustomTaggers(registry, config, rootDir, disabled);
527
527
  return registry;
528
528
  }
529
- var import_node_path4, TaggerRegistry, BUILTIN_TAGGERS;
529
+ var import_node_path5, TaggerRegistry, BUILTIN_TAGGERS;
530
530
  var init_tagger_registry = __esm({
531
531
  "src/server/graph/core/tagger-registry.ts"() {
532
532
  "use strict";
533
- import_node_path4 = require("node:path");
533
+ import_node_path5 = require("node:path");
534
534
  init_module_tagger();
535
535
  init_screen_tagger();
536
536
  TaggerRegistry = class {
@@ -558,42 +558,42 @@ var init_tagger_registry = __esm({
558
558
 
559
559
  // src/server/graph/core/atomic-write.ts
560
560
  function atomicWriteFileSync(filePath, content, encoding = "utf-8") {
561
- (0, import_node_fs4.mkdirSync)((0, import_node_path5.dirname)(filePath), { recursive: true });
561
+ (0, import_node_fs5.mkdirSync)((0, import_node_path6.dirname)(filePath), { recursive: true });
562
562
  const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
563
563
  try {
564
- (0, import_node_fs4.writeFileSync)(tmp, content, typeof content === "string" ? encoding : void 0);
565
- (0, import_node_fs4.renameSync)(tmp, filePath);
564
+ (0, import_node_fs5.writeFileSync)(tmp, content, typeof content === "string" ? encoding : void 0);
565
+ (0, import_node_fs5.renameSync)(tmp, filePath);
566
566
  } catch (e) {
567
567
  try {
568
- (0, import_node_fs4.unlinkSync)(tmp);
568
+ (0, import_node_fs5.unlinkSync)(tmp);
569
569
  } catch {
570
570
  }
571
571
  throw e;
572
572
  }
573
573
  }
574
- var import_node_fs4, import_node_path5;
574
+ var import_node_fs5, import_node_path6;
575
575
  var init_atomic_write = __esm({
576
576
  "src/server/graph/core/atomic-write.ts"() {
577
577
  "use strict";
578
- import_node_fs4 = require("node:fs");
579
- import_node_path5 = require("node:path");
578
+ import_node_fs5 = require("node:fs");
579
+ import_node_path6 = require("node:path");
580
580
  }
581
581
  });
582
582
 
583
583
  // src/server/graph/core/tag-store.ts
584
584
  function tagsFilePath(rootDir) {
585
- return (0, import_node_path6.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
585
+ return (0, import_node_path7.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
586
586
  }
587
587
  function readTagStore(rootDir) {
588
588
  const filePath = tagsFilePath(rootDir);
589
- if (!(0, import_node_fs5.existsSync)(filePath)) return {};
590
- const stat = (0, import_node_fs5.statSync)(filePath);
589
+ if (!(0, import_node_fs6.existsSync)(filePath)) return {};
590
+ const stat = (0, import_node_fs6.statSync)(filePath);
591
591
  const cached = tagCache.get(filePath);
592
592
  if (cached && cached.mtimeMs === stat.mtimeMs) {
593
593
  return cached.store;
594
594
  }
595
595
  try {
596
- const content = (0, import_node_fs5.readFileSync)(filePath, "utf-8");
596
+ const content = (0, import_node_fs6.readFileSync)(filePath, "utf-8");
597
597
  const store = JSON.parse(content);
598
598
  tagCache.set(filePath, { mtimeMs: stat.mtimeMs, store });
599
599
  return store;
@@ -603,8 +603,8 @@ function readTagStore(rootDir) {
603
603
  }
604
604
  function writeTagStore(rootDir, store) {
605
605
  const filePath = tagsFilePath(rootDir);
606
- const dir = (0, import_node_path6.dirname)(filePath);
607
- (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
606
+ const dir = (0, import_node_path7.dirname)(filePath);
607
+ (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
608
608
  const cleaned = {};
609
609
  for (const [nodeId, tags] of Object.entries(store)) {
610
610
  if (Object.keys(tags).length > 0) {
@@ -629,12 +629,12 @@ function removeTag(rootDir, nodeId, key) {
629
629
  }
630
630
  writeTagStore(rootDir, store);
631
631
  }
632
- var import_node_fs5, import_node_path6, TAGS_FILENAME, GRAPHS_DIR, tagCache;
632
+ var import_node_fs6, import_node_path7, TAGS_FILENAME, GRAPHS_DIR, tagCache;
633
633
  var init_tag_store = __esm({
634
634
  "src/server/graph/core/tag-store.ts"() {
635
635
  "use strict";
636
- import_node_fs5 = require("node:fs");
637
- import_node_path6 = require("node:path");
636
+ import_node_fs6 = require("node:fs");
637
+ import_node_path7 = require("node:path");
638
638
  init_atomic_write();
639
639
  TAGS_FILENAME = "tags.json";
640
640
  GRAPHS_DIR = ".launchsecure/graphs";
@@ -644,16 +644,16 @@ var init_tag_store = __esm({
644
644
 
645
645
  // src/server/graph/core/parse-worker-host.ts
646
646
  function resolveWorkerPath() {
647
- const sibling = (0, import_node_path7.join)(__dirname, "parse-worker-entry.js");
648
- if ((0, import_node_fs6.existsSync)(sibling)) return sibling;
649
- const srcSibling = (0, import_node_path7.join)(__dirname, "..", "..", "parse-worker-entry.ts");
650
- if ((0, import_node_fs6.existsSync)(srcSibling)) return srcSibling;
647
+ const sibling = (0, import_node_path8.join)(__dirname, "parse-worker-entry.js");
648
+ if ((0, import_node_fs7.existsSync)(sibling)) return sibling;
649
+ const srcSibling = (0, import_node_path8.join)(__dirname, "..", "..", "parse-worker-entry.ts");
650
+ if ((0, import_node_fs7.existsSync)(srcSibling)) return srcSibling;
651
651
  throw new Error(
652
652
  `parse-worker-entry not found. Build the chart server first (pnpm --filter @launchsecure/launch-kit build:server). Looked at: ${sibling} and ${srcSibling}`
653
653
  );
654
654
  }
655
655
  function runParseInWorker(req) {
656
- return new Promise((resolve6, reject) => {
656
+ return new Promise((resolve7, reject) => {
657
657
  let workerPath;
658
658
  try {
659
659
  workerPath = resolveWorkerPath();
@@ -672,7 +672,7 @@ function runParseInWorker(req) {
672
672
  };
673
673
  worker.on("message", (reply) => {
674
674
  if (reply.ok) {
675
- finish(() => resolve6({ results: reply.results, failedFiles: reply.failedFiles }));
675
+ finish(() => resolve7({ results: reply.results, failedFiles: reply.failedFiles }));
676
676
  } else {
677
677
  const err2 = new Error(reply.error.message);
678
678
  err2.name = reply.error.name;
@@ -689,12 +689,12 @@ function runParseInWorker(req) {
689
689
  worker.postMessage(req);
690
690
  });
691
691
  }
692
- var import_node_fs6, import_node_path7, import_node_worker_threads;
692
+ var import_node_fs7, import_node_path8, import_node_worker_threads;
693
693
  var init_parse_worker_host = __esm({
694
694
  "src/server/graph/core/parse-worker-host.ts"() {
695
695
  "use strict";
696
- import_node_fs6 = require("node:fs");
697
- import_node_path7 = require("node:path");
696
+ import_node_fs7 = require("node:fs");
697
+ import_node_path8 = require("node:path");
698
698
  import_node_worker_threads = require("node:worker_threads");
699
699
  }
700
700
  });
@@ -752,20 +752,342 @@ function buildEffectsIndex(layerOutputs) {
752
752
  return idx;
753
753
  }
754
754
  function writeEffectsIndex(rootDir, idx) {
755
- const path2 = (0, import_node_path8.join)(rootDir, LAUNCHSECURE_DIR, "graphs", "effects-index.json");
755
+ const path2 = (0, import_node_path9.join)(rootDir, LAUNCHSECURE_DIR, "graphs", "effects-index.json");
756
756
  atomicWriteFileSync(path2, JSON.stringify(idx, null, 2) + "\n");
757
757
  return path2;
758
758
  }
759
- var import_node_path8;
759
+ var import_node_path9;
760
760
  var init_effects_index = __esm({
761
761
  "src/server/graph/core/effects-index.ts"() {
762
762
  "use strict";
763
763
  init_atomic_write();
764
- import_node_path8 = require("node:path");
764
+ import_node_path9 = require("node:path");
765
765
  init_launch_kit_paths();
766
766
  }
767
767
  });
768
768
 
769
+ // src/server/graph/core/context/types.ts
770
+ function higherConfidence(a, b) {
771
+ return CONFIDENCE_RANK[a] >= CONFIDENCE_RANK[b] ? a : b;
772
+ }
773
+ function stateId(token) {
774
+ return `state:${token}`;
775
+ }
776
+ function actionId(key) {
777
+ return `action:${key}`;
778
+ }
779
+ function stateNode(token, label) {
780
+ return { id: stateId(token), type: CONTEXT_NODE_STATE, name: token, label };
781
+ }
782
+ function actionNode(key, name, meta = {}) {
783
+ return { id: actionId(key), type: CONTEXT_NODE_ACTION, name, ...meta };
784
+ }
785
+ function contextEdge(fromActionId, toStateId, type, confidence, origin) {
786
+ return { source: fromActionId, target: toStateId, type, label: `${type} (${origin})`, confidence, origin };
787
+ }
788
+ var CONTEXT_NODE_ACTION, CONTEXT_NODE_STATE, CONFIDENCE_RANK;
789
+ var init_types = __esm({
790
+ "src/server/graph/core/context/types.ts"() {
791
+ "use strict";
792
+ CONTEXT_NODE_ACTION = "action";
793
+ CONTEXT_NODE_STATE = "state";
794
+ CONFIDENCE_RANK = { low: 0, medium: 1, high: 2 };
795
+ }
796
+ });
797
+
798
+ // src/server/graph/core/context/providers/nextjs-prisma.ts
799
+ function isPublic(auth) {
800
+ if (!auth || auth.length === 0) return true;
801
+ return auth.every((a) => a === "public");
802
+ }
803
+ function notFoundEntity(consequence) {
804
+ if (!consequence) return null;
805
+ const m = consequence.match(/notFound\(\s*['"]([A-Za-z0-9_]+)['"]/);
806
+ return m ? m[1] : null;
807
+ }
808
+ var PRODUCING_METHODS, nextjsPrismaContextProvider;
809
+ var init_nextjs_prisma = __esm({
810
+ "src/server/graph/core/context/providers/nextjs-prisma.ts"() {
811
+ "use strict";
812
+ init_types();
813
+ PRODUCING_METHODS = /* @__PURE__ */ new Set(["create", "createMany", "upsert"]);
814
+ nextjsPrismaContextProvider = {
815
+ id: "nextjs-prisma",
816
+ detect(layerOutputs) {
817
+ const api = layerOutputs["api"];
818
+ return !!api && (api.nodes ?? []).some((n) => n.type === "endpoint");
819
+ },
820
+ derive(layerOutputs) {
821
+ const api = layerOutputs["api"];
822
+ const states = /* @__PURE__ */ new Map();
823
+ const actions = [];
824
+ const edges = [];
825
+ const seenEdge = /* @__PURE__ */ new Set();
826
+ const ensureState = (token, label) => {
827
+ const id = stateId(token);
828
+ if (!states.has(id)) states.set(id, stateNode(token, label));
829
+ return id;
830
+ };
831
+ const addEdge = (from, to, type, confidence, origin) => {
832
+ const key = `${from}|${type}|${to}`;
833
+ if (seenEdge.has(key)) return;
834
+ seenEdge.add(key);
835
+ edges.push(contextEdge(from, to, type, confidence, origin));
836
+ };
837
+ const endpoints = (api?.nodes ?? []).filter((n) => n.type === "endpoint");
838
+ for (const ep of endpoints) {
839
+ const aId = actionId(ep.id);
840
+ actions.push(actionNode(ep.id, ep.name, { methods: ep.methods ?? [], endpoint: ep.id }));
841
+ if (!isPublic(ep.auth)) {
842
+ addEdge(aId, ensureState("session", "Authenticated session"), "requires", "high", "auth-wrapper");
843
+ }
844
+ for (const op of ep.db_operations ?? []) {
845
+ const [model, method] = op.split(".");
846
+ if (!model || !PRODUCING_METHODS.has(method ?? "")) continue;
847
+ addEdge(aId, ensureState(model, `${model} record exists`), "produces", "medium", `db:${op}`);
848
+ }
849
+ for (const cond of ep.conditions ?? []) {
850
+ const entity = notFoundEntity(cond.consequence);
851
+ if (!entity) continue;
852
+ const token = entity.toLowerCase();
853
+ addEdge(aId, ensureState(token, `${token} record exists`), "requires", "low", "guard:notFound");
854
+ }
855
+ }
856
+ return { nodes: [...actions, ...states.values()], edges };
857
+ }
858
+ };
859
+ }
860
+ });
861
+
862
+ // src/server/graph/core/context/overlay.ts
863
+ function overlayPath(rootDir) {
864
+ return (0, import_node_path10.join)(rootDir, OVERLAY_FILE);
865
+ }
866
+ function loadOverlay(rootDir) {
867
+ const path2 = overlayPath(rootDir);
868
+ if (!(0, import_node_fs8.existsSync)(path2)) return null;
869
+ try {
870
+ return JSON.parse((0, import_node_fs8.readFileSync)(path2, "utf-8"));
871
+ } catch (e) {
872
+ process.stderr.write(`[launch-chart] failed to parse ${OVERLAY_FILE}: ${e.message}
873
+ `);
874
+ return null;
875
+ }
876
+ }
877
+ function applyOverlayRejections(edges, rootDir) {
878
+ const overlay = loadOverlay(rootDir);
879
+ const rejects = overlay?.reject ?? [];
880
+ if (rejects.length === 0) return edges;
881
+ const rejectKeys = new Set(
882
+ rejects.map((r) => `${actionId(r.action)}|${r.type}|${stateId(r.state)}`)
883
+ );
884
+ return edges.filter((e) => !rejectKeys.has(`${e.source}|${e.type}|${e.target}`));
885
+ }
886
+ var import_node_fs8, import_node_path10, OVERLAY_FILE, overlayProvider;
887
+ var init_overlay = __esm({
888
+ "src/server/graph/core/context/overlay.ts"() {
889
+ "use strict";
890
+ import_node_fs8 = require("node:fs");
891
+ import_node_path10 = require("node:path");
892
+ init_types();
893
+ OVERLAY_FILE = ".launchchart.context.json";
894
+ overlayProvider = {
895
+ id: "overlay",
896
+ detect(_layerOutputs, rootDir) {
897
+ return (0, import_node_fs8.existsSync)(overlayPath(rootDir));
898
+ },
899
+ derive(_layerOutputs, rootDir) {
900
+ const overlay = loadOverlay(rootDir);
901
+ if (!overlay) return { nodes: [], edges: [] };
902
+ const nodes = /* @__PURE__ */ new Map();
903
+ const edges = [];
904
+ const seenEdge = /* @__PURE__ */ new Set();
905
+ const ensureState = (token, label) => {
906
+ const id = stateId(token);
907
+ if (!nodes.has(id)) nodes.set(id, stateNode(token, label ?? `${token} (overlay)`));
908
+ return id;
909
+ };
910
+ const ensureAction = (key, name) => {
911
+ const id = actionId(key);
912
+ if (!nodes.has(id)) nodes.set(id, actionNode(key, name ?? key, { source: "overlay" }));
913
+ return id;
914
+ };
915
+ for (const s of overlay.states ?? []) ensureState(s.token, s.label);
916
+ for (const a of overlay.actions ?? []) ensureAction(a.id, a.name);
917
+ for (const e of overlay.edges ?? []) {
918
+ const aId = ensureAction(e.action);
919
+ const link = (token, type) => {
920
+ const sId = ensureState(token);
921
+ const key = `${aId}|${type}|${sId}`;
922
+ if (seenEdge.has(key)) return;
923
+ seenEdge.add(key);
924
+ edges.push(contextEdge(aId, sId, type, "high", "overlay"));
925
+ };
926
+ for (const token of e.requires ?? []) link(token, "requires");
927
+ for (const token of e.produces ?? []) link(token, "produces");
928
+ }
929
+ return { nodes: [...nodes.values()], edges };
930
+ }
931
+ };
932
+ }
933
+ });
934
+
935
+ // src/server/graph/core/context/registry.ts
936
+ function registerBuiltins2(registry, disabled) {
937
+ const builtins = [nextjsPrismaContextProvider, overlayProvider];
938
+ for (const provider of builtins) {
939
+ if (disabled.has(provider.id)) continue;
940
+ registry.register(provider);
941
+ }
942
+ }
943
+ function loadCustomProviders(registry, config, rootDir, disabled) {
944
+ for (const entry of config.context?.providers ?? []) {
945
+ try {
946
+ const absPath = (0, import_node_path11.resolve)(rootDir, entry.path);
947
+ const mod = require(absPath);
948
+ const provider = "default" in mod ? mod.default : mod;
949
+ if (disabled.has(provider.id)) continue;
950
+ registry.register(provider);
951
+ } catch (err2) {
952
+ process.stderr.write(`[launch-chart] failed to load custom context provider from ${entry.path}: ${err2}
953
+ `);
954
+ }
955
+ }
956
+ }
957
+ function createContextProviderRegistry(config, rootDir) {
958
+ const registry = new ContextProviderRegistry();
959
+ const disabled = new Set(config.context?.disabled ?? []);
960
+ registerBuiltins2(registry, disabled);
961
+ loadCustomProviders(registry, config, rootDir, disabled);
962
+ return registry;
963
+ }
964
+ var import_node_path11, ContextProviderRegistry;
965
+ var init_registry = __esm({
966
+ "src/server/graph/core/context/registry.ts"() {
967
+ "use strict";
968
+ import_node_path11 = require("node:path");
969
+ init_nextjs_prisma();
970
+ init_overlay();
971
+ ContextProviderRegistry = class {
972
+ constructor() {
973
+ this.providers = [];
974
+ this.ids = /* @__PURE__ */ new Set();
975
+ }
976
+ register(provider) {
977
+ if (this.ids.has(provider.id)) {
978
+ throw new Error(`Duplicate context provider id: ${provider.id}`);
979
+ }
980
+ this.ids.add(provider.id);
981
+ this.providers.push(provider);
982
+ }
983
+ getAll() {
984
+ return [...this.providers];
985
+ }
986
+ };
987
+ }
988
+ });
989
+
990
+ // src/server/graph/core/context-map.ts
991
+ function buildContextMap(layerOutputs, rootDir) {
992
+ const generated = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
993
+ const config = loadConfig(rootDir);
994
+ const registry = createContextProviderRegistry(config, rootDir);
995
+ const nodesById = /* @__PURE__ */ new Map();
996
+ const edgesByKey = /* @__PURE__ */ new Map();
997
+ const providerStats = {};
998
+ const usedProviders = [];
999
+ for (const provider of registry.getAll()) {
1000
+ let detected = false;
1001
+ try {
1002
+ detected = provider.detect(layerOutputs, rootDir);
1003
+ } catch (e) {
1004
+ process.stderr.write(`[launch-chart] context provider "${provider.id}" detect failed: ${e.message}
1005
+ `);
1006
+ continue;
1007
+ }
1008
+ if (!detected) continue;
1009
+ let contribution;
1010
+ try {
1011
+ contribution = provider.derive(layerOutputs, rootDir);
1012
+ } catch (e) {
1013
+ process.stderr.write(`[launch-chart] context provider "${provider.id}" derive failed: ${e.message}
1014
+ `);
1015
+ continue;
1016
+ }
1017
+ usedProviders.push(provider.id);
1018
+ providerStats[provider.id] = { nodes: contribution.nodes.length, edges: contribution.edges.length };
1019
+ for (const node of contribution.nodes) {
1020
+ if (!nodesById.has(node.id)) nodesById.set(node.id, node);
1021
+ }
1022
+ for (const edge of contribution.edges) {
1023
+ const key = `${edge.source}|${edge.type}|${edge.target}`;
1024
+ const existing = edgesByKey.get(key);
1025
+ const edgeConf = edge.confidence ?? "low";
1026
+ if (!existing) {
1027
+ edgesByKey.set(key, { ...edge, providers: [provider.id] });
1028
+ } else {
1029
+ const existingConf = existing.confidence ?? "low";
1030
+ existing.confidence = higherConfidence(existingConf, edgeConf);
1031
+ const provs = existing.providers ?? [];
1032
+ if (!provs.includes(provider.id)) provs.push(provider.id);
1033
+ existing.providers = provs;
1034
+ }
1035
+ }
1036
+ }
1037
+ const merged = [...edgesByKey.values()];
1038
+ const edges = applyOverlayRejections(merged, rootDir);
1039
+ const rejectedCount = merged.length - edges.length;
1040
+ const flagged = edges.map((e) => ({
1041
+ source: e.source,
1042
+ target: e.target,
1043
+ type: e.type,
1044
+ label: e.label ?? `${e.type}`,
1045
+ confidence: e.confidence ?? "low"
1046
+ }));
1047
+ const nodes = [...nodesById.values()];
1048
+ const stateCount = nodes.filter((n) => n.type === CONTEXT_NODE_STATE).length;
1049
+ return {
1050
+ metadata: {
1051
+ generated,
1052
+ scope: "derived",
1053
+ layer: "context",
1054
+ source: "context-map-builder",
1055
+ derived: true,
1056
+ providers: usedProviders,
1057
+ provider_stats: providerStats,
1058
+ action_count: nodes.length - stateCount,
1059
+ state_count: stateCount,
1060
+ candidate_edge_count: edges.length,
1061
+ rejected_edge_count: rejectedCount,
1062
+ note: "Edges are candidates (see flagged_edges + confidence) from the context providers. Promote via the curation overlay."
1063
+ },
1064
+ nodes,
1065
+ edges,
1066
+ cross_refs: [],
1067
+ contradictions: [],
1068
+ warnings: [],
1069
+ flagged_edges: flagged
1070
+ };
1071
+ }
1072
+ function writeContextMap(rootDir, output) {
1073
+ const path2 = (0, import_node_path12.join)(rootDir, LAUNCHSECURE_DIR, "graphs", "context.json");
1074
+ atomicWriteFileSync(path2, JSON.stringify(output, null, 2) + "\n");
1075
+ return path2;
1076
+ }
1077
+ var import_node_path12;
1078
+ var init_context_map = __esm({
1079
+ "src/server/graph/core/context-map.ts"() {
1080
+ "use strict";
1081
+ init_atomic_write();
1082
+ import_node_path12 = require("node:path");
1083
+ init_launch_kit_paths();
1084
+ init_config();
1085
+ init_registry();
1086
+ init_overlay();
1087
+ init_types();
1088
+ }
1089
+ });
1090
+
769
1091
  // src/server/graph/core/freshness.ts
770
1092
  function exactFilenameRegex(name) {
771
1093
  return new RegExp(`^${name.replace(/\./g, "\\.")}$`);
@@ -781,12 +1103,12 @@ function getFreshnessTracker(rootDir) {
781
1103
  }
782
1104
  return t;
783
1105
  }
784
- var import_node_fs7, import_node_path9, SCHEMA_VERSION, MAX_PATCHED_FILES_TRACKED, DRIFTING_PATCH_THRESHOLD, HARD_ESCALATION_PATTERNS, FreshnessTracker, trackers;
1106
+ var import_node_fs9, import_node_path13, SCHEMA_VERSION, MAX_PATCHED_FILES_TRACKED, DRIFTING_PATCH_THRESHOLD, HARD_ESCALATION_PATTERNS, FreshnessTracker, trackers;
785
1107
  var init_freshness = __esm({
786
1108
  "src/server/graph/core/freshness.ts"() {
787
1109
  "use strict";
788
- import_node_fs7 = require("node:fs");
789
- import_node_path9 = require("node:path");
1110
+ import_node_fs9 = require("node:fs");
1111
+ import_node_path13 = require("node:path");
790
1112
  init_launch_kit_paths();
791
1113
  init_atomic_write();
792
1114
  SCHEMA_VERSION = 1;
@@ -803,7 +1125,7 @@ var init_freshness = __esm({
803
1125
  FreshnessTracker = class {
804
1126
  constructor(rootDir) {
805
1127
  this.dirty = false;
806
- this.filePath = (0, import_node_path9.join)(rootDir, LAUNCHSECURE_DIR, "graphs", ".freshness.json");
1128
+ this.filePath = (0, import_node_path13.join)(rootDir, LAUNCHSECURE_DIR, "graphs", ".freshness.json");
807
1129
  this.snapshot = this.load() ?? {
808
1130
  state: "fresh",
809
1131
  lastFullRegenAt: null,
@@ -890,9 +1212,9 @@ var init_freshness = __esm({
890
1212
  }
891
1213
  }
892
1214
  load() {
893
- if (!(0, import_node_fs7.existsSync)(this.filePath)) return null;
1215
+ if (!(0, import_node_fs9.existsSync)(this.filePath)) return null;
894
1216
  try {
895
- const parsed = JSON.parse((0, import_node_fs7.readFileSync)(this.filePath, "utf-8"));
1217
+ const parsed = JSON.parse((0, import_node_fs9.readFileSync)(this.filePath, "utf-8"));
896
1218
  if (parsed.schemaVersion !== SCHEMA_VERSION) return null;
897
1219
  return {
898
1220
  state: parsed.state,
@@ -914,22 +1236,22 @@ var init_freshness = __esm({
914
1236
 
915
1237
  // src/server/graph/index.ts
916
1238
  function getAvailableLayers(rootDir) {
917
- const dir = (0, import_node_path10.join)(rootDir, GRAPHS_DIR2);
918
- if (!(0, import_node_fs8.existsSync)(dir)) return [];
919
- return (0, import_node_fs8.readdirSync)(dir).filter((f) => f.endsWith(".json") && !f.startsWith(".") && !NON_LAYER_GRAPH_FILES.has(f)).map((f) => f.replace(".json", ""));
1239
+ const dir = (0, import_node_path14.join)(rootDir, GRAPHS_DIR2);
1240
+ if (!(0, import_node_fs10.existsSync)(dir)) return [];
1241
+ return (0, import_node_fs10.readdirSync)(dir).filter((f) => f.endsWith(".json") && !f.startsWith(".") && !NON_LAYER_GRAPH_FILES.has(f)).map((f) => f.replace(".json", ""));
920
1242
  }
921
1243
  function graphsDir(rootDir) {
922
- return (0, import_node_path10.join)(rootDir, GRAPHS_DIR2);
1244
+ return (0, import_node_path14.join)(rootDir, GRAPHS_DIR2);
923
1245
  }
924
1246
  function graphFilePath(rootDir, layer) {
925
- return (0, import_node_path10.join)(graphsDir(rootDir), `${layer}.json`);
1247
+ return (0, import_node_path14.join)(graphsDir(rootDir), `${layer}.json`);
926
1248
  }
927
1249
  function tagsFilePath2(rootDir) {
928
- return (0, import_node_path10.join)(graphsDir(rootDir), "tags.json");
1250
+ return (0, import_node_path14.join)(graphsDir(rootDir), "tags.json");
929
1251
  }
930
1252
  function getMtimeMs(filePath) {
931
- if (!(0, import_node_fs8.existsSync)(filePath)) return 0;
932
- return (0, import_node_fs8.statSync)(filePath).mtimeMs;
1253
+ if (!(0, import_node_fs10.existsSync)(filePath)) return 0;
1254
+ return (0, import_node_fs10.statSync)(filePath).mtimeMs;
933
1255
  }
934
1256
  function invalidateCache(filePath) {
935
1257
  graphCache.delete(filePath);
@@ -968,20 +1290,20 @@ function applyTags(graph, layer, rootDir) {
968
1290
  }
969
1291
  function readGraphRaw(rootDir, layer) {
970
1292
  const filePath = graphFilePath(rootDir, layer);
971
- if (!(0, import_node_fs8.existsSync)(filePath)) return null;
972
- const stat = (0, import_node_fs8.statSync)(filePath);
1293
+ if (!(0, import_node_fs10.existsSync)(filePath)) return null;
1294
+ const stat = (0, import_node_fs10.statSync)(filePath);
973
1295
  const cached = graphCache.get(filePath);
974
1296
  if (cached && cached.mtimeMs === stat.mtimeMs) {
975
1297
  return cached.graph;
976
1298
  }
977
- const content = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
1299
+ const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
978
1300
  const graph = JSON.parse(content);
979
1301
  graphCache.set(filePath, { mtimeMs: stat.mtimeMs, graph });
980
1302
  return graph;
981
1303
  }
982
1304
  function readGraph(rootDir, layer) {
983
1305
  const rawFilePath = graphFilePath(rootDir, layer);
984
- if (!(0, import_node_fs8.existsSync)(rawFilePath)) return null;
1306
+ if (!(0, import_node_fs10.existsSync)(rawFilePath)) return null;
985
1307
  const rawMtime = getMtimeMs(rawFilePath);
986
1308
  const tagsMtime = getMtimeMs(tagsFilePath2(rootDir));
987
1309
  const cacheKey = `${rootDir}:${layer}`;
@@ -1005,7 +1327,7 @@ function readAllGraphs(rootDir) {
1005
1327
  }
1006
1328
  async function generateGraph(rootDir, layer) {
1007
1329
  const dir = graphsDir(rootDir);
1008
- (0, import_node_fs8.mkdirSync)(dir, { recursive: true });
1330
+ (0, import_node_fs10.mkdirSync)(dir, { recursive: true });
1009
1331
  const { results, failedFiles } = await runParseInWorker({ rootDir, layer });
1010
1332
  for (const result of results) {
1011
1333
  const filePath = graphFilePath(rootDir, result.layer);
@@ -1016,13 +1338,13 @@ async function generateGraph(rootDir, layer) {
1016
1338
  if (!layer) {
1017
1339
  const producedLayers = new Set(results.map((r) => r.layer));
1018
1340
  try {
1019
- for (const f of (0, import_node_fs8.readdirSync)(dir)) {
1020
- if (!f.endsWith(".json") || f === "tags.json" || f === "effects-index.json") continue;
1341
+ for (const f of (0, import_node_fs10.readdirSync)(dir)) {
1342
+ if (!f.endsWith(".json") || f === "tags.json" || f === "effects-index.json" || f === "context.json") continue;
1021
1343
  const layerName = f.replace(/\.json$/, "");
1022
1344
  if (producedLayers.has(layerName)) continue;
1023
- const orphan = (0, import_node_path10.join)(dir, f);
1345
+ const orphan = (0, import_node_path14.join)(dir, f);
1024
1346
  try {
1025
- (0, import_node_fs8.unlinkSync)(orphan);
1347
+ (0, import_node_fs10.unlinkSync)(orphan);
1026
1348
  invalidateCache(orphan);
1027
1349
  invalidateTaggedCache(rootDir, layerName);
1028
1350
  process.stderr.write(`[launch-chart] removed orphan layer file: ${f} (no parser produced ${layerName} this run)
@@ -1033,22 +1355,31 @@ async function generateGraph(rootDir, layer) {
1033
1355
  } catch {
1034
1356
  }
1035
1357
  }
1036
- try {
1037
- const allLayers = {};
1038
- for (const r of results) allLayers[r.layer] = r.output;
1039
- if (layer) {
1040
- for (const f of (0, import_node_fs8.readdirSync)(dir)) {
1041
- if (!f.endsWith(".json") || f === "tags.json" || f === "effects-index.json") continue;
1042
- const layerName = f.replace(/\.json$/, "");
1043
- if (allLayers[layerName]) continue;
1044
- const existing = readGraphRaw(rootDir, layerName);
1045
- if (existing) allLayers[layerName] = existing;
1046
- }
1358
+ const allLayers = {};
1359
+ for (const r of results) allLayers[r.layer] = r.output;
1360
+ if (layer) {
1361
+ for (const f of (0, import_node_fs10.readdirSync)(dir)) {
1362
+ if (!f.endsWith(".json") || f.startsWith(".") || f === "tags.json" || f === "effects-index.json" || f === "context.json") continue;
1363
+ const layerName = f.replace(/\.json$/, "");
1364
+ if (allLayers[layerName]) continue;
1365
+ const existing = readGraphRaw(rootDir, layerName);
1366
+ if (existing) allLayers[layerName] = existing;
1047
1367
  }
1368
+ }
1369
+ try {
1048
1370
  const idx = buildEffectsIndex(allLayers);
1049
1371
  writeEffectsIndex(rootDir, idx);
1050
1372
  } catch (e) {
1051
1373
  process.stderr.write(`[launch-chart] effects-index build failed: ${e.message}
1374
+ `);
1375
+ }
1376
+ try {
1377
+ const ctx = buildContextMap(allLayers, rootDir);
1378
+ const ctxPath = writeContextMap(rootDir, ctx);
1379
+ invalidateCache(ctxPath);
1380
+ invalidateTaggedCache(rootDir, "context");
1381
+ } catch (e) {
1382
+ process.stderr.write(`[launch-chart] context-map build failed: ${e.message}
1052
1383
  `);
1053
1384
  }
1054
1385
  try {
@@ -1065,25 +1396,26 @@ async function generateGraph(rootDir, layer) {
1065
1396
  return results;
1066
1397
  }
1067
1398
  function readEffectsIndex(rootDir) {
1068
- const path2 = (0, import_node_path10.join)(rootDir, GRAPHS_DIR2, "effects-index.json");
1069
- if (!(0, import_node_fs8.existsSync)(path2)) return null;
1399
+ const path2 = (0, import_node_path14.join)(rootDir, GRAPHS_DIR2, "effects-index.json");
1400
+ if (!(0, import_node_fs10.existsSync)(path2)) return null;
1070
1401
  try {
1071
- return JSON.parse((0, import_node_fs8.readFileSync)(path2, "utf-8"));
1402
+ return JSON.parse((0, import_node_fs10.readFileSync)(path2, "utf-8"));
1072
1403
  } catch {
1073
1404
  return null;
1074
1405
  }
1075
1406
  }
1076
- var import_node_fs8, import_node_path10, GRAPHS_DIR2, NON_LAYER_GRAPH_FILES, graphCache, taggedCache;
1407
+ var import_node_fs10, import_node_path14, GRAPHS_DIR2, NON_LAYER_GRAPH_FILES, graphCache, taggedCache;
1077
1408
  var init_graph = __esm({
1078
1409
  "src/server/graph/index.ts"() {
1079
1410
  "use strict";
1080
- import_node_fs8 = require("node:fs");
1081
- import_node_path10 = require("node:path");
1411
+ import_node_fs10 = require("node:fs");
1412
+ import_node_path14 = require("node:path");
1082
1413
  init_config();
1083
1414
  init_tagger_registry();
1084
1415
  init_tag_store();
1085
1416
  init_parse_worker_host();
1086
1417
  init_effects_index();
1418
+ init_context_map();
1087
1419
  init_atomic_write();
1088
1420
  init_freshness();
1089
1421
  init_tag_store();
@@ -1097,12 +1429,12 @@ var init_graph = __esm({
1097
1429
  // src/server/graph/core/walk.ts
1098
1430
  function walk(dir, exts) {
1099
1431
  const results = [];
1100
- if (!(0, import_node_fs9.existsSync)(dir)) return results;
1101
- for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
1102
- const full = (0, import_node_path11.join)(dir, entry.name);
1432
+ if (!(0, import_node_fs11.existsSync)(dir)) return results;
1433
+ for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
1434
+ const full = (0, import_node_path15.join)(dir, entry.name);
1103
1435
  if (entry.isDirectory()) {
1104
1436
  results.push(...walk(full, exts));
1105
- } else if (exts.includes((0, import_node_path11.extname)(entry.name))) {
1437
+ } else if (exts.includes((0, import_node_path15.extname)(entry.name))) {
1106
1438
  results.push(full);
1107
1439
  }
1108
1440
  }
@@ -1110,25 +1442,25 @@ function walk(dir, exts) {
1110
1442
  }
1111
1443
  function walkWithIgnore(dir, exts, opts = {}) {
1112
1444
  const results = [];
1113
- if (!(0, import_node_fs9.existsSync)(dir)) return results;
1445
+ if (!(0, import_node_fs11.existsSync)(dir)) return results;
1114
1446
  const skip = opts.extraIgnore ? /* @__PURE__ */ new Set([...DEFAULT_IGNORE_DIRS, ...opts.extraIgnore]) : DEFAULT_IGNORE_DIRS;
1115
- for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
1447
+ for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
1116
1448
  if (entry.isDirectory()) {
1117
1449
  if (entry.name.startsWith(".")) continue;
1118
1450
  if (skip.has(entry.name)) continue;
1119
- results.push(...walkWithIgnore((0, import_node_path11.join)(dir, entry.name), exts, opts));
1120
- } else if (exts.includes((0, import_node_path11.extname)(entry.name))) {
1121
- results.push((0, import_node_path11.join)(dir, entry.name));
1451
+ results.push(...walkWithIgnore((0, import_node_path15.join)(dir, entry.name), exts, opts));
1452
+ } else if (exts.includes((0, import_node_path15.extname)(entry.name))) {
1453
+ results.push((0, import_node_path15.join)(dir, entry.name));
1122
1454
  }
1123
1455
  }
1124
1456
  return results;
1125
1457
  }
1126
- var import_node_fs9, import_node_path11, DEFAULT_IGNORE_DIRS;
1458
+ var import_node_fs11, import_node_path15, DEFAULT_IGNORE_DIRS;
1127
1459
  var init_walk = __esm({
1128
1460
  "src/server/graph/core/walk.ts"() {
1129
1461
  "use strict";
1130
- import_node_fs9 = require("node:fs");
1131
- import_node_path11 = require("node:path");
1462
+ import_node_fs11 = require("node:fs");
1463
+ import_node_path15 = require("node:path");
1132
1464
  DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
1133
1465
  "node_modules",
1134
1466
  "dist",
@@ -1141,9 +1473,9 @@ var init_walk = __esm({
1141
1473
 
1142
1474
  // src/server/graph/core/resolve-paths.ts
1143
1475
  function hasSqlFiles(dir) {
1144
- if (!(0, import_node_fs10.existsSync)(dir)) return false;
1476
+ if (!(0, import_node_fs12.existsSync)(dir)) return false;
1145
1477
  try {
1146
- return (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true }).some(
1478
+ return (0, import_node_fs12.readdirSync)(dir, { withFileTypes: true }).some(
1147
1479
  (e) => e.isFile() && e.name.endsWith(".sql")
1148
1480
  );
1149
1481
  } catch {
@@ -1151,27 +1483,27 @@ function hasSqlFiles(dir) {
1151
1483
  }
1152
1484
  }
1153
1485
  function hasNestedMigrationSql(dir) {
1154
- if (!(0, import_node_fs10.existsSync)(dir)) return false;
1486
+ if (!(0, import_node_fs12.existsSync)(dir)) return false;
1155
1487
  try {
1156
- return (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true }).some(
1157
- (e) => e.isDirectory() && (0, import_node_fs10.existsSync)((0, import_node_path12.join)(dir, e.name, "migration.sql"))
1488
+ return (0, import_node_fs12.readdirSync)(dir, { withFileTypes: true }).some(
1489
+ (e) => e.isDirectory() && (0, import_node_fs12.existsSync)((0, import_node_path16.join)(dir, e.name, "migration.sql"))
1158
1490
  );
1159
1491
  } catch {
1160
1492
  return false;
1161
1493
  }
1162
1494
  }
1163
1495
  function resolveDbFromDir(dir) {
1164
- if (!(0, import_node_fs10.existsSync)(dir)) return { kind: "none", schemaPath: null, migrationsDir: null };
1165
- const schemaPath = (0, import_node_path12.join)(dir, "schema.prisma");
1166
- if ((0, import_node_fs10.existsSync)(schemaPath)) {
1167
- const migrationsDir2 = (0, import_node_path12.join)(dir, "migrations");
1496
+ if (!(0, import_node_fs12.existsSync)(dir)) return { kind: "none", schemaPath: null, migrationsDir: null };
1497
+ const schemaPath = (0, import_node_path16.join)(dir, "schema.prisma");
1498
+ if ((0, import_node_fs12.existsSync)(schemaPath)) {
1499
+ const migrationsDir2 = (0, import_node_path16.join)(dir, "migrations");
1168
1500
  return {
1169
1501
  kind: "prisma",
1170
1502
  schemaPath,
1171
- migrationsDir: (0, import_node_fs10.existsSync)(migrationsDir2) ? migrationsDir2 : null
1503
+ migrationsDir: (0, import_node_fs12.existsSync)(migrationsDir2) ? migrationsDir2 : null
1172
1504
  };
1173
1505
  }
1174
- const migrationsDir = (0, import_node_path12.join)(dir, "migrations");
1506
+ const migrationsDir = (0, import_node_path16.join)(dir, "migrations");
1175
1507
  if (hasSqlFiles(migrationsDir) || hasNestedMigrationSql(migrationsDir)) {
1176
1508
  return { kind: "sql-migrations", migrationsDir, schemaPath: null };
1177
1509
  }
@@ -1182,33 +1514,33 @@ function resolveDbFromDir(dir) {
1182
1514
  }
1183
1515
  function detectDbConfig(rootDir, config) {
1184
1516
  if (config.paths?.dbDir) {
1185
- return resolveDbFromDir((0, import_node_path12.join)(rootDir, config.paths.dbDir));
1517
+ return resolveDbFromDir((0, import_node_path16.join)(rootDir, config.paths.dbDir));
1186
1518
  }
1187
- const candidates = ["prisma", "supabase", "drizzle", (0, import_node_path12.join)("db", "migrations"), "migrations"];
1519
+ const candidates = ["prisma", "supabase", "drizzle", (0, import_node_path16.join)("db", "migrations"), "migrations"];
1188
1520
  for (const c of candidates) {
1189
- const dir = (0, import_node_path12.join)(rootDir, c);
1521
+ const dir = (0, import_node_path16.join)(rootDir, c);
1190
1522
  const resolved = resolveDbFromDir(dir);
1191
1523
  if (resolved.kind !== "none") return resolved;
1192
1524
  }
1193
1525
  return { kind: "none", schemaPath: null, migrationsDir: null };
1194
1526
  }
1195
1527
  function detectDbDir(rootDir, config, dbConfig) {
1196
- if (config.paths?.dbDir) return (0, import_node_path12.join)(rootDir, config.paths.dbDir);
1197
- if (dbConfig.kind === "prisma") return (0, import_node_path12.dirname)(dbConfig.schemaPath);
1528
+ if (config.paths?.dbDir) return (0, import_node_path16.join)(rootDir, config.paths.dbDir);
1529
+ if (dbConfig.kind === "prisma") return (0, import_node_path16.dirname)(dbConfig.schemaPath);
1198
1530
  if (dbConfig.kind === "sql-migrations") return dbConfig.migrationsDir;
1199
1531
  return null;
1200
1532
  }
1201
1533
  function dirHasTSFiles(dir) {
1202
- if (!(0, import_node_fs10.existsSync)(dir)) return false;
1534
+ if (!(0, import_node_fs12.existsSync)(dir)) return false;
1203
1535
  try {
1204
1536
  const stack = [dir];
1205
1537
  while (stack.length > 0) {
1206
1538
  const cur = stack.pop();
1207
- const entries = (0, import_node_fs10.readdirSync)(cur, { withFileTypes: true });
1539
+ const entries = (0, import_node_fs12.readdirSync)(cur, { withFileTypes: true });
1208
1540
  for (const e of entries) {
1209
1541
  if (e.isFile() && (e.name.endsWith(".ts") || e.name.endsWith(".tsx"))) return true;
1210
1542
  if (e.isDirectory() && !e.name.startsWith(".") && !DEFAULT_IGNORE_DIRS.has(e.name)) {
1211
- stack.push((0, import_node_path12.join)(cur, e.name));
1543
+ stack.push((0, import_node_path16.join)(cur, e.name));
1212
1544
  }
1213
1545
  }
1214
1546
  }
@@ -1217,15 +1549,15 @@ function dirHasTSFiles(dir) {
1217
1549
  return false;
1218
1550
  }
1219
1551
  function collectCodeBearingChildren(dir, extraSkip) {
1220
- if (!(0, import_node_fs10.existsSync)(dir)) return [];
1552
+ if (!(0, import_node_fs12.existsSync)(dir)) return [];
1221
1553
  const out = [];
1222
1554
  try {
1223
- for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true })) {
1555
+ for (const entry of (0, import_node_fs12.readdirSync)(dir, { withFileTypes: true })) {
1224
1556
  if (!entry.isDirectory()) continue;
1225
1557
  if (entry.name.startsWith(".")) continue;
1226
1558
  if (NON_SOURCE_DIRS.has(entry.name)) continue;
1227
1559
  if (extraSkip?.has(entry.name)) continue;
1228
- const full = (0, import_node_path12.join)(dir, entry.name);
1560
+ const full = (0, import_node_path16.join)(dir, entry.name);
1229
1561
  if (dirHasTSFiles(full)) out.push(full);
1230
1562
  }
1231
1563
  } catch {
@@ -1237,7 +1569,7 @@ function detectSrcRoots(rootDir, srcDir, appDir, config) {
1237
1569
  const roots2 = /* @__PURE__ */ new Set();
1238
1570
  roots2.add(appDir);
1239
1571
  for (const r of config.paths.srcRoots) {
1240
- const abs = (0, import_node_path12.isAbsolute)(r) ? r : (0, import_node_path12.resolve)(rootDir, r);
1572
+ const abs = (0, import_node_path16.isAbsolute)(r) ? r : (0, import_node_path16.resolve)(rootDir, r);
1241
1573
  roots2.add(abs);
1242
1574
  }
1243
1575
  return [...roots2];
@@ -1246,7 +1578,7 @@ function detectSrcRoots(rootDir, srcDir, appDir, config) {
1246
1578
  roots.add(appDir);
1247
1579
  for (const c of collectCodeBearingChildren(srcDir)) roots.add(c);
1248
1580
  if (srcDir !== rootDir) {
1249
- const skipSrcWrapper = /* @__PURE__ */ new Set([(0, import_node_path12.basename)(srcDir)]);
1581
+ const skipSrcWrapper = /* @__PURE__ */ new Set([(0, import_node_path16.basename)(srcDir)]);
1250
1582
  for (const c of collectCodeBearingChildren(rootDir, skipSrcWrapper)) roots.add(c);
1251
1583
  }
1252
1584
  return [...roots];
@@ -1257,10 +1589,10 @@ function detectConventionFiles(rootDir, srcDir) {
1257
1589
  const dirs = srcDir === rootDir ? [rootDir] : [srcDir, rootDir];
1258
1590
  for (const dir of dirs) {
1259
1591
  for (const name of CONVENTION_NAMES) {
1260
- const full = (0, import_node_path12.join)(dir, name);
1261
- if (!seen.has(full) && (0, import_node_fs10.existsSync)(full)) {
1592
+ const full = (0, import_node_path16.join)(dir, name);
1593
+ if (!seen.has(full) && (0, import_node_fs12.existsSync)(full)) {
1262
1594
  try {
1263
- if ((0, import_node_fs10.statSync)(full).isFile()) {
1595
+ if ((0, import_node_fs12.statSync)(full).isFile()) {
1264
1596
  seen.add(full);
1265
1597
  out.push(full);
1266
1598
  }
@@ -1275,34 +1607,34 @@ function resolveProjectPaths(rootDir, config) {
1275
1607
  let srcDir;
1276
1608
  let appDir;
1277
1609
  if (config.paths?.appDir) {
1278
- appDir = (0, import_node_path12.join)(rootDir, config.paths.appDir);
1279
- srcDir = config.paths.srcDir ? (0, import_node_path12.join)(rootDir, config.paths.srcDir) : (0, import_node_path12.dirname)(appDir);
1610
+ appDir = (0, import_node_path16.join)(rootDir, config.paths.appDir);
1611
+ srcDir = config.paths.srcDir ? (0, import_node_path16.join)(rootDir, config.paths.srcDir) : (0, import_node_path16.dirname)(appDir);
1280
1612
  } else {
1281
- const srcApp = (0, import_node_path12.join)(rootDir, "src", "app");
1282
- const rootApp = (0, import_node_path12.join)(rootDir, "app");
1283
- if ((0, import_node_fs10.existsSync)(srcApp)) {
1284
- srcDir = (0, import_node_path12.join)(rootDir, "src");
1613
+ const srcApp = (0, import_node_path16.join)(rootDir, "src", "app");
1614
+ const rootApp = (0, import_node_path16.join)(rootDir, "app");
1615
+ if ((0, import_node_fs12.existsSync)(srcApp)) {
1616
+ srcDir = (0, import_node_path16.join)(rootDir, "src");
1285
1617
  appDir = srcApp;
1286
- } else if ((0, import_node_fs10.existsSync)(rootApp)) {
1618
+ } else if ((0, import_node_fs12.existsSync)(rootApp)) {
1287
1619
  srcDir = rootDir;
1288
1620
  appDir = rootApp;
1289
1621
  } else {
1290
1622
  return null;
1291
1623
  }
1292
1624
  }
1293
- const apiDir = (0, import_node_path12.join)(appDir, "api");
1625
+ const apiDir = (0, import_node_path16.join)(appDir, "api");
1294
1626
  const dbConfig = detectDbConfig(rootDir, config);
1295
1627
  const dbDir = detectDbDir(rootDir, config, dbConfig);
1296
1628
  const srcRoots = detectSrcRoots(rootDir, srcDir, appDir, config);
1297
1629
  const conventionFiles = detectConventionFiles(rootDir, srcDir);
1298
1630
  return { srcDir, appDir, apiDir, dbDir, srcRoots, conventionFiles, dbConfig };
1299
1631
  }
1300
- var import_node_fs10, import_node_path12, NON_SOURCE_DIRS, CONVENTION_NAMES;
1632
+ var import_node_fs12, import_node_path16, NON_SOURCE_DIRS, CONVENTION_NAMES;
1301
1633
  var init_resolve_paths = __esm({
1302
1634
  "src/server/graph/core/resolve-paths.ts"() {
1303
1635
  "use strict";
1304
- import_node_fs10 = require("node:fs");
1305
- import_node_path12 = require("node:path");
1636
+ import_node_fs12 = require("node:fs");
1637
+ import_node_path16 = require("node:path");
1306
1638
  init_walk();
1307
1639
  NON_SOURCE_DIRS = /* @__PURE__ */ new Set([
1308
1640
  ...DEFAULT_IGNORE_DIRS,
@@ -1401,8 +1733,8 @@ function getQuery(name) {
1401
1733
  ensureInit();
1402
1734
  const cached = queryCache.get(name);
1403
1735
  if (cached) return cached;
1404
- const scmPath = (0, import_node_path13.join)(queriesDir, `${name}.scm`);
1405
- const scm = (0, import_node_fs11.readFileSync)(scmPath, "utf-8");
1736
+ const scmPath = (0, import_node_path17.join)(queriesDir, `${name}.scm`);
1737
+ const scm = (0, import_node_fs13.readFileSync)(scmPath, "utf-8");
1406
1738
  const query = tsxLanguage.query(scm);
1407
1739
  queryCache.set(name, query);
1408
1740
  return query;
@@ -1422,13 +1754,13 @@ function parseSource(absPath) {
1422
1754
  ensureInit();
1423
1755
  let content;
1424
1756
  try {
1425
- const stat = (0, import_node_fs11.statSync)(absPath);
1757
+ const stat = (0, import_node_fs13.statSync)(absPath);
1426
1758
  if (stat.size > MAX_PARSEABLE_BYTES) {
1427
1759
  process.stderr.write(`[lc-extractor] skipping ${absPath}: ${stat.size} bytes exceeds max ${MAX_PARSEABLE_BYTES}
1428
1760
  `);
1429
1761
  return null;
1430
1762
  }
1431
- content = (0, import_node_fs11.readFileSync)(absPath, "utf-8");
1763
+ content = (0, import_node_fs13.readFileSync)(absPath, "utf-8");
1432
1764
  } catch (e) {
1433
1765
  process.stderr.write(`[lc-extractor] read failed for ${absPath}: ${e instanceof Error ? e.message : String(e)}
1434
1766
  `);
@@ -2462,18 +2794,18 @@ function collectUiLabels(root) {
2462
2794
  visit(root);
2463
2795
  return out;
2464
2796
  }
2465
- var import_node_fs11, import_node_path13, tsxLanguage, parserInstance, TreeSitterCtor, initPromise, initialized, queriesDir, queryCache, MAX_PARSEABLE_BYTES, MAX_CONSECUTIVE_PARSE_FAILURES, consecutiveParseFailures, ParseCascadeError, PRISMA_MUTATION_METHODS_BUILTIN, SUPABASE_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods, INLINE_AUTH_IMPORTS, EXEMPT_NAME_PATTERNS, PROTECT_NAME_PATTERNS, TRUST_AS_PROTECT_KEYS, TIMER_FNS, DOM_METHOD_NAMES, CLASSLIST_METHODS, STORAGE_OBJECTS, HISTORY_METHODS, LOCATION_METHODS, ASSIGN_DOM_PROPS, UI_LABEL_KEYS, UI_LABELS_MAX, NOTE_REGEX, NOTES_MAX;
2797
+ var import_node_fs13, import_node_path17, tsxLanguage, parserInstance, TreeSitterCtor, initPromise, initialized, queriesDir, queryCache, MAX_PARSEABLE_BYTES, MAX_CONSECUTIVE_PARSE_FAILURES, consecutiveParseFailures, ParseCascadeError, PRISMA_MUTATION_METHODS_BUILTIN, SUPABASE_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods, INLINE_AUTH_IMPORTS, EXEMPT_NAME_PATTERNS, PROTECT_NAME_PATTERNS, TRUST_AS_PROTECT_KEYS, TIMER_FNS, DOM_METHOD_NAMES, CLASSLIST_METHODS, STORAGE_OBJECTS, HISTORY_METHODS, LOCATION_METHODS, ASSIGN_DOM_PROPS, UI_LABEL_KEYS, UI_LABELS_MAX, NOTE_REGEX, NOTES_MAX;
2466
2798
  var init_ts_extractor = __esm({
2467
2799
  "src/server/graph/core/ts-extractor.ts"() {
2468
2800
  "use strict";
2469
- import_node_fs11 = require("node:fs");
2470
- import_node_path13 = require("node:path");
2801
+ import_node_fs13 = require("node:fs");
2802
+ import_node_path17 = require("node:path");
2471
2803
  init_parse_failure_cache();
2472
2804
  initialized = false;
2473
2805
  queriesDir = (() => {
2474
- const srcPath = (0, import_node_path13.join)((0, import_node_path13.dirname)(__filename), "..", "queries");
2806
+ const srcPath = (0, import_node_path17.join)((0, import_node_path17.dirname)(__filename), "..", "queries");
2475
2807
  if (require("fs").existsSync(srcPath)) return srcPath;
2476
- return (0, import_node_path13.join)((0, import_node_path13.dirname)(__filename), "graph", "queries");
2808
+ return (0, import_node_path17.join)((0, import_node_path17.dirname)(__filename), "graph", "queries");
2477
2809
  })();
2478
2810
  queryCache = /* @__PURE__ */ new Map();
2479
2811
  MAX_PARSEABLE_BYTES = 2 * 1024 * 1024;
@@ -2607,25 +2939,25 @@ var init_ts_extractor = __esm({
2607
2939
 
2608
2940
  // src/server/graph/parsers/ts/typescript-project.ts
2609
2941
  function toNodeId(srcDir, rootDir, absPath) {
2610
- const relFromSrc = (0, import_node_path14.relative)(srcDir, absPath).replace(/\\/g, "/");
2942
+ const relFromSrc = (0, import_node_path18.relative)(srcDir, absPath).replace(/\\/g, "/");
2611
2943
  if (relFromSrc.startsWith("..")) {
2612
- return (0, import_node_path14.relative)(rootDir, absPath).replace(/\\/g, "/");
2944
+ return (0, import_node_path18.relative)(rootDir, absPath).replace(/\\/g, "/");
2613
2945
  }
2614
2946
  return relFromSrc;
2615
2947
  }
2616
2948
  function resolveImport(srcDir, specifier) {
2617
2949
  if (!specifier.startsWith("@/")) return null;
2618
2950
  const rel = specifier.slice(2);
2619
- const base = (0, import_node_path14.join)(srcDir, rel);
2620
- for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path14.join)(base, "index.ts"), (0, import_node_path14.join)(base, "index.tsx")]) {
2621
- if ((0, import_node_fs12.existsSync)(c) && (0, import_node_fs12.statSync)(c).isFile()) return c;
2951
+ const base = (0, import_node_path18.join)(srcDir, rel);
2952
+ for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path18.join)(base, "index.ts"), (0, import_node_path18.join)(base, "index.tsx")]) {
2953
+ if ((0, import_node_fs14.existsSync)(c) && (0, import_node_fs14.statSync)(c).isFile()) return c;
2622
2954
  }
2623
2955
  return null;
2624
2956
  }
2625
2957
  function resolveRelativeImport(fromFile, specifier) {
2626
- const base = (0, import_node_path14.join)((0, import_node_path14.dirname)(fromFile), specifier);
2627
- for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path14.join)(base, "index.ts"), (0, import_node_path14.join)(base, "index.tsx")]) {
2628
- if ((0, import_node_fs12.existsSync)(c) && (0, import_node_fs12.statSync)(c).isFile()) return c;
2958
+ const base = (0, import_node_path18.join)((0, import_node_path18.dirname)(fromFile), specifier);
2959
+ for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path18.join)(base, "index.ts"), (0, import_node_path18.join)(base, "index.tsx")]) {
2960
+ if ((0, import_node_fs14.existsSync)(c) && (0, import_node_fs14.statSync)(c).isFile()) return c;
2629
2961
  }
2630
2962
  return null;
2631
2963
  }
@@ -2646,7 +2978,7 @@ function resolveBarrelMap(barrelAbsPath, parsedByPath, memo, visiting) {
2646
2978
  const resolved = resolveRelativeImport(barrelAbsPath, re.from);
2647
2979
  if (!resolved) continue;
2648
2980
  if (re.isWildcard) {
2649
- const targetBn = (0, import_node_path14.basename)(resolved);
2981
+ const targetBn = (0, import_node_path18.basename)(resolved);
2650
2982
  const targetIsBarrel = targetBn === "index.ts" || targetBn === "index.tsx";
2651
2983
  if (targetIsBarrel) {
2652
2984
  const nested = resolveBarrelMap(resolved, parsedByPath, memo, visiting);
@@ -2673,12 +3005,12 @@ function buildAllBarrelMaps(srcDir, parsedByPath) {
2673
3005
  const barrels = /* @__PURE__ */ new Map();
2674
3006
  const memo = /* @__PURE__ */ new Map();
2675
3007
  for (const [absPath, parsed] of parsedByPath) {
2676
- const bn = (0, import_node_path14.basename)(absPath);
3008
+ const bn = (0, import_node_path18.basename)(absPath);
2677
3009
  if (bn !== "index.ts" && bn !== "index.tsx") continue;
2678
3010
  if (parsed.reExports.length === 0) continue;
2679
3011
  const map = resolveBarrelMap(absPath, parsedByPath, memo, /* @__PURE__ */ new Set());
2680
3012
  if (map.size > 0) {
2681
- const barrelId = (0, import_node_path14.relative)(srcDir, (0, import_node_path14.dirname)(absPath)).replace(/\\/g, "/");
3013
+ const barrelId = (0, import_node_path18.relative)(srcDir, (0, import_node_path18.dirname)(absPath)).replace(/\\/g, "/");
2682
3014
  barrels.set(barrelId, map);
2683
3015
  }
2684
3016
  }
@@ -2703,10 +3035,10 @@ function extractRoute(id) {
2703
3035
  return route || "/";
2704
3036
  }
2705
3037
  function nameFromFilename(absPath) {
2706
- return (0, import_node_path14.basename)(absPath, (0, import_node_path14.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
3038
+ return (0, import_node_path18.basename)(absPath, (0, import_node_path18.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
2707
3039
  }
2708
3040
  function filePathToAppRoute(appDir, absPath) {
2709
- let route = ("/" + (0, import_node_path14.relative)(appDir, absPath).replace(/\\/g, "/")).replace(/\/route\.tsx?$/, "");
3041
+ let route = ("/" + (0, import_node_path18.relative)(appDir, absPath).replace(/\\/g, "/")).replace(/\/route\.tsx?$/, "");
2710
3042
  route = route.replace(/\/\([^)]+\)/g, "");
2711
3043
  route = route.replace(/\[\[\.\.\.([^\]]+)\]\]/g, "*$1?");
2712
3044
  route = route.replace(/\[\.\.\.([^\]]+)\]/g, "*$1");
@@ -2954,7 +3286,7 @@ function generate(rootDir) {
2954
3286
  const apiNodes = [];
2955
3287
  const nodeIdSet = /* @__PURE__ */ new Set();
2956
3288
  const routeToNodeId = /* @__PURE__ */ new Map();
2957
- const fileSet = allDiscovered.filter((f) => !(0, import_node_path14.basename)(f).startsWith("index."));
3289
+ const fileSet = allDiscovered.filter((f) => !(0, import_node_path18.basename)(f).startsWith("index."));
2958
3290
  for (const absPath of fileSet) {
2959
3291
  const id = toNodeId(srcDir, rootDir, absPath);
2960
3292
  const type = classifyType(absPath, id);
@@ -3114,7 +3446,7 @@ function generate(rootDir) {
3114
3446
  } catch {
3115
3447
  continue;
3116
3448
  }
3117
- const externalId = (0, import_node_path14.relative)(rootDir, absPath).replace(/\\/g, "/");
3449
+ const externalId = (0, import_node_path18.relative)(rootDir, absPath).replace(/\\/g, "/");
3118
3450
  const edgesFromThis = [];
3119
3451
  const seen = /* @__PURE__ */ new Set();
3120
3452
  for (const imp of parsed.imports) {
@@ -3456,12 +3788,12 @@ function generate(rootDir) {
3456
3788
  }
3457
3789
  return result;
3458
3790
  }
3459
- var import_node_fs12, import_node_path14, HTTP_METHODS, CLASSIFICATION_TO_LAYER, typescriptProjectParser;
3791
+ var import_node_fs14, import_node_path18, HTTP_METHODS, CLASSIFICATION_TO_LAYER, typescriptProjectParser;
3460
3792
  var init_typescript_project = __esm({
3461
3793
  "src/server/graph/parsers/ts/typescript-project.ts"() {
3462
3794
  "use strict";
3463
- import_node_fs12 = require("node:fs");
3464
- import_node_path14 = require("node:path");
3795
+ import_node_fs14 = require("node:fs");
3796
+ import_node_path18 = require("node:path");
3465
3797
  init_config();
3466
3798
  init_resolve_paths();
3467
3799
  init_walk();
@@ -3583,7 +3915,7 @@ function parseEnums(content) {
3583
3915
  }
3584
3916
  function detect2(rootDir) {
3585
3917
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
3586
- return paths?.dbConfig.kind === "prisma" && (0, import_node_fs13.existsSync)(paths.dbConfig.schemaPath);
3918
+ return paths?.dbConfig.kind === "prisma" && (0, import_node_fs15.existsSync)(paths.dbConfig.schemaPath);
3587
3919
  }
3588
3920
  function generate2(rootDir) {
3589
3921
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
@@ -3600,7 +3932,7 @@ function generate2(rootDir) {
3600
3932
  };
3601
3933
  }
3602
3934
  const schemaPath = paths.dbConfig.schemaPath;
3603
- const content = (0, import_node_fs13.readFileSync)(schemaPath, "utf-8");
3935
+ const content = (0, import_node_fs15.readFileSync)(schemaPath, "utf-8");
3604
3936
  const { nodes: modelNodes, relations } = parseModels(content);
3605
3937
  const enumNodes = parseEnums(content);
3606
3938
  const allNodes = [...modelNodes, ...enumNodes];
@@ -3649,11 +3981,11 @@ function generate2(rootDir) {
3649
3981
  }
3650
3982
  };
3651
3983
  }
3652
- var import_node_fs13, prismaSchemaParser;
3984
+ var import_node_fs15, prismaSchemaParser;
3653
3985
  var init_prisma_schema = __esm({
3654
3986
  "src/server/graph/parsers/db/prisma-schema.ts"() {
3655
3987
  "use strict";
3656
- import_node_fs13 = require("node:fs");
3988
+ import_node_fs15 = require("node:fs");
3657
3989
  init_config();
3658
3990
  init_resolve_paths();
3659
3991
  prismaSchemaParser = {
@@ -3671,15 +4003,15 @@ function pgTypeToPrisma(pgType) {
3671
4003
  return PG_TO_PRISMA[upper] ?? upper;
3672
4004
  }
3673
4005
  function discoverMigrationFiles(migrationsDir) {
3674
- if (!(0, import_node_fs14.existsSync)(migrationsDir)) return [];
4006
+ if (!(0, import_node_fs16.existsSync)(migrationsDir)) return [];
3675
4007
  const out = [];
3676
- const entries = (0, import_node_fs14.readdirSync)(migrationsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
4008
+ const entries = (0, import_node_fs16.readdirSync)(migrationsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
3677
4009
  for (const entry of entries) {
3678
4010
  if (entry.isDirectory()) {
3679
- const sqlPath = (0, import_node_path15.join)(migrationsDir, entry.name, "migration.sql");
3680
- if ((0, import_node_fs14.existsSync)(sqlPath)) out.push(sqlPath);
4011
+ const sqlPath = (0, import_node_path19.join)(migrationsDir, entry.name, "migration.sql");
4012
+ if ((0, import_node_fs16.existsSync)(sqlPath)) out.push(sqlPath);
3681
4013
  } else if (entry.isFile() && entry.name.endsWith(".sql")) {
3682
- out.push((0, import_node_path15.join)(migrationsDir, entry.name));
4014
+ out.push((0, import_node_path19.join)(migrationsDir, entry.name));
3683
4015
  }
3684
4016
  }
3685
4017
  return out;
@@ -3699,7 +4031,7 @@ function parseMigrations(migrationsDir, dialect = postgresDialect) {
3699
4031
  };
3700
4032
  if (!migrationsDir) return state;
3701
4033
  for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
3702
- const sql = (0, import_node_fs14.readFileSync)(sqlPath, "utf-8");
4034
+ const sql = (0, import_node_fs16.readFileSync)(sqlPath, "utf-8");
3703
4035
  let ast;
3704
4036
  try {
3705
4037
  ast = dialect.parse(sql);
@@ -4268,8 +4600,8 @@ function indexIsPrismaUncoverable(idx) {
4268
4600
  return idx.hasPredicate || idx.hasExpressions || idx.method !== "btree";
4269
4601
  }
4270
4602
  function loadPrismaState(schemaPath) {
4271
- if (!schemaPath || !(0, import_node_fs14.existsSync)(schemaPath)) return null;
4272
- const content = (0, import_node_fs14.readFileSync)(schemaPath, "utf-8");
4603
+ if (!schemaPath || !(0, import_node_fs16.existsSync)(schemaPath)) return null;
4604
+ const content = (0, import_node_fs16.readFileSync)(schemaPath, "utf-8");
4273
4605
  const tables = /* @__PURE__ */ new Map();
4274
4606
  const enums = /* @__PURE__ */ new Map();
4275
4607
  const relations = [];
@@ -4676,7 +5008,7 @@ function generate3(rootDir) {
4676
5008
  const migrationFiles = migrationsDir ? discoverMigrationFiles(migrationsDir) : [];
4677
5009
  let migrationNodeCount = 0;
4678
5010
  for (const sqlPath of migrationFiles) {
4679
- const sql = (0, import_node_fs14.readFileSync)(sqlPath, "utf-8");
5011
+ const sql = (0, import_node_fs16.readFileSync)(sqlPath, "utf-8");
4680
5012
  const name = deriveMigrationName(sqlPath);
4681
5013
  let ast;
4682
5014
  try {
@@ -4740,12 +5072,12 @@ function generate3(rootDir) {
4740
5072
  flagged_edges: flaggedEdges
4741
5073
  };
4742
5074
  }
4743
- var import_node_fs14, import_node_path15, import_pgsql_parser, PG_TO_PRISMA, postgresDialect, sqlMigrationsParser;
5075
+ var import_node_fs16, import_node_path19, import_pgsql_parser, PG_TO_PRISMA, postgresDialect, sqlMigrationsParser;
4744
5076
  var init_sql_migrations = __esm({
4745
5077
  "src/server/graph/parsers/db/sql-migrations.ts"() {
4746
5078
  "use strict";
4747
- import_node_fs14 = require("node:fs");
4748
- import_node_path15 = require("node:path");
5079
+ import_node_fs16 = require("node:fs");
5080
+ import_node_path19 = require("node:path");
4749
5081
  import_pgsql_parser = require("pgsql-parser");
4750
5082
  init_config();
4751
5083
  init_resolve_paths();
@@ -5069,18 +5401,18 @@ var init_fetch_resolver = __esm({
5069
5401
 
5070
5402
  // src/server/graph/parsers/crosslayer/api-annotations.ts
5071
5403
  function toNodeId2(srcDir, rootDir, absPath) {
5072
- const relFromSrc = (0, import_node_path16.relative)(srcDir, absPath).replace(/\\/g, "/");
5404
+ const relFromSrc = (0, import_node_path20.relative)(srcDir, absPath).replace(/\\/g, "/");
5073
5405
  if (relFromSrc.startsWith("..")) {
5074
- return (0, import_node_path16.relative)(rootDir, absPath).replace(/\\/g, "/");
5406
+ return (0, import_node_path20.relative)(rootDir, absPath).replace(/\\/g, "/");
5075
5407
  }
5076
5408
  return relFromSrc;
5077
5409
  }
5078
- var import_node_fs15, import_node_path16, API_ANNOTATION_RE, apiAnnotationsParser;
5410
+ var import_node_fs17, import_node_path20, API_ANNOTATION_RE, apiAnnotationsParser;
5079
5411
  var init_api_annotations = __esm({
5080
5412
  "src/server/graph/parsers/crosslayer/api-annotations.ts"() {
5081
5413
  "use strict";
5082
- import_node_fs15 = require("node:fs");
5083
- import_node_path16 = require("node:path");
5414
+ import_node_fs17 = require("node:fs");
5415
+ import_node_path20 = require("node:path");
5084
5416
  init_api_route_matching();
5085
5417
  init_config();
5086
5418
  init_resolve_paths();
@@ -5127,7 +5459,7 @@ var init_api_annotations = __esm({
5127
5459
  const flaggedEdges = [];
5128
5460
  const seenEdge = /* @__PURE__ */ new Set();
5129
5461
  for (const absPath of files) {
5130
- const content = (0, import_node_fs15.readFileSync)(absPath, "utf-8");
5462
+ const content = (0, import_node_fs17.readFileSync)(absPath, "utf-8");
5131
5463
  const sourceId = toNodeId2(srcDir, rootDir, absPath);
5132
5464
  if (!uiNodeIds.has(sourceId)) continue;
5133
5465
  let match;
@@ -5174,18 +5506,18 @@ var init_api_annotations = __esm({
5174
5506
 
5175
5507
  // src/server/graph/parsers/crosslayer/url-literal-scanner.ts
5176
5508
  function toNodeId3(srcDir, rootDir, absPath) {
5177
- const relFromSrc = (0, import_node_path17.relative)(srcDir, absPath).replace(/\\/g, "/");
5509
+ const relFromSrc = (0, import_node_path21.relative)(srcDir, absPath).replace(/\\/g, "/");
5178
5510
  if (relFromSrc.startsWith("..")) {
5179
- return (0, import_node_path17.relative)(rootDir, absPath).replace(/\\/g, "/");
5511
+ return (0, import_node_path21.relative)(rootDir, absPath).replace(/\\/g, "/");
5180
5512
  }
5181
5513
  return relFromSrc;
5182
5514
  }
5183
- var import_node_fs16, import_node_path17, URL_LITERAL_RE, urlLiteralScannerParser;
5515
+ var import_node_fs18, import_node_path21, URL_LITERAL_RE, urlLiteralScannerParser;
5184
5516
  var init_url_literal_scanner = __esm({
5185
5517
  "src/server/graph/parsers/crosslayer/url-literal-scanner.ts"() {
5186
5518
  "use strict";
5187
- import_node_fs16 = require("node:fs");
5188
- import_node_path17 = require("node:path");
5519
+ import_node_fs18 = require("node:fs");
5520
+ import_node_path21 = require("node:path");
5189
5521
  init_api_route_matching();
5190
5522
  init_config();
5191
5523
  init_resolve_paths();
@@ -5231,7 +5563,7 @@ var init_url_literal_scanner = __esm({
5231
5563
  for (const absPath of files) {
5232
5564
  const sourceId = toNodeId3(srcDir, rootDir, absPath);
5233
5565
  if (!uiNodeIds.has(sourceId)) continue;
5234
- const content = (0, import_node_fs16.readFileSync)(absPath, "utf-8");
5566
+ const content = (0, import_node_fs18.readFileSync)(absPath, "utf-8");
5235
5567
  let match;
5236
5568
  URL_LITERAL_RE.lastIndex = 0;
5237
5569
  while ((match = URL_LITERAL_RE.exec(content)) !== null) {
@@ -5296,21 +5628,21 @@ function extractEnumValues(rootDir) {
5296
5628
  const schemaPaths = [];
5297
5629
  if (paths?.dbConfig.kind === "prisma" && paths.dbConfig.schemaPath) {
5298
5630
  schemaPaths.push(paths.dbConfig.schemaPath);
5299
- schemaPaths.push((0, import_node_path18.join)((0, import_node_path18.dirname)(paths.dbConfig.schemaPath), "schema"));
5631
+ schemaPaths.push((0, import_node_path22.join)((0, import_node_path22.dirname)(paths.dbConfig.schemaPath), "schema"));
5300
5632
  } else {
5301
- schemaPaths.push((0, import_node_path18.join)(rootDir, "prisma", "schema.prisma"));
5302
- schemaPaths.push((0, import_node_path18.join)(rootDir, "prisma", "schema"));
5633
+ schemaPaths.push((0, import_node_path22.join)(rootDir, "prisma", "schema.prisma"));
5634
+ schemaPaths.push((0, import_node_path22.join)(rootDir, "prisma", "schema"));
5303
5635
  }
5304
5636
  let content = "";
5305
5637
  for (const p of schemaPaths) {
5306
- if ((0, import_node_fs17.existsSync)(p)) {
5638
+ if ((0, import_node_fs19.existsSync)(p)) {
5307
5639
  try {
5308
- const stat = (0, import_node_fs17.statSync)(p);
5640
+ const stat = (0, import_node_fs19.statSync)(p);
5309
5641
  if (stat.isFile()) {
5310
- content = (0, import_node_fs17.readFileSync)(p, "utf-8");
5642
+ content = (0, import_node_fs19.readFileSync)(p, "utf-8");
5311
5643
  } else if (stat.isDirectory()) {
5312
- const files = (0, import_node_fs17.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
5313
- content = files.map((f) => (0, import_node_fs17.readFileSync)((0, import_node_path18.join)(p, f), "utf-8")).join("\n");
5644
+ const files = (0, import_node_fs19.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
5645
+ content = files.map((f) => (0, import_node_fs19.readFileSync)((0, import_node_path22.join)(p, f), "utf-8")).join("\n");
5314
5646
  }
5315
5647
  } catch {
5316
5648
  continue;
@@ -5468,27 +5800,27 @@ function extractSeedData(rootDir) {
5468
5800
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
5469
5801
  const candidates = [];
5470
5802
  if (paths?.dbDir) {
5471
- candidates.push((0, import_node_path18.join)(paths.dbDir, "seed.ts"));
5472
- candidates.push((0, import_node_path18.join)(paths.dbDir, "seed.js"));
5803
+ candidates.push((0, import_node_path22.join)(paths.dbDir, "seed.ts"));
5804
+ candidates.push((0, import_node_path22.join)(paths.dbDir, "seed.js"));
5473
5805
  } else {
5474
- candidates.push((0, import_node_path18.join)(rootDir, "prisma", "seed.ts"));
5475
- candidates.push((0, import_node_path18.join)(rootDir, "prisma", "seed.js"));
5806
+ candidates.push((0, import_node_path22.join)(rootDir, "prisma", "seed.ts"));
5807
+ candidates.push((0, import_node_path22.join)(rootDir, "prisma", "seed.js"));
5476
5808
  }
5477
- const baseRoots = paths?.srcRoots ?? [(0, import_node_path18.join)(rootDir, "src")];
5809
+ const baseRoots = paths?.srcRoots ?? [(0, import_node_path22.join)(rootDir, "src")];
5478
5810
  for (const root of baseRoots) {
5479
- candidates.push((0, import_node_path18.join)(root, "server", "lib", "system-tags.ts"));
5811
+ candidates.push((0, import_node_path22.join)(root, "server", "lib", "system-tags.ts"));
5480
5812
  }
5481
5813
  const seedFiles = candidates.filter((p) => {
5482
5814
  try {
5483
- return (0, import_node_fs17.existsSync)(p) && (0, import_node_fs17.statSync)(p).isFile();
5815
+ return (0, import_node_fs19.existsSync)(p) && (0, import_node_fs19.statSync)(p).isFile();
5484
5816
  } catch {
5485
5817
  return false;
5486
5818
  }
5487
5819
  });
5488
5820
  const useTreeSitter = tryLoadTreeSitter();
5489
5821
  for (const filePath of seedFiles) {
5490
- const content = (0, import_node_fs17.readFileSync)(filePath, "utf-8");
5491
- const relPath = (0, import_node_path18.relative)(rootDir, filePath);
5822
+ const content = (0, import_node_fs19.readFileSync)(filePath, "utf-8");
5823
+ const relPath = (0, import_node_path22.relative)(rootDir, filePath);
5492
5824
  const seeded = detectSeededArrays(content, relPath);
5493
5825
  let astRoot = null;
5494
5826
  if (useTreeSitter && parseCode) {
@@ -5582,11 +5914,11 @@ function extractSeedData(rootDir) {
5582
5914
  return { nodes, edges };
5583
5915
  }
5584
5916
  function walkDir(dir, exts) {
5585
- if (!(0, import_node_fs17.existsSync)(dir)) return [];
5917
+ if (!(0, import_node_fs19.existsSync)(dir)) return [];
5586
5918
  const results = [];
5587
- for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
5919
+ for (const entry of (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true })) {
5588
5920
  if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
5589
- const full = (0, import_node_path18.join)(dir, entry.name);
5921
+ const full = (0, import_node_path22.join)(dir, entry.name);
5590
5922
  if (entry.isDirectory()) results.push(...walkDir(full, exts));
5591
5923
  else if (exts.some((ext) => entry.name.endsWith(ext))) results.push(full);
5592
5924
  }
@@ -5595,7 +5927,7 @@ function walkDir(dir, exts) {
5595
5927
  function extractConstants(rootDir) {
5596
5928
  const nodes = [];
5597
5929
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
5598
- const roots = paths?.srcRoots ?? [(0, import_node_path18.join)(rootDir, "src")];
5930
+ const roots = paths?.srcRoots ?? [(0, import_node_path22.join)(rootDir, "src")];
5599
5931
  const seenFile = /* @__PURE__ */ new Set();
5600
5932
  const allFiles = [];
5601
5933
  for (const root of roots) {
@@ -5608,8 +5940,8 @@ function extractConstants(rootDir) {
5608
5940
  }
5609
5941
  if (allFiles.length === 0) return { nodes };
5610
5942
  for (const filePath of allFiles) {
5611
- const content = (0, import_node_fs17.readFileSync)(filePath, "utf-8");
5612
- const relPath = (0, import_node_path18.relative)(rootDir, filePath);
5943
+ const content = (0, import_node_fs19.readFileSync)(filePath, "utf-8");
5944
+ const relPath = (0, import_node_path22.relative)(rootDir, filePath);
5613
5945
  const constArrayRe = /export\s+const\s+([A-Z][A-Z_0-9]+)\s*(?::[^=]+)?\s*=\s*\[/g;
5614
5946
  let cm;
5615
5947
  while ((cm = constArrayRe.exec(content)) !== null) {
@@ -5643,13 +5975,13 @@ function extractConstants(rootDir) {
5643
5975
  }
5644
5976
  function detect4(rootDir) {
5645
5977
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
5646
- if (paths?.dbConfig.kind === "prisma" && paths.dbConfig.schemaPath && (0, import_node_fs17.existsSync)(paths.dbConfig.schemaPath)) {
5978
+ if (paths?.dbConfig.kind === "prisma" && paths.dbConfig.schemaPath && (0, import_node_fs19.existsSync)(paths.dbConfig.schemaPath)) {
5647
5979
  return true;
5648
5980
  }
5649
5981
  if (paths?.dbDir) {
5650
- if ((0, import_node_fs17.existsSync)((0, import_node_path18.join)(paths.dbDir, "seed.ts")) || (0, import_node_fs17.existsSync)((0, import_node_path18.join)(paths.dbDir, "seed.js"))) return true;
5982
+ if ((0, import_node_fs19.existsSync)((0, import_node_path22.join)(paths.dbDir, "seed.ts")) || (0, import_node_fs19.existsSync)((0, import_node_path22.join)(paths.dbDir, "seed.js"))) return true;
5651
5983
  }
5652
- return (0, import_node_fs17.existsSync)((0, import_node_path18.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs17.existsSync)((0, import_node_path18.join)(rootDir, "prisma", "seed.ts"));
5984
+ return (0, import_node_fs19.existsSync)((0, import_node_path22.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs19.existsSync)((0, import_node_path22.join)(rootDir, "prisma", "seed.ts"));
5653
5985
  }
5654
5986
  function generate4(rootDir) {
5655
5987
  const enumResult = extractEnumValues(rootDir);
@@ -5716,12 +6048,12 @@ function generate4(rootDir) {
5716
6048
  }
5717
6049
  };
5718
6050
  }
5719
- var import_node_fs17, import_node_path18, parseCode, SHARED_MODELS, DB_MODELS, staticValuesParser;
6051
+ var import_node_fs19, import_node_path22, parseCode, SHARED_MODELS, DB_MODELS, staticValuesParser;
5720
6052
  var init_static_values = __esm({
5721
6053
  "src/server/graph/parsers/static/static-values.ts"() {
5722
6054
  "use strict";
5723
- import_node_fs17 = require("node:fs");
5724
- import_node_path18 = require("node:path");
6055
+ import_node_fs19 = require("node:fs");
6056
+ import_node_path22 = require("node:path");
5725
6057
  init_config();
5726
6058
  init_resolve_paths();
5727
6059
  parseCode = null;
@@ -5821,12 +6153,12 @@ function collectStaticRefsRegex(content, valueLookup, allValues) {
5821
6153
  }
5822
6154
  return refs;
5823
6155
  }
5824
- var import_node_fs18, import_node_path19, MIN_VALUE_LENGTH, SKIP_VALUES, staticRefScannerParser;
6156
+ var import_node_fs20, import_node_path23, MIN_VALUE_LENGTH, SKIP_VALUES, staticRefScannerParser;
5825
6157
  var init_static_ref_scanner = __esm({
5826
6158
  "src/server/graph/parsers/crosslayer/static-ref-scanner.ts"() {
5827
6159
  "use strict";
5828
- import_node_fs18 = require("node:fs");
5829
- import_node_path19 = require("node:path");
6160
+ import_node_fs20 = require("node:fs");
6161
+ import_node_path23 = require("node:path");
5830
6162
  init_config();
5831
6163
  init_resolve_paths();
5832
6164
  init_walk();
@@ -5919,11 +6251,11 @@ var init_static_ref_scanner = __esm({
5919
6251
  const seen = /* @__PURE__ */ new Set();
5920
6252
  let filesScanned = 0;
5921
6253
  for (const absPath of files) {
5922
- const relFromSrc = (0, import_node_path19.relative)(srcDir, absPath).replace(/\\/g, "/");
5923
- const sourceId = relFromSrc.startsWith("..") ? (0, import_node_path19.relative)(rootDir, absPath).replace(/\\/g, "/") : relFromSrc;
6254
+ const relFromSrc = (0, import_node_path23.relative)(srcDir, absPath).replace(/\\/g, "/");
6255
+ const sourceId = relFromSrc.startsWith("..") ? (0, import_node_path23.relative)(rootDir, absPath).replace(/\\/g, "/") : relFromSrc;
5924
6256
  const sourceLayer = uiNodeIds.has(sourceId) ? "ui" : apiNodeIds.has(sourceId) ? "api" : null;
5925
6257
  if (!sourceLayer) continue;
5926
- const content = (0, import_node_fs18.readFileSync)(absPath, "utf-8");
6258
+ const content = (0, import_node_fs20.readFileSync)(absPath, "utf-8");
5927
6259
  filesScanned++;
5928
6260
  let fileRefs;
5929
6261
  if (parseCode2) {
@@ -5968,9 +6300,9 @@ var init_static_ref_scanner = __esm({
5968
6300
 
5969
6301
  // src/server/graph/parsers/crosslayer/middleware-gates.ts
5970
6302
  function toNodeId4(srcDir, rootDir, absPath) {
5971
- const relFromSrc = (0, import_node_path20.relative)(srcDir, absPath).replace(/\\/g, "/");
6303
+ const relFromSrc = (0, import_node_path24.relative)(srcDir, absPath).replace(/\\/g, "/");
5972
6304
  if (relFromSrc.startsWith("..")) {
5973
- return (0, import_node_path20.relative)(rootDir, absPath).replace(/\\/g, "/");
6305
+ return (0, import_node_path24.relative)(rootDir, absPath).replace(/\\/g, "/");
5974
6306
  }
5975
6307
  return relFromSrc;
5976
6308
  }
@@ -5990,11 +6322,11 @@ function collectTargets(apiOutput, uiOutput) {
5990
6322
  }
5991
6323
  return out;
5992
6324
  }
5993
- var import_node_path20, middlewareGatesParser;
6325
+ var import_node_path24, middlewareGatesParser;
5994
6326
  var init_middleware_gates = __esm({
5995
6327
  "src/server/graph/parsers/crosslayer/middleware-gates.ts"() {
5996
6328
  "use strict";
5997
- import_node_path20 = require("node:path");
6329
+ import_node_path24 = require("node:path");
5998
6330
  init_ts_extractor();
5999
6331
  init_config();
6000
6332
  init_resolve_paths();
@@ -6215,7 +6547,7 @@ var init_call_resolver = __esm({
6215
6547
  function isMultiLayerParser(p) {
6216
6548
  return "layers" in p && Array.isArray(p.layers);
6217
6549
  }
6218
- function registerBuiltins2(registry, disabled) {
6550
+ function registerBuiltins3(registry, disabled) {
6219
6551
  const builtins = [
6220
6552
  typescriptProjectParser,
6221
6553
  prismaSchemaParser,
@@ -6236,7 +6568,7 @@ function registerBuiltins2(registry, disabled) {
6236
6568
  function loadCustomParsers(registry, config, rootDir, disabled) {
6237
6569
  for (const entry of config.parsers?.custom ?? []) {
6238
6570
  try {
6239
- const absPath = (0, import_node_path21.resolve)(rootDir, entry.path);
6571
+ const absPath = (0, import_node_path25.resolve)(rootDir, entry.path);
6240
6572
  const mod = require(absPath);
6241
6573
  const parser = "default" in mod ? mod.default : mod;
6242
6574
  if (disabled.has(parser.id)) continue;
@@ -6259,15 +6591,15 @@ function loadCustomParsers(registry, config, rootDir, disabled) {
6259
6591
  function createRegistry(config, rootDir) {
6260
6592
  const registry = new ParserRegistry();
6261
6593
  const disabled = new Set(config.parsers?.disabled ?? []);
6262
- registerBuiltins2(registry, disabled);
6594
+ registerBuiltins3(registry, disabled);
6263
6595
  loadCustomParsers(registry, config, rootDir, disabled);
6264
6596
  return registry;
6265
6597
  }
6266
- var import_node_path21, ParserRegistry;
6598
+ var import_node_path25, ParserRegistry;
6267
6599
  var init_parser_registry = __esm({
6268
6600
  "src/server/graph/core/parser-registry.ts"() {
6269
6601
  "use strict";
6270
- import_node_path21 = require("node:path");
6602
+ import_node_path25 = require("node:path");
6271
6603
  init_typescript_project();
6272
6604
  init_prisma_schema();
6273
6605
  init_sql_migrations();
@@ -6356,9 +6688,9 @@ function collectSourceFiles(rootDir) {
6356
6688
  return out;
6357
6689
  }
6358
6690
  function toNodeId5(rootDir, srcDir, absPath) {
6359
- const relFromSrc = (0, import_node_path22.relative)(srcDir, absPath).replace(/\\/g, "/");
6691
+ const relFromSrc = (0, import_node_path26.relative)(srcDir, absPath).replace(/\\/g, "/");
6360
6692
  if (relFromSrc.startsWith("..")) {
6361
- return (0, import_node_path22.relative)(rootDir, absPath).replace(/\\/g, "/");
6693
+ return (0, import_node_path26.relative)(rootDir, absPath).replace(/\\/g, "/");
6362
6694
  }
6363
6695
  return relFromSrc;
6364
6696
  }
@@ -6446,18 +6778,18 @@ function collectDeclaredEnvKeys(rootDir) {
6446
6778
  const files = [];
6447
6779
  let entries = [];
6448
6780
  try {
6449
- entries = (0, import_node_fs19.readdirSync)(rootDir);
6781
+ entries = (0, import_node_fs21.readdirSync)(rootDir);
6450
6782
  } catch {
6451
6783
  return { keys, files };
6452
6784
  }
6453
6785
  for (const name of entries) {
6454
6786
  if (!name.startsWith(".env")) continue;
6455
- const abs = (0, import_node_path22.join)(rootDir, name);
6456
- if (!(0, import_node_fs19.existsSync)(abs)) continue;
6787
+ const abs = (0, import_node_path26.join)(rootDir, name);
6788
+ if (!(0, import_node_fs21.existsSync)(abs)) continue;
6457
6789
  files.push(name);
6458
6790
  let content = "";
6459
6791
  try {
6460
- content = (0, import_node_fs19.readFileSync)(abs, "utf-8");
6792
+ content = (0, import_node_fs21.readFileSync)(abs, "utf-8");
6461
6793
  } catch {
6462
6794
  continue;
6463
6795
  }
@@ -6611,12 +6943,12 @@ function checkHardcodedUrlFallback(rootDir, core) {
6611
6943
  }
6612
6944
  return core.buildReport("security", "hardcoded_url_fallback", findings);
6613
6945
  }
6614
- var import_node_fs19, import_node_path22, SECRET_KEY_RE, SECRET_KEY_ALLOWLIST, FRAMEWORK_ENV_KEYS;
6946
+ var import_node_fs21, import_node_path26, SECRET_KEY_RE, SECRET_KEY_ALLOWLIST, FRAMEWORK_ENV_KEYS;
6615
6947
  var init_audit_security = __esm({
6616
6948
  "src/server/graph/core/audit-security.ts"() {
6617
6949
  "use strict";
6618
- import_node_fs19 = require("node:fs");
6619
- import_node_path22 = require("node:path");
6950
+ import_node_fs21 = require("node:fs");
6951
+ import_node_path26 = require("node:path");
6620
6952
  init_ts_extractor();
6621
6953
  init_config();
6622
6954
  init_resolve_paths();
@@ -6678,10 +7010,10 @@ var init_audit_security = __esm({
6678
7010
 
6679
7011
  // src/server/graph/core/audit-core.ts
6680
7012
  function readGraphFile(rootDir, layer) {
6681
- const filePath = (0, import_node_path23.join)(rootDir, LAUNCHSECURE_DIR, "graphs", `${layer}.json`);
6682
- if (!(0, import_node_fs20.existsSync)(filePath)) return null;
7013
+ const filePath = (0, import_node_path27.join)(rootDir, LAUNCHSECURE_DIR, "graphs", `${layer}.json`);
7014
+ if (!(0, import_node_fs22.existsSync)(filePath)) return null;
6683
7015
  try {
6684
- return JSON.parse((0, import_node_fs20.readFileSync)(filePath, "utf-8"));
7016
+ return JSON.parse((0, import_node_fs22.readFileSync)(filePath, "utf-8"));
6685
7017
  } catch {
6686
7018
  return null;
6687
7019
  }
@@ -6723,20 +7055,20 @@ function checkUnprotectedRoutes(rootDir) {
6723
7055
  const findings = [];
6724
7056
  const api = readGraphFile(rootDir, "api");
6725
7057
  if (!api) return buildSkipped("api", "unprotected_routes", "no api graph");
6726
- const routePermsPath = (0, import_node_path23.join)(rootDir, "src", "config", "route-permissions.ts");
6727
- if (!(0, import_node_fs20.existsSync)(routePermsPath)) {
7058
+ const routePermsPath = (0, import_node_path27.join)(rootDir, "src", "config", "route-permissions.ts");
7059
+ if (!(0, import_node_fs22.existsSync)(routePermsPath)) {
6728
7060
  return buildSkipped(
6729
7061
  "api",
6730
7062
  "unprotected_routes",
6731
7063
  `no src/config/route-permissions.ts \u2014 this check needs a centralized ROUTE_PERMISSIONS inventory to compare endpoints against`
6732
7064
  );
6733
7065
  }
6734
- const routePermsContent = (0, import_node_fs20.readFileSync)(routePermsPath, "utf-8");
7066
+ const routePermsContent = (0, import_node_fs22.readFileSync)(routePermsPath, "utf-8");
6735
7067
  const registeredRoutes = /* @__PURE__ */ new Set();
6736
7068
  const routeEntryRe = /path:\s*'([^']+)'/g;
6737
- let rm;
6738
- while ((rm = routeEntryRe.exec(routePermsContent)) !== null) {
6739
- registeredRoutes.add(rm[1].replace(/:(\w+)/g, "[$1]"));
7069
+ let rm2;
7070
+ while ((rm2 = routeEntryRe.exec(routePermsContent)) !== null) {
7071
+ registeredRoutes.add(rm2[1].replace(/:(\w+)/g, "[$1]"));
6740
7072
  }
6741
7073
  for (const node of api.nodes) {
6742
7074
  if (node.type !== "endpoint") continue;
@@ -6816,15 +7148,15 @@ function checkUnenforcedPermissions(rootDir) {
6816
7148
  `no seed_permission nodes \u2014 this project either has no seed permissions or hasn't tagged them in seed.ts`
6817
7149
  );
6818
7150
  }
6819
- const routePermsPath = (0, import_node_path23.join)(rootDir, "src", "config", "route-permissions.ts");
6820
- if (!(0, import_node_fs20.existsSync)(routePermsPath)) {
7151
+ const routePermsPath = (0, import_node_path27.join)(rootDir, "src", "config", "route-permissions.ts");
7152
+ if (!(0, import_node_fs22.existsSync)(routePermsPath)) {
6821
7153
  return buildSkipped(
6822
7154
  "static",
6823
7155
  "unenforced_permissions",
6824
7156
  `no src/config/route-permissions.ts to compare seed permissions against`
6825
7157
  );
6826
7158
  }
6827
- const routePermsContent = (0, import_node_fs20.readFileSync)(routePermsPath, "utf-8");
7159
+ const routePermsContent = (0, import_node_fs22.readFileSync)(routePermsPath, "utf-8");
6828
7160
  for (const perm of permissions) {
6829
7161
  const regex = new RegExp(`permission:\\s*['"]${perm.key}['"]`);
6830
7162
  if (!regex.test(routePermsContent)) {
@@ -6860,9 +7192,9 @@ function checkHardcodedValues(rootDir) {
6860
7192
  const seen = /* @__PURE__ */ new Set();
6861
7193
  for (const node of api.nodes) {
6862
7194
  if (node.type !== "endpoint") continue;
6863
- const filePath = (0, import_node_path23.join)(rootDir, "src", node.id);
6864
- if (!(0, import_node_fs20.existsSync)(filePath)) continue;
6865
- const content = (0, import_node_fs20.readFileSync)(filePath, "utf-8");
7195
+ const filePath = (0, import_node_path27.join)(rootDir, "src", node.id);
7196
+ if (!(0, import_node_fs22.existsSync)(filePath)) continue;
7197
+ const content = (0, import_node_fs22.readFileSync)(filePath, "utf-8");
6866
7198
  let m;
6867
7199
  allCapsRe.lastIndex = 0;
6868
7200
  while ((m = allCapsRe.exec(content)) !== null) {
@@ -6981,12 +7313,12 @@ function formatAsPrompt(reports) {
6981
7313
  if (lines.length === 0) return "No audit findings.";
6982
7314
  return lines.join("\n");
6983
7315
  }
6984
- var import_node_fs20, import_node_path23, CHECKS;
7316
+ var import_node_fs22, import_node_path27, CHECKS;
6985
7317
  var init_audit_core = __esm({
6986
7318
  "src/server/graph/core/audit-core.ts"() {
6987
7319
  "use strict";
6988
- import_node_fs20 = require("node:fs");
6989
- import_node_path23 = require("node:path");
7320
+ import_node_fs22 = require("node:fs");
7321
+ import_node_path27 = require("node:path");
6990
7322
  init_launch_kit_paths();
6991
7323
  init_audit_security();
6992
7324
  CHECKS = {
@@ -7025,16 +7357,16 @@ function randomPort() {
7025
7357
  function findProjectRoot(startDir) {
7026
7358
  let dir = startDir;
7027
7359
  for (let i = 0; i < 8; i++) {
7028
- const graphsDir2 = import_node_path24.default.join(dir, LAUNCHSECURE_DIR, "graphs");
7029
- if (import_node_fs21.default.existsSync(import_node_path24.default.join(graphsDir2, "ui.json")) || import_node_fs21.default.existsSync(import_node_path24.default.join(graphsDir2, "api.json")) || import_node_fs21.default.existsSync(import_node_path24.default.join(graphsDir2, "db.json"))) return dir;
7030
- const parent = import_node_path24.default.dirname(dir);
7360
+ const graphsDir2 = import_node_path28.default.join(dir, LAUNCHSECURE_DIR, "graphs");
7361
+ if (import_node_fs23.default.existsSync(import_node_path28.default.join(graphsDir2, "ui.json")) || import_node_fs23.default.existsSync(import_node_path28.default.join(graphsDir2, "api.json")) || import_node_fs23.default.existsSync(import_node_path28.default.join(graphsDir2, "db.json"))) return dir;
7362
+ const parent = import_node_path28.default.dirname(dir);
7031
7363
  if (parent === dir) break;
7032
7364
  dir = parent;
7033
7365
  }
7034
7366
  dir = startDir;
7035
7367
  for (let i = 0; i < 8; i++) {
7036
- if (import_node_fs21.default.existsSync(import_node_path24.default.join(dir, ".git"))) return dir;
7037
- const parent = import_node_path24.default.dirname(dir);
7368
+ if (import_node_fs23.default.existsSync(import_node_path28.default.join(dir, ".git"))) return dir;
7369
+ const parent = import_node_path28.default.dirname(dir);
7038
7370
  if (parent === dir) break;
7039
7371
  dir = parent;
7040
7372
  }
@@ -7043,7 +7375,7 @@ function findProjectRoot(startDir) {
7043
7375
  function resolveRequestRoot(url, monorepoRoot, projects) {
7044
7376
  const projectParam = url.searchParams.get("project");
7045
7377
  if (!projectParam || projects.length === 0) return monorepoRoot;
7046
- const resolved = import_node_path24.default.resolve(monorepoRoot, projectParam);
7378
+ const resolved = import_node_path28.default.resolve(monorepoRoot, projectParam);
7047
7379
  if (!resolved.startsWith(monorepoRoot)) {
7048
7380
  throw new Error("Project path outside monorepo root");
7049
7381
  }
@@ -7094,16 +7426,16 @@ async function buildMergedGraph(root) {
7094
7426
  };
7095
7427
  }
7096
7428
  function serveStatic(res, filePath) {
7097
- if (!import_node_fs21.default.existsSync(filePath) || !import_node_fs21.default.statSync(filePath).isFile()) return false;
7098
- const ext = import_node_path24.default.extname(filePath).toLowerCase();
7429
+ if (!import_node_fs23.default.existsSync(filePath) || !import_node_fs23.default.statSync(filePath).isFile()) return false;
7430
+ const ext = import_node_path28.default.extname(filePath).toLowerCase();
7099
7431
  const mime = MIME_TYPES[ext] ?? "application/octet-stream";
7100
7432
  res.writeHead(200, { "Content-Type": mime, "Cache-Control": "no-cache" });
7101
- import_node_fs21.default.createReadStream(filePath).pipe(res);
7433
+ import_node_fs23.default.createReadStream(filePath).pipe(res);
7102
7434
  return true;
7103
7435
  }
7104
7436
  function serveIndex(res, clientDir) {
7105
- const indexPath = import_node_path24.default.join(clientDir, "index.html");
7106
- if (!import_node_fs21.default.existsSync(indexPath)) {
7437
+ const indexPath = import_node_path28.default.join(clientDir, "index.html");
7438
+ if (!import_node_fs23.default.existsSync(indexPath)) {
7107
7439
  res.writeHead(500, { "Content-Type": "text/plain" });
7108
7440
  res.end(`LaunchChart client bundle not found at ${clientDir}. Run 'npm run build:chart-client'.`);
7109
7441
  return;
@@ -7111,14 +7443,14 @@ function serveIndex(res, clientDir) {
7111
7443
  serveStatic(res, indexPath);
7112
7444
  }
7113
7445
  function tryListen(server, port) {
7114
- return new Promise((resolve6, reject) => {
7446
+ return new Promise((resolve7, reject) => {
7115
7447
  const onError = (err2) => {
7116
7448
  server.off("listening", onListening);
7117
7449
  reject(err2);
7118
7450
  };
7119
7451
  const onListening = () => {
7120
7452
  server.off("error", onError);
7121
- resolve6(port);
7453
+ resolve7(port);
7122
7454
  };
7123
7455
  server.once("error", onError);
7124
7456
  server.once("listening", onListening);
@@ -7155,7 +7487,7 @@ async function startChartServer(opts = {}) {
7155
7487
  }
7156
7488
  return { port: existing.port, url: existing.url };
7157
7489
  }
7158
- const clientDir = opts.clientDir ?? import_node_path24.default.join(__dirname, "..", "chart-client");
7490
+ const clientDir = opts.clientDir ?? import_node_path28.default.join(__dirname, "..", "chart-client");
7159
7491
  const rootConfig = loadConfig(projectRoot);
7160
7492
  const projects = rootConfig.projects ?? [];
7161
7493
  const server = import_node_http.default.createServer((req, res) => {
@@ -7171,11 +7503,11 @@ async function startChartServer(opts = {}) {
7171
7503
  }
7172
7504
  if (req.method === "GET" && url2.pathname === "/api/projects") {
7173
7505
  const projectList = projects.length > 0 ? projects.map((p) => {
7174
- const absRoot = import_node_path24.default.resolve(projectRoot, p.root);
7175
- const hasGraphs = import_node_fs21.default.existsSync(import_node_path24.default.join(absRoot, LAUNCHSECURE_DIR, "graphs"));
7176
- const hasNextConfig = import_node_fs21.default.existsSync(import_node_path24.default.join(absRoot, "next.config.ts")) || import_node_fs21.default.existsSync(import_node_path24.default.join(absRoot, "next.config.js")) || import_node_fs21.default.existsSync(import_node_path24.default.join(absRoot, "next.config.mjs"));
7506
+ const absRoot = import_node_path28.default.resolve(projectRoot, p.root);
7507
+ const hasGraphs = import_node_fs23.default.existsSync(import_node_path28.default.join(absRoot, LAUNCHSECURE_DIR, "graphs"));
7508
+ const hasNextConfig = import_node_fs23.default.existsSync(import_node_path28.default.join(absRoot, "next.config.ts")) || import_node_fs23.default.existsSync(import_node_path28.default.join(absRoot, "next.config.js")) || import_node_fs23.default.existsSync(import_node_path28.default.join(absRoot, "next.config.mjs"));
7177
7509
  return { name: p.name, root: p.root, hasGraphs, hasNextConfig };
7178
- }) : [{ name: import_node_path24.default.basename(projectRoot), root: ".", hasGraphs: import_node_fs21.default.existsSync(import_node_path24.default.join(projectRoot, LAUNCHSECURE_DIR, "graphs")), hasNextConfig: true }];
7510
+ }) : [{ name: import_node_path28.default.basename(projectRoot), root: ".", hasGraphs: import_node_fs23.default.existsSync(import_node_path28.default.join(projectRoot, LAUNCHSECURE_DIR, "graphs")), hasNextConfig: true }];
7179
7511
  res.writeHead(200, { "Content-Type": "application/json" });
7180
7512
  res.end(JSON.stringify({ projects: projectList, monorepoRoot: projectRoot }));
7181
7513
  return;
@@ -7221,20 +7553,20 @@ async function startChartServer(opts = {}) {
7221
7553
  }
7222
7554
  if (req.method === "GET" && url2.pathname === "/api/file-content") {
7223
7555
  const relPath = url2.searchParams.get("path");
7224
- if (!relPath || relPath.includes("..") || import_node_path24.default.isAbsolute(relPath)) {
7556
+ if (!relPath || relPath.includes("..") || import_node_path28.default.isAbsolute(relPath)) {
7225
7557
  res.writeHead(400, { "Content-Type": "application/json" });
7226
7558
  res.end(JSON.stringify({ error: "Invalid path" }));
7227
7559
  return;
7228
7560
  }
7229
- const filePath = import_node_path24.default.join(reqRoot, relPath);
7230
- if (!filePath.startsWith(reqRoot) || !import_node_fs21.default.existsSync(filePath) || !import_node_fs21.default.statSync(filePath).isFile()) {
7561
+ const filePath = import_node_path28.default.join(reqRoot, relPath);
7562
+ if (!filePath.startsWith(reqRoot) || !import_node_fs23.default.existsSync(filePath) || !import_node_fs23.default.statSync(filePath).isFile()) {
7231
7563
  res.writeHead(404, { "Content-Type": "application/json" });
7232
7564
  res.end(JSON.stringify({ error: "File not found" }));
7233
7565
  return;
7234
7566
  }
7235
- const ext = import_node_path24.default.extname(filePath).toLowerCase();
7567
+ const ext = import_node_path28.default.extname(filePath).toLowerCase();
7236
7568
  const langMap = { ".ts": "typescript", ".tsx": "tsx", ".js": "javascript", ".jsx": "jsx", ".prisma": "prisma", ".json": "json", ".css": "css" };
7237
- const content = import_node_fs21.default.readFileSync(filePath, "utf-8");
7569
+ const content = import_node_fs23.default.readFileSync(filePath, "utf-8");
7238
7570
  res.writeHead(200, { "Content-Type": "application/json" });
7239
7571
  res.end(JSON.stringify({ content, language: langMap[ext] ?? "text", path: relPath }));
7240
7572
  return;
@@ -7289,8 +7621,8 @@ async function startChartServer(opts = {}) {
7289
7621
  const newConfig = JSON.parse(body);
7290
7622
  const existingConfig = loadConfig(reqRoot);
7291
7623
  const merged = { ...existingConfig, ...newConfig };
7292
- const configPath = import_node_path24.default.join(reqRoot, LAUNCHCHART_CONFIG_FILE);
7293
- import_node_fs21.default.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
7624
+ const configPath = import_node_path28.default.join(reqRoot, LAUNCHCHART_CONFIG_FILE);
7625
+ import_node_fs23.default.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
7294
7626
  res.writeHead(200, { "Content-Type": "application/json" });
7295
7627
  res.end(JSON.stringify({ ok: true }));
7296
7628
  } catch (err2) {
@@ -7323,8 +7655,8 @@ async function startChartServer(opts = {}) {
7323
7655
  const taggerConfig = JSON.parse(body);
7324
7656
  const config2 = loadConfig(reqRoot);
7325
7657
  config2.taggers = taggerConfig;
7326
- const configPath = import_node_path24.default.join(reqRoot, LAUNCHCHART_CONFIG_FILE);
7327
- import_node_fs21.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
7658
+ const configPath = import_node_path28.default.join(reqRoot, LAUNCHCHART_CONFIG_FILE);
7659
+ import_node_fs23.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
7328
7660
  res.writeHead(200, { "Content-Type": "application/json" });
7329
7661
  res.end(JSON.stringify({ ok: true }));
7330
7662
  } catch (err2) {
@@ -7394,7 +7726,7 @@ async function startChartServer(opts = {}) {
7394
7726
  dbDir: !!config2.paths?.dbDir,
7395
7727
  srcRoots: !!(config2.paths?.srcRoots && config2.paths.srcRoots.length > 0)
7396
7728
  };
7397
- const relFromRoot = (abs) => import_node_path24.default.relative(reqRoot, abs) || ".";
7729
+ const relFromRoot = (abs) => import_node_path28.default.relative(reqRoot, abs) || ".";
7398
7730
  res.writeHead(200, { "Content-Type": "application/json" });
7399
7731
  res.end(JSON.stringify({
7400
7732
  projectRoot: reqRoot,
@@ -7416,19 +7748,19 @@ async function startChartServer(opts = {}) {
7416
7748
  }
7417
7749
  if (req.method === "GET" && url2.pathname === "/api/browse-dir") {
7418
7750
  const browsePath = url2.searchParams.get("path") || projectRoot;
7419
- const abs = import_node_path24.default.resolve(browsePath);
7420
- const twoUp = import_node_path24.default.resolve(projectRoot, "..", "..");
7751
+ const abs = import_node_path28.default.resolve(browsePath);
7752
+ const twoUp = import_node_path28.default.resolve(projectRoot, "..", "..");
7421
7753
  if (!abs.startsWith(twoUp)) {
7422
7754
  res.writeHead(403, { "Content-Type": "application/json" });
7423
7755
  res.end(JSON.stringify({ ok: false, error: "Path outside allowed range" }));
7424
7756
  return;
7425
7757
  }
7426
7758
  try {
7427
- const entries = import_node_fs21.default.readdirSync(abs, { withFileTypes: true });
7759
+ const entries = import_node_fs23.default.readdirSync(abs, { withFileTypes: true });
7428
7760
  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();
7429
- const parent = abs !== twoUp ? import_node_path24.default.dirname(abs) : null;
7761
+ const parent = abs !== twoUp ? import_node_path28.default.dirname(abs) : null;
7430
7762
  res.writeHead(200, { "Content-Type": "application/json" });
7431
- res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path24.default.relative(projectRoot, abs) || "." }));
7763
+ res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path28.default.relative(projectRoot, abs) || "." }));
7432
7764
  } catch (err2) {
7433
7765
  res.writeHead(400, { "Content-Type": "application/json" });
7434
7766
  res.end(JSON.stringify({ ok: false, error: String(err2) }));
@@ -7454,8 +7786,8 @@ async function startChartServer(opts = {}) {
7454
7786
  const { projects: newProjects } = JSON.parse(body);
7455
7787
  const config2 = loadConfig(projectRoot);
7456
7788
  config2.projects = newProjects.length > 0 ? newProjects : void 0;
7457
- const configPath = import_node_path24.default.join(projectRoot, LAUNCHCHART_CONFIG_FILE);
7458
- import_node_fs21.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
7789
+ const configPath = import_node_path28.default.join(projectRoot, LAUNCHCHART_CONFIG_FILE);
7790
+ import_node_fs23.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
7459
7791
  projects.length = 0;
7460
7792
  if (config2.projects) projects.push(...config2.projects);
7461
7793
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -7468,7 +7800,7 @@ async function startChartServer(opts = {}) {
7468
7800
  return;
7469
7801
  }
7470
7802
  if (url2.pathname !== "/") {
7471
- const staticPath = import_node_path24.default.join(clientDir, url2.pathname);
7803
+ const staticPath = import_node_path28.default.join(clientDir, url2.pathname);
7472
7804
  if (serveStatic(res, staticPath)) return;
7473
7805
  }
7474
7806
  serveIndex(res, clientDir);
@@ -7528,13 +7860,13 @@ function runServeCli(argv) {
7528
7860
  process.exit(1);
7529
7861
  });
7530
7862
  }
7531
- var import_node_http, import_node_fs21, import_node_path24, MAX_PORT_SCAN, MIME_TYPES;
7863
+ var import_node_http, import_node_fs23, import_node_path28, MAX_PORT_SCAN, MIME_TYPES;
7532
7864
  var init_chart_serve = __esm({
7533
7865
  "src/server/chart-serve.ts"() {
7534
7866
  "use strict";
7535
7867
  import_node_http = __toESM(require("node:http"));
7536
- import_node_fs21 = __toESM(require("node:fs"));
7537
- import_node_path24 = __toESM(require("node:path"));
7868
+ import_node_fs23 = __toESM(require("node:fs"));
7869
+ import_node_path28 = __toESM(require("node:path"));
7538
7870
  init_launch_kit_paths();
7539
7871
  init_graph();
7540
7872
  init_freshness();
@@ -7563,9 +7895,9 @@ function emptyRegistry() {
7563
7895
  return { version: 1, worktrees: {} };
7564
7896
  }
7565
7897
  function readRegistry() {
7566
- if (!(0, import_node_fs22.existsSync)(REGISTRY_PATH)) return emptyRegistry();
7898
+ if (!(0, import_node_fs24.existsSync)(REGISTRY_PATH)) return emptyRegistry();
7567
7899
  try {
7568
- const parsed = JSON.parse((0, import_node_fs22.readFileSync)(REGISTRY_PATH, "utf-8"));
7900
+ const parsed = JSON.parse((0, import_node_fs24.readFileSync)(REGISTRY_PATH, "utf-8"));
7569
7901
  if (parsed?.version === 1 && parsed.worktrees && typeof parsed.worktrees === "object") {
7570
7902
  return parsed;
7571
7903
  }
@@ -7576,17 +7908,17 @@ function readRegistry() {
7576
7908
  function listWorktrees() {
7577
7909
  return Object.values(readRegistry().worktrees);
7578
7910
  }
7579
- var import_node_fs22, import_node_os2, import_node_path25, REGISTRY_DIR, REGISTRY_PATH, LOCK_PATH;
7580
- var init_registry = __esm({
7911
+ var import_node_fs24, import_node_os3, import_node_path29, REGISTRY_DIR, REGISTRY_PATH, LOCK_PATH;
7912
+ var init_registry2 = __esm({
7581
7913
  "src/server/orbit/registry.ts"() {
7582
7914
  "use strict";
7583
- import_node_fs22 = require("node:fs");
7584
- import_node_os2 = require("node:os");
7585
- import_node_path25 = require("node:path");
7915
+ import_node_fs24 = require("node:fs");
7916
+ import_node_os3 = require("node:os");
7917
+ import_node_path29 = require("node:path");
7586
7918
  init_launch_kit_paths();
7587
- REGISTRY_DIR = (0, import_node_path25.join)((0, import_node_os2.homedir)(), LAUNCHSECURE_DIR, "orbit");
7588
- REGISTRY_PATH = (0, import_node_path25.join)(REGISTRY_DIR, "state.json");
7589
- LOCK_PATH = (0, import_node_path25.join)(REGISTRY_DIR, "state.json.lock");
7919
+ REGISTRY_DIR = (0, import_node_path29.join)((0, import_node_os3.homedir)(), LAUNCHSECURE_DIR, "orbit");
7920
+ REGISTRY_PATH = (0, import_node_path29.join)(REGISTRY_DIR, "state.json");
7921
+ LOCK_PATH = (0, import_node_path29.join)(REGISTRY_DIR, "state.json.lock");
7590
7922
  }
7591
7923
  });
7592
7924
 
@@ -7606,7 +7938,7 @@ function resolveWorktreeRoot(slug, monorepoRoot) {
7606
7938
  function resolveWorktreeOrProjectRoot(args, monorepoRoot) {
7607
7939
  const projectRoot = typeof args.project_root === "string" ? args.project_root.trim() : "";
7608
7940
  if (projectRoot) {
7609
- return (0, import_node_path26.isAbsolute)(projectRoot) ? projectRoot : (0, import_node_path26.resolve)(monorepoRoot, projectRoot);
7941
+ return (0, import_node_path30.isAbsolute)(projectRoot) ? projectRoot : (0, import_node_path30.resolve)(monorepoRoot, projectRoot);
7610
7942
  }
7611
7943
  const worktree = typeof args.worktree === "string" ? args.worktree.trim() : "";
7612
7944
  if (worktree) {
@@ -7614,12 +7946,12 @@ function resolveWorktreeOrProjectRoot(args, monorepoRoot) {
7614
7946
  }
7615
7947
  return null;
7616
7948
  }
7617
- var import_node_path26, WORKTREE_PARAM_DESCRIPTION, PROJECT_ROOT_PARAM_DESCRIPTION;
7949
+ var import_node_path30, WORKTREE_PARAM_DESCRIPTION, PROJECT_ROOT_PARAM_DESCRIPTION;
7618
7950
  var init_worktree = __esm({
7619
7951
  "src/server/lib/worktree.ts"() {
7620
7952
  "use strict";
7621
- import_node_path26 = require("node:path");
7622
- init_registry();
7953
+ import_node_path30 = require("node:path");
7954
+ init_registry2();
7623
7955
  WORKTREE_PARAM_DESCRIPTION = "Optional orbit worktree slug (from `launch-orbit create`). Resolves to the worktree's path via the orbit registry (~/.launchsecure/orbit/state.json). Lets you query a worktree's state from a Claude Code session pinned to the main repo. Superseded by `project_root`.";
7624
7956
  PROJECT_ROOT_PARAM_DESCRIPTION = "Optional explicit project root. Accepts an absolute path or a path relative to the monorepo root. Escape hatch when `worktree` doesn't fit. Takes precedence over all other root args.";
7625
7957
  }
@@ -7632,7 +7964,7 @@ function listProjects(monorepoRoot) {
7632
7964
  return entries.map((p) => ({
7633
7965
  name: p.name,
7634
7966
  root: p.root,
7635
- absoluteRoot: (0, import_node_path27.resolve)(monorepoRoot, p.root)
7967
+ absoluteRoot: (0, import_node_path31.resolve)(monorepoRoot, p.root)
7636
7968
  }));
7637
7969
  }
7638
7970
  function resolveProject(name, projects) {
@@ -7660,11 +7992,11 @@ function resolveRequestRoot2(args, monorepoRoot) {
7660
7992
  const project = typeof args.project === "string" ? args.project : void 0;
7661
7993
  return resolveProjectRoot(project, monorepoRoot);
7662
7994
  }
7663
- var import_node_path27, WORKTREE_PARAM_DESCRIPTION2, PROJECT_ROOT_PARAM_DESCRIPTION2, PROJECT_PARAM_DESCRIPTION;
7995
+ var import_node_path31, WORKTREE_PARAM_DESCRIPTION2, PROJECT_ROOT_PARAM_DESCRIPTION2, PROJECT_PARAM_DESCRIPTION;
7664
7996
  var init_projects = __esm({
7665
7997
  "src/server/graph/core/projects.ts"() {
7666
7998
  "use strict";
7667
- import_node_path27 = require("node:path");
7999
+ import_node_path31 = require("node:path");
7668
8000
  init_worktree();
7669
8001
  init_config();
7670
8002
  WORKTREE_PARAM_DESCRIPTION2 = WORKTREE_PARAM_DESCRIPTION;
@@ -7804,13 +8136,51 @@ var init_graph_cli = __esm({
7804
8136
  }
7805
8137
  });
7806
8138
 
8139
+ // src/server/graph/core/context/snippet.ts
8140
+ function toExportName(name) {
8141
+ const words = name.replace(/^action:/, "").replace(/^state:/, "").split(/[^A-Za-z0-9]+/).filter(Boolean).filter((w) => w.toLowerCase() !== "api");
8142
+ if (words.length === 0) return "snippet";
8143
+ const camel = words.map((w, i) => i === 0 ? w.charAt(0).toLowerCase() + w.slice(1) : w.charAt(0).toUpperCase() + w.slice(1)).join("");
8144
+ return /^[0-9]/.test(camel) ? `s${camel}` : camel;
8145
+ }
8146
+ function scaffoldSnippet(input) {
8147
+ const exportName = toExportName(input.name || input.nodeId);
8148
+ const arr = (xs) => `[${xs.map((x) => `'${x}'`).join(", ")}]`;
8149
+ const code = `import { type Page } from '@playwright/test';
8150
+
8151
+ /**
8152
+ * Snippet: ${input.name}
8153
+ * Scaffolded by launch-chart \`scaffold_snippet\` \u2014 conforms to the Snippet shape.
8154
+ * requires/produces are derived from the context graph. TODO(you):
8155
+ * 1. fill \`params\` from the endpoint's request/validation schema;
8156
+ * 2. implement \`run()\` with real Playwright steps (navigate, fill, click, assert).
8157
+ */
8158
+ export const ${exportName} = {
8159
+ id: '${input.nodeId}',
8160
+ requires: ${arr(input.requires)},
8161
+ produces: ${arr(input.produces)},
8162
+ params: [], // TODO: e.g. ['name', 'color'] \u2014 from the endpoint schema
8163
+ async run(page: Page, params: Record<string, unknown>) {
8164
+ // TODO: implement with Playwright.
8165
+ // e.g. await page.goto('/...'); await page.fill('#...', params.x); await page.click('text=Save');
8166
+ },
8167
+ };
8168
+ `;
8169
+ return { exportName, code };
8170
+ }
8171
+ var init_snippet = __esm({
8172
+ "src/server/graph/core/context/snippet.ts"() {
8173
+ "use strict";
8174
+ }
8175
+ });
8176
+
7807
8177
  // src/server/graph/core/language-detection.ts
7808
8178
  function walkForExtensions(dir, extCounts, depth = 0) {
7809
8179
  if (depth > 10) return;
7810
- if (!(0, import_node_fs23.existsSync)(dir)) return;
8180
+ if (!(0, import_node_fs25.existsSync)(dir)) return;
7811
8181
  let entries;
7812
8182
  try {
7813
- entries = (0, import_node_fs23.readdirSync)(dir, { withFileTypes: true });
8183
+ entries = (0, import_node_fs25.readdirSync)(dir, { withFileTypes: true });
7814
8184
  } catch {
7815
8185
  return;
7816
8186
  }
@@ -7818,9 +8188,9 @@ function walkForExtensions(dir, extCounts, depth = 0) {
7818
8188
  if (entry.name.startsWith(".") && entry.isDirectory()) continue;
7819
8189
  if (entry.isDirectory()) {
7820
8190
  if (IGNORE_DIRS.has(entry.name)) continue;
7821
- walkForExtensions((0, import_node_path28.join)(dir, entry.name), extCounts, depth + 1);
8191
+ walkForExtensions((0, import_node_path32.join)(dir, entry.name), extCounts, depth + 1);
7822
8192
  } else {
7823
- const ext = (0, import_node_path28.extname)(entry.name).toLowerCase();
8193
+ const ext = (0, import_node_path32.extname)(entry.name).toLowerCase();
7824
8194
  if (ext && EXTENSION_TO_LANGUAGE[ext]) {
7825
8195
  extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
7826
8196
  }
@@ -7859,12 +8229,12 @@ function detectLanguages(rootDir, supportedLanguages) {
7859
8229
  });
7860
8230
  return results;
7861
8231
  }
7862
- var import_node_fs23, import_node_path28, EXTENSION_TO_LANGUAGE, IGNORE_DIRS, AUXILIARY_LANGUAGES;
8232
+ var import_node_fs25, import_node_path32, EXTENSION_TO_LANGUAGE, IGNORE_DIRS, AUXILIARY_LANGUAGES;
7863
8233
  var init_language_detection = __esm({
7864
8234
  "src/server/graph/core/language-detection.ts"() {
7865
8235
  "use strict";
7866
- import_node_fs23 = require("node:fs");
7867
- import_node_path28 = require("node:path");
8236
+ import_node_fs25 = require("node:fs");
8237
+ import_node_path32 = require("node:path");
7868
8238
  init_launch_kit_paths();
7869
8239
  EXTENSION_TO_LANGUAGE = {
7870
8240
  // Web / Frontend
@@ -7986,7 +8356,7 @@ __export(watcher_exports, {
7986
8356
  function isIgnoredPath(rel) {
7987
8357
  if (rel.startsWith(GRAPHS_RELATIVE)) return true;
7988
8358
  if (rel.endsWith(".lock") || rel.endsWith(".log")) return true;
7989
- for (const part of rel.split(import_node_path29.sep)) {
8359
+ for (const part of rel.split(import_node_path33.sep)) {
7990
8360
  if (IGNORE_SEGMENTS.has(part)) return true;
7991
8361
  }
7992
8362
  return false;
@@ -8028,7 +8398,7 @@ function startGraphWatcher(rootDir, opts = {}) {
8028
8398
  regenerating = false;
8029
8399
  }
8030
8400
  }
8031
- const watcher = (0, import_node_fs24.watch)(rootDir, { recursive: true }, (event, filename) => {
8401
+ const watcher = (0, import_node_fs26.watch)(rootDir, { recursive: true }, (event, filename) => {
8032
8402
  if (!filename) return;
8033
8403
  const rel = filename.toString();
8034
8404
  if (process.env.LAUNCH_CHART_WATCH_TRACE === "1") {
@@ -8061,12 +8431,12 @@ function startGraphWatcher(rootDir, opts = {}) {
8061
8431
  freshness: () => getFreshnessTracker(rootDir).get()
8062
8432
  };
8063
8433
  }
8064
- var import_node_fs24, import_node_path29, IGNORE_SEGMENTS, TRIGGER_EXTENSIONS, GRAPHS_RELATIVE;
8434
+ var import_node_fs26, import_node_path33, IGNORE_SEGMENTS, TRIGGER_EXTENSIONS, GRAPHS_RELATIVE;
8065
8435
  var init_watcher = __esm({
8066
8436
  "src/server/graph/core/watcher.ts"() {
8067
8437
  "use strict";
8068
- import_node_fs24 = require("node:fs");
8069
- import_node_path29 = require("node:path");
8438
+ import_node_fs26 = require("node:fs");
8439
+ import_node_path33 = require("node:path");
8070
8440
  init_launch_kit_paths();
8071
8441
  init_graph();
8072
8442
  init_freshness();
@@ -8095,7 +8465,7 @@ var init_watcher = __esm({
8095
8465
  ".prisma",
8096
8466
  ".sql"
8097
8467
  ]);
8098
- GRAPHS_RELATIVE = (0, import_node_path29.join)(LAUNCHSECURE_DIR, "graphs");
8468
+ GRAPHS_RELATIVE = (0, import_node_path33.join)(LAUNCHSECURE_DIR, "graphs");
8099
8469
  }
8100
8470
  });
8101
8471
 
@@ -8828,12 +9198,12 @@ function handleReadGraph(args) {
8828
9198
  return okJson(result);
8829
9199
  }
8830
9200
  function nodeToFilePath(rootDir, layer, nodeId) {
8831
- if (layer === "ui" || layer === "api") return (0, import_node_path30.join)(rootDir, "src", nodeId);
8832
- if (layer === "db") return (0, import_node_path30.join)(rootDir, "prisma", "schema.prisma");
8833
- const withSrc = (0, import_node_path30.join)(rootDir, "src", nodeId);
8834
- if ((0, import_node_fs25.existsSync)(withSrc)) return withSrc;
8835
- const direct = (0, import_node_path30.join)(rootDir, nodeId);
8836
- if ((0, import_node_fs25.existsSync)(direct)) return direct;
9201
+ if (layer === "ui" || layer === "api") return (0, import_node_path34.join)(rootDir, "src", nodeId);
9202
+ if (layer === "db") return (0, import_node_path34.join)(rootDir, "prisma", "schema.prisma");
9203
+ const withSrc = (0, import_node_path34.join)(rootDir, "src", nodeId);
9204
+ if ((0, import_node_fs27.existsSync)(withSrc)) return withSrc;
9205
+ const direct = (0, import_node_path34.join)(rootDir, nodeId);
9206
+ if ((0, import_node_fs27.existsSync)(direct)) return direct;
8837
9207
  return null;
8838
9208
  }
8839
9209
  function handleInspectNode(args) {
@@ -9101,11 +9471,11 @@ function handleGrepNodes(args) {
9101
9471
  let filesSearched = 0;
9102
9472
  let truncated = false;
9103
9473
  for (const [filePath, nodeId] of filePaths) {
9104
- if (!(0, import_node_fs25.existsSync)(filePath)) continue;
9474
+ if (!(0, import_node_fs27.existsSync)(filePath)) continue;
9105
9475
  filesSearched++;
9106
9476
  let content;
9107
9477
  try {
9108
- content = (0, import_node_fs25.readFileSync)(filePath, "utf-8");
9478
+ content = (0, import_node_fs27.readFileSync)(filePath, "utf-8");
9109
9479
  } catch {
9110
9480
  continue;
9111
9481
  }
@@ -9324,11 +9694,11 @@ function handleStartChartServer(args) {
9324
9694
  });
9325
9695
  }
9326
9696
  const entryPath = process.argv[1];
9327
- const logDir = (0, import_node_path30.join)((0, import_node_os3.homedir)(), LAUNCHSECURE_DIR);
9328
- (0, import_node_fs25.mkdirSync)(logDir, { recursive: true });
9329
- const logPath = (0, import_node_path30.join)(logDir, "launch-chart.log");
9330
- const out = (0, import_node_fs25.openSync)(logPath, "a");
9331
- const err2 = (0, import_node_fs25.openSync)(logPath, "a");
9697
+ const logDir = (0, import_node_path34.join)((0, import_node_os4.homedir)(), LAUNCHSECURE_DIR);
9698
+ (0, import_node_fs27.mkdirSync)(logDir, { recursive: true });
9699
+ const logPath = (0, import_node_path34.join)(logDir, "launch-chart.log");
9700
+ const out = (0, import_node_fs27.openSync)(logPath, "a");
9701
+ const err2 = (0, import_node_fs27.openSync)(logPath, "a");
9332
9702
  const portArgs = args.port ? ["--port", String(args.port)] : [];
9333
9703
  const child = (0, import_node_child_process2.spawn)(process.execPath, [entryPath, "serve", ...portArgs], {
9334
9704
  detached: true,
@@ -9506,6 +9876,42 @@ function handleDriftReport(args) {
9506
9876
  items: page
9507
9877
  });
9508
9878
  }
9879
+ function handleScaffoldSnippet(args) {
9880
+ const __resolved = resolveOrErr(args);
9881
+ if ("content" in __resolved) return __resolved;
9882
+ const { rootDir } = __resolved;
9883
+ const target = typeof args.target === "string" ? args.target.trim() : "";
9884
+ if (!target) return err('target is required (a context node id, e.g. "action:app/api/.../tags/route.ts").');
9885
+ const g = readGraph(rootDir, "context");
9886
+ if (!g) return err("No `context` layer found. Run generate_graph first to build context.json.");
9887
+ let node = g.nodes.find((n) => n.id === target);
9888
+ if (!node && !target.startsWith("action:") && !target.startsWith("state:")) {
9889
+ node = g.nodes.find((n) => n.id === `action:${target}`) ?? g.nodes.find((n) => n.id === `state:${target}`);
9890
+ }
9891
+ if (!node) return err(`No context node matching "${target}". Use read_graph layer:context to list nodes.`);
9892
+ const out = g.edges.filter((e) => e.source === node.id);
9893
+ const tokensOf = (type) => [...new Set(out.filter((e) => e.type === type).map((e) => String(e.target).replace(/^state:/, "")))].sort();
9894
+ const requires = tokensOf("requires");
9895
+ const produces = tokensOf("produces");
9896
+ const { exportName, code } = scaffoldSnippet({
9897
+ nodeId: node.id,
9898
+ name: String(node.name ?? node.id),
9899
+ requires,
9900
+ produces
9901
+ });
9902
+ const requiresDetail = out.filter((e) => e.type === "requires").map((e) => ({ state: String(e.target).replace(/^state:/, ""), confidence: e.confidence ?? "low", origin: e.origin ?? null }));
9903
+ return okJson({
9904
+ target: node.id,
9905
+ name: node.name ?? node.id,
9906
+ requires,
9907
+ produces,
9908
+ requires_detail: requiresDetail,
9909
+ export_name: exportName,
9910
+ suggested_path: `tests/snippets/${exportName}.ts`,
9911
+ snippet: code,
9912
+ next: "Fill `params` from the endpoint request/validation schema and implement run() with Playwright, then write the file to suggested_path."
9913
+ });
9914
+ }
9509
9915
  function handleWhoUses(args) {
9510
9916
  const __resolved = resolveOrErr(args);
9511
9917
  if ("content" in __resolved) return __resolved;
@@ -9751,20 +10157,20 @@ function handleDetectProjectStack() {
9751
10157
  if (ref.type === "references_api") stats.references_api++;
9752
10158
  }
9753
10159
  }
9754
- const srcDir = (0, import_node_path30.join)(rootDir, "src");
9755
- if ((0, import_node_fs25.existsSync)(srcDir)) {
10160
+ const srcDir = (0, import_node_path34.join)(rootDir, "src");
10161
+ if ((0, import_node_fs27.existsSync)(srcDir)) {
9756
10162
  const scanDir = (dir) => {
9757
- if (!(0, import_node_fs25.existsSync)(dir)) return;
9758
- for (const entry of (0, import_node_fs25.readdirSync)(dir, { withFileTypes: true })) {
10163
+ if (!(0, import_node_fs27.existsSync)(dir)) return;
10164
+ for (const entry of (0, import_node_fs27.readdirSync)(dir, { withFileTypes: true })) {
9759
10165
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
9760
- const full = (0, import_node_path30.join)(dir, entry.name);
10166
+ const full = (0, import_node_path34.join)(dir, entry.name);
9761
10167
  if (entry.isDirectory()) {
9762
10168
  scanDir(full);
9763
10169
  continue;
9764
10170
  }
9765
- if (![".ts", ".tsx"].includes((0, import_node_path30.extname)(entry.name))) continue;
10171
+ if (![".ts", ".tsx"].includes((0, import_node_path34.extname)(entry.name))) continue;
9766
10172
  try {
9767
- const content = (0, import_node_fs25.readFileSync)(full, "utf-8");
10173
+ const content = (0, import_node_fs27.readFileSync)(full, "utf-8");
9768
10174
  const matches = content.match(/@api\s+(GET|POST|PUT|DELETE|PATCH)\s+\/\S+/g);
9769
10175
  if (matches) stats.annotations += matches.length;
9770
10176
  } catch {
@@ -9783,7 +10189,7 @@ function handleDetectProjectStack() {
9783
10189
  name: p.name,
9784
10190
  root: p.root,
9785
10191
  absolute_root: p.absoluteRoot,
9786
- has_graph: (0, import_node_fs25.existsSync)((0, import_node_path30.join)(p.absoluteRoot, LAUNCHSECURE_DIR, "graphs"))
10192
+ has_graph: (0, import_node_fs27.existsSync)((0, import_node_path34.join)(p.absoluteRoot, LAUNCHSECURE_DIR, "graphs"))
9787
10193
  }));
9788
10194
  return okJson({
9789
10195
  languages,
@@ -9913,6 +10319,10 @@ async function handleMessage(msg) {
9913
10319
  respond(id ?? null, withFreshnessMeta(handleWhoUses(args), args));
9914
10320
  return;
9915
10321
  }
10322
+ if (toolName === "scaffold_snippet") {
10323
+ respond(id ?? null, withFreshnessMeta(handleScaffoldSnippet(args), args));
10324
+ return;
10325
+ }
9916
10326
  if (toolName === "trace_path") {
9917
10327
  respond(id ?? null, withFreshnessMeta(handleTracePath(args), args));
9918
10328
  return;
@@ -9981,16 +10391,17 @@ function startGraphMcpServer() {
9981
10391
  process.stderr.write(`[launchsecure-graph] MCP server started (cwd: ${process.cwd()})
9982
10392
  `);
9983
10393
  }
9984
- var import_node_fs25, import_node_path30, import_node_child_process2, import_node_os3, SERVER_INFO, TOOLS, MINIMAL_STRIP_FIELDS, COMPACT_SCHEMA, COMPACT_NODE_KNOWN_KEYS, DEEP_FIELDS, NOTE_KIND_CATEGORY, 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, MAX_FILTER_EDGES, BATCH_BUDGET_CHARS, watcherHandle;
10394
+ var import_node_fs27, import_node_path34, import_node_child_process2, import_node_os4, SERVER_INFO, TOOLS, MINIMAL_STRIP_FIELDS, COMPACT_SCHEMA, COMPACT_NODE_KNOWN_KEYS, DEEP_FIELDS, NOTE_KIND_CATEGORY, 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, MAX_FILTER_EDGES, BATCH_BUDGET_CHARS, watcherHandle;
9985
10395
  var init_graph_mcp = __esm({
9986
10396
  "src/server/graph-mcp.ts"() {
9987
10397
  "use strict";
9988
- import_node_fs25 = require("node:fs");
9989
- import_node_path30 = require("node:path");
10398
+ import_node_fs27 = require("node:fs");
10399
+ import_node_path34 = require("node:path");
9990
10400
  import_node_child_process2 = require("node:child_process");
9991
- import_node_os3 = require("node:os");
10401
+ import_node_os4 = require("node:os");
9992
10402
  init_launch_kit_paths();
9993
10403
  init_graph();
10404
+ init_snippet();
9994
10405
  init_lockfile();
9995
10406
  init_config();
9996
10407
  init_parser_registry();
@@ -10375,6 +10786,20 @@ USE THIS FOR: "are there unsafe migrations on this branch", "audit the migration
10375
10786
  required: ["from", "to"]
10376
10787
  }
10377
10788
  },
10789
+ {
10790
+ name: "scaffold_snippet",
10791
+ description: 'Scaffold a standardised test "snippet" for a context-graph action/state node. Returns a ready-to-complete snippet file: requires/produces are filled from the context graph (certain); params + the run() body are left as TODOs for you to fill from the endpoint source.\n\nUSE THIS FOR: turning a context `action` (e.g. "create tag", "pay via UPI") into a reusable Playwright snippet in the project\'s standard shape, instead of hand-writing the requires/produces wiring. Requires the `context` layer (run generate_graph first).',
10792
+ inputSchema: {
10793
+ type: "object",
10794
+ properties: {
10795
+ target: { type: "string", description: 'Context node id (e.g. "action:app/api/orgs/[orgSlug]/tags/route.ts") or the bare key (the "action:"/"state:" prefix is added if missing).' },
10796
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
10797
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
10798
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
10799
+ },
10800
+ required: ["target"]
10801
+ }
10802
+ },
10378
10803
  {
10379
10804
  name: "auth_coverage_report",
10380
10805
  description: 'Aggregate every API endpoint by its auth[] wrapper(s) \u2014 surfaces endpoints with empty auth, groups by module, shows which auth strategies dominate. Computed from api.json endpoint auth field (100% populated).\n\nUSE THIS FOR: "are there unauthenticated endpoints", "which auth wrappers are in use", "audit auth strategy consistency across modules". Paginated. Returns { total, by_strategy: {strategy: count}, unauthenticated: [endpoint_ids], by_module: {module: {total, by_strategy}} } plus the paginated endpoint list.',
@@ -10641,8 +11066,92 @@ Example: blast_points(node_id: "server/auth/middleware.ts", hops: 2) \u2192 retu
10641
11066
 
10642
11067
  // src/server/graph-mcp-entry.ts
10643
11068
  init_lockfile();
11069
+
11070
+ // src/server/prune-npx-cache.ts
11071
+ var import_node_fs2 = require("node:fs");
11072
+ var import_node_os2 = require("node:os");
11073
+ var import_node_path2 = require("node:path");
11074
+ var import_node_util = require("node:util");
11075
+ var PKG = "@launchsecure/launch-kit";
11076
+ var readFileAsync = (0, import_node_util.promisify)(import_node_fs2.readFile);
11077
+ var readdirAsync = (0, import_node_util.promisify)(import_node_fs2.readdir);
11078
+ var rmAsync = (0, import_node_util.promisify)(import_node_fs2.rm);
11079
+ var realpathAsync = (0, import_node_util.promisify)(import_node_fs2.realpath);
11080
+ function npxCacheRoot() {
11081
+ const cache = process.env.npm_config_cache;
11082
+ if (cache && cache.trim()) return (0, import_node_path2.join)(cache, "_npx");
11083
+ if (process.platform === "win32") {
11084
+ const localAppData = process.env.LOCALAPPDATA;
11085
+ if (localAppData) return (0, import_node_path2.join)(localAppData, "npm-cache", "_npx");
11086
+ }
11087
+ return (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".npm", "_npx");
11088
+ }
11089
+ function ownVersion() {
11090
+ let dir = __dirname;
11091
+ for (let i = 0; i < 8; i++) {
11092
+ try {
11093
+ const pkg = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(dir, "package.json"), "utf8"));
11094
+ if (pkg && pkg.name === PKG) return typeof pkg.version === "string" ? pkg.version : null;
11095
+ } catch {
11096
+ }
11097
+ const parent = (0, import_node_path2.dirname)(dir);
11098
+ if (parent === dir) break;
11099
+ dir = parent;
11100
+ }
11101
+ return null;
11102
+ }
11103
+ async function pruneStaleNpxCache() {
11104
+ try {
11105
+ const version = ownVersion();
11106
+ if (!version) return;
11107
+ const root = npxCacheRoot();
11108
+ let hashes;
11109
+ try {
11110
+ hashes = await readdirAsync(root);
11111
+ } catch {
11112
+ return;
11113
+ }
11114
+ const selfPath = await realpathAsync(process.argv[1] || __dirname).catch(() => __dirname);
11115
+ let reaped = 0;
11116
+ for (const hash of hashes) {
11117
+ const dir = (0, import_node_path2.join)(root, hash);
11118
+ if (selfPath === dir || selfPath.startsWith(dir + import_node_path2.sep)) continue;
11119
+ let ver;
11120
+ try {
11121
+ const lkPkg = JSON.parse(
11122
+ await readFileAsync((0, import_node_path2.join)(dir, "node_modules", PKG, "package.json"), "utf8")
11123
+ );
11124
+ ver = lkPkg.version;
11125
+ } catch {
11126
+ continue;
11127
+ }
11128
+ if (ver === version) continue;
11129
+ try {
11130
+ const top = JSON.parse(await readFileAsync((0, import_node_path2.join)(dir, "package.json"), "utf8"));
11131
+ const spec = top?.dependencies?.[PKG];
11132
+ if (typeof spec === "string" && spec.startsWith("file:")) continue;
11133
+ } catch {
11134
+ }
11135
+ try {
11136
+ await rmAsync(dir, { recursive: true, force: true });
11137
+ reaped++;
11138
+ } catch {
11139
+ }
11140
+ }
11141
+ if (reaped > 0) {
11142
+ process.stderr.write(
11143
+ `[launch-kit] npx-cache: reaped ${reaped} stale copy(ies), kept v${version}
11144
+ `
11145
+ );
11146
+ }
11147
+ } catch {
11148
+ }
11149
+ }
11150
+
11151
+ // src/server/graph-mcp-entry.ts
10644
11152
  async function main() {
10645
11153
  setProjectRoot(process.cwd());
11154
+ void pruneStaleNpxCache();
10646
11155
  const argv = process.argv.slice(2);
10647
11156
  const subcommand = argv[0];
10648
11157
  if (subcommand === "serve") {