@launchsecure/launch-kit 0.0.29 → 0.0.30

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 (191) hide show
  1. package/dist/beacon/beacon.mjs +2759 -1246
  2. package/dist/beacon/beacon.mjs.map +1 -1
  3. package/dist/beacon/beacon.umd.js +710 -95
  4. package/dist/beacon/beacon.umd.js.map +1 -1
  5. package/dist/beacon/types/core.d.ts +14 -0
  6. package/dist/beacon/types/core.d.ts.map +1 -0
  7. package/dist/beacon/types/ctx.d.ts +14 -0
  8. package/dist/beacon/types/ctx.d.ts.map +1 -0
  9. package/dist/beacon/types/element.d.ts +16 -48
  10. package/dist/beacon/types/element.d.ts.map +1 -1
  11. package/dist/beacon/types/index.d.ts +5 -4
  12. package/dist/beacon/types/index.d.ts.map +1 -1
  13. package/dist/beacon/types/internal/annotation-cache.d.ts +10 -0
  14. package/dist/beacon/types/internal/annotation-cache.d.ts.map +1 -0
  15. package/dist/beacon/types/internal/element-capture.d.ts +19 -0
  16. package/dist/beacon/types/internal/element-capture.d.ts.map +1 -0
  17. package/dist/beacon/types/internal/event-buffer.d.ts +16 -0
  18. package/dist/beacon/types/internal/event-buffer.d.ts.map +1 -0
  19. package/dist/beacon/types/internal/framework-detect.d.ts +6 -0
  20. package/dist/beacon/types/internal/framework-detect.d.ts.map +1 -0
  21. package/dist/beacon/types/internal/markers.d.ts +17 -0
  22. package/dist/beacon/types/internal/markers.d.ts.map +1 -0
  23. package/dist/beacon/types/internal/monitor/capture-dom.d.ts +14 -0
  24. package/dist/beacon/types/internal/monitor/capture-dom.d.ts.map +1 -0
  25. package/dist/beacon/types/internal/monitor/capture-network.d.ts +12 -0
  26. package/dist/beacon/types/internal/monitor/capture-network.d.ts.map +1 -0
  27. package/dist/beacon/types/internal/monitor/overlay.d.ts +16 -0
  28. package/dist/beacon/types/internal/monitor/overlay.d.ts.map +1 -0
  29. package/dist/beacon/types/internal/monitor/session.d.ts +41 -0
  30. package/dist/beacon/types/internal/monitor/session.d.ts.map +1 -0
  31. package/dist/beacon/types/{monitor → internal/monitor}/transport.d.ts +3 -3
  32. package/dist/beacon/types/internal/monitor/transport.d.ts.map +1 -0
  33. package/dist/beacon/types/{monitor/types.d.ts → internal/monitor/wire.d.ts} +69 -27
  34. package/dist/beacon/types/internal/monitor/wire.d.ts.map +1 -0
  35. package/dist/beacon/types/{ui → internal}/pick-mode-overlay.d.ts +4 -5
  36. package/dist/beacon/types/internal/pick-mode-overlay.d.ts.map +1 -0
  37. package/dist/beacon/types/{capture → internal}/picker.d.ts +0 -1
  38. package/dist/beacon/types/internal/picker.d.ts.map +1 -0
  39. package/dist/beacon/types/{ui → internal}/pin-popover.d.ts +1 -1
  40. package/dist/beacon/types/internal/pin-popover.d.ts.map +1 -0
  41. package/dist/beacon/types/{capture → internal}/screenshot.d.ts +1 -0
  42. package/dist/beacon/types/internal/screenshot.d.ts.map +1 -0
  43. package/dist/beacon/types/internal/selector.d.ts.map +1 -0
  44. package/dist/beacon/types/plugins/domEle.d.ts +14 -0
  45. package/dist/beacon/types/plugins/domEle.d.ts.map +1 -0
  46. package/dist/beacon/types/plugins/domSS.d.ts +8 -0
  47. package/dist/beacon/types/plugins/domSS.d.ts.map +1 -0
  48. package/dist/beacon/types/plugins/errors.d.ts +3 -0
  49. package/dist/beacon/types/plugins/errors.d.ts.map +1 -0
  50. package/dist/beacon/types/plugins/index.d.ts +8 -0
  51. package/dist/beacon/types/plugins/index.d.ts.map +1 -0
  52. package/dist/beacon/types/plugins/liveMonitor.d.ts +14 -0
  53. package/dist/beacon/types/plugins/liveMonitor.d.ts.map +1 -0
  54. package/dist/beacon/types/plugins/metadata.d.ts +3 -0
  55. package/dist/beacon/types/plugins/metadata.d.ts.map +1 -0
  56. package/dist/beacon/types/registry.d.ts +33 -0
  57. package/dist/beacon/types/registry.d.ts.map +1 -0
  58. package/dist/beacon/types/styles.d.ts +8 -0
  59. package/dist/beacon/types/styles.d.ts.map +1 -0
  60. package/dist/beacon/types/transport.d.ts +3 -0
  61. package/dist/beacon/types/transport.d.ts.map +1 -0
  62. package/dist/beacon/types/types.d.ts +152 -68
  63. package/dist/beacon/types/types.d.ts.map +1 -1
  64. package/dist/beacon/types/ui/dialog.d.ts +53 -0
  65. package/dist/beacon/types/ui/dialog.d.ts.map +1 -0
  66. package/dist/beacon/types/ui/form.d.ts +7 -0
  67. package/dist/beacon/types/ui/form.d.ts.map +1 -0
  68. package/dist/beacon/types/ui/overlay.d.ts +6 -0
  69. package/dist/beacon/types/ui/overlay.d.ts.map +1 -0
  70. package/dist/deck-client/assets/{_baseUniq-W2JQDmje.js → _baseUniq-DCt2IMRR.js} +1 -1
  71. package/dist/deck-client/assets/{arc-DIBWAId9.js → arc-h-ifqmNR.js} +1 -1
  72. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-CAIRMvJK.js → architectureDiagram-Q4EWVU46-C9dITSPv.js} +1 -1
  73. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-BeNaNiOi.js → blockDiagram-DXYQGD6D-BHuJT34t.js} +1 -1
  74. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-B9Ozi62h.js → c4Diagram-AHTNJAMY-CpvMGtDG.js} +1 -1
  75. package/dist/deck-client/assets/channel-2PZVMiXf.js +1 -0
  76. package/dist/deck-client/assets/{chunk-4BX2VUAB-D7AZ47dt.js → chunk-4BX2VUAB-B6md1VIm.js} +1 -1
  77. package/dist/deck-client/assets/{chunk-4TB4RGXK-DnVnNPcI.js → chunk-4TB4RGXK-BmEnX8ik.js} +1 -1
  78. package/dist/deck-client/assets/{chunk-55IACEB6-UKYs-YNd.js → chunk-55IACEB6-BZPUyZAZ.js} +1 -1
  79. package/dist/deck-client/assets/{chunk-EDXVE4YY-D43b-SKn.js → chunk-EDXVE4YY-BWwNUK-l.js} +1 -1
  80. package/dist/deck-client/assets/{chunk-FMBD7UC4-QzBAoyyW.js → chunk-FMBD7UC4-o7gSppGI.js} +1 -1
  81. package/dist/deck-client/assets/{chunk-OYMX7WX6-Cjif4r6W.js → chunk-OYMX7WX6-C4KoTL5p.js} +1 -1
  82. package/dist/deck-client/assets/{chunk-QZHKN3VN-CqLDirEI.js → chunk-QZHKN3VN-jkf68sDs.js} +1 -1
  83. package/dist/deck-client/assets/{chunk-YZCP3GAM-_FQvmMs4.js → chunk-YZCP3GAM-Cd4yBE7o.js} +1 -1
  84. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-Bt8xBAof.js +1 -0
  85. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-Bt8xBAof.js +1 -0
  86. package/dist/deck-client/assets/clone-BHQryoDl.js +1 -0
  87. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-rfrocesE.js → cose-bilkent-S5V4N54A-DeGFUgAV.js} +1 -1
  88. package/dist/deck-client/assets/{dagre-KV5264BT-Bv_7DJat.js → dagre-KV5264BT-ekcYJuUV.js} +1 -1
  89. package/dist/deck-client/assets/{diagram-5BDNPKRD-4F1414G5.js → diagram-5BDNPKRD-YHPk4rV2.js} +1 -1
  90. package/dist/deck-client/assets/{diagram-G4DWMVQ6-C4-Pszqm.js → diagram-G4DWMVQ6-DM-JCd_B.js} +1 -1
  91. package/dist/deck-client/assets/{diagram-MMDJMWI5-B647TIx9.js → diagram-MMDJMWI5-l5FK1ybk.js} +1 -1
  92. package/dist/deck-client/assets/{diagram-TYMM5635-BFAqpezd.js → diagram-TYMM5635-CIN4_1-j.js} +1 -1
  93. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BfBfrJOC.js → erDiagram-SMLLAGMA-MyinSkEl.js} +1 -1
  94. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-DX9YAYes.js → flowDiagram-DWJPFMVM-Dk8nn42x.js} +1 -1
  95. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-DCuiy7wF.js → ganttDiagram-T4ZO3ILL-BU1ihicu.js} +1 -1
  96. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-CGp1IXUh.js → gitGraphDiagram-UUTBAWPF-BjsTL13C.js} +1 -1
  97. package/dist/deck-client/assets/{graph-B7g8aoxv.js → graph-DJmh-xi7.js} +1 -1
  98. package/dist/deck-client/assets/{index-Dg1r-WSN.js → index-KsShfCV-.js} +3 -3
  99. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-L3fahMkF.js → infoDiagram-42DDH7IO-Dxvy_RB4.js} +1 -1
  100. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-aS_EjWBZ.js → ishikawaDiagram-UXIWVN3A-DPOaNF1l.js} +1 -1
  101. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-djTSQZF9.js → journeyDiagram-VCZTEJTY-DMew3K5c.js} +1 -1
  102. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-CcTHo4CM.js → kanban-definition-6JOO6SKY-csciJFuk.js} +1 -1
  103. package/dist/deck-client/assets/{layout-mEJiadb7.js → layout-Dg4yyms2.js} +1 -1
  104. package/dist/deck-client/assets/{linear-XgTKqyRu.js → linear-BA3zU6gq.js} +1 -1
  105. package/dist/deck-client/assets/{min-Ct9jZdpd.js → min-lz-Ird-p.js} +1 -1
  106. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-BaFxCGNU.js → mindmap-definition-QFDTVHPH-CCEN8OQV.js} +1 -1
  107. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-CIbYYjtw.js → pieDiagram-DEJITSTG-DM6n1HY7.js} +1 -1
  108. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-D9EtCOvh.js → quadrantDiagram-34T5L4WZ-_ULoR66n.js} +1 -1
  109. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-xeni9eVG.js → requirementDiagram-MS252O5E-BuwJs7Tn.js} +1 -1
  110. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-LYeknz9h.js → sankeyDiagram-XADWPNL6-BEsuzkW4.js} +1 -1
  111. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-RDbsKFZf.js → sequenceDiagram-FGHM5R23-CP2H0YWf.js} +1 -1
  112. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-BH1Zjglk.js → stateDiagram-FHFEXIEX-B5Gw_NNL.js} +1 -1
  113. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-4T4wMDXr.js +1 -0
  114. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-IFXxKptt.js → timeline-definition-GMOUNBTQ-DsoYydQa.js} +1 -1
  115. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-D-sLkQs9.js → vennDiagram-DHZGUBPP-Dz8JT_ob.js} +1 -1
  116. package/dist/deck-client/assets/wardley-RL74JXVD-DGHQ_Ijv.js +162 -0
  117. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-BTjjuDU3.js → wardleyDiagram-NUSXRM2D-DN1LJMB1.js} +1 -1
  118. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-AYbv92n-.js → xychartDiagram-5P7HB3ND-nb0oSfrQ.js} +1 -1
  119. package/dist/deck-client/index.html +1 -1
  120. package/dist/server/beacon-monitor-entry.js +548 -6
  121. package/dist/server/chart-serve.js +917 -248
  122. package/dist/server/cli.js +1368 -374
  123. package/dist/server/council-entry.js +0 -0
  124. package/dist/server/fb-wizard.js +0 -0
  125. package/dist/server/graph-mcp-entry.js +1326 -322
  126. package/dist/server/init-entry.js +16 -11
  127. package/dist/server/orbit-entry.js +135 -7
  128. package/dist/server/parse-worker-entry.js +918 -247
  129. package/package.json +22 -22
  130. package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-array.md +107 -0
  131. package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-clear.md +94 -0
  132. package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-pulse.md +82 -0
  133. package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-scan.md +66 -0
  134. package/scaffolds/ls-marketplace/plugins/kit/skills/blast-radius.md +101 -0
  135. package/scaffolds/ls-marketplace/plugins/kit/skills/brief.md +112 -0
  136. package/scaffolds/ls-marketplace/plugins/kit/skills/course.md +84 -0
  137. package/scaffolds/ls-marketplace/plugins/kit/skills/debug.md +92 -0
  138. package/scaffolds/ls-marketplace/plugins/kit/skills/deploy-check.md +160 -0
  139. package/scaffolds/ls-marketplace/plugins/kit/skills/diagram.md +134 -0
  140. package/scaffolds/ls-marketplace/plugins/kit/skills/orbit.md +87 -0
  141. package/scaffolds/ls-marketplace/plugins/kit/skills/prototype.md +90 -0
  142. package/scaffolds/ls-marketplace/plugins/kit/skills/recall.md +83 -0
  143. package/scaffolds/ls-marketplace/plugins/kit/{commands → skills}/show-mcp-status.md +4 -4
  144. package/scaffolds/ls-marketplace/plugins/kit/skills/wireframe.md +70 -0
  145. package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
  146. package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
  147. package/scaffolds/statusline/statusline-mcp.sh +21 -9
  148. package/dist/beacon/types/capture/element.d.ts +0 -3
  149. package/dist/beacon/types/capture/element.d.ts.map +0 -1
  150. package/dist/beacon/types/capture/events.d.ts +0 -20
  151. package/dist/beacon/types/capture/events.d.ts.map +0 -1
  152. package/dist/beacon/types/capture/framework.d.ts +0 -3
  153. package/dist/beacon/types/capture/framework.d.ts.map +0 -1
  154. package/dist/beacon/types/capture/metadata.d.ts +0 -3
  155. package/dist/beacon/types/capture/metadata.d.ts.map +0 -1
  156. package/dist/beacon/types/capture/overlay.d.ts +0 -7
  157. package/dist/beacon/types/capture/overlay.d.ts.map +0 -1
  158. package/dist/beacon/types/capture/picker.d.ts.map +0 -1
  159. package/dist/beacon/types/capture/screenshot.d.ts.map +0 -1
  160. package/dist/beacon/types/capture/selector.d.ts.map +0 -1
  161. package/dist/beacon/types/monitor/dom.d.ts +0 -13
  162. package/dist/beacon/types/monitor/dom.d.ts.map +0 -1
  163. package/dist/beacon/types/monitor/index.d.ts +0 -19
  164. package/dist/beacon/types/monitor/index.d.ts.map +0 -1
  165. package/dist/beacon/types/monitor/network.d.ts +0 -12
  166. package/dist/beacon/types/monitor/network.d.ts.map +0 -1
  167. package/dist/beacon/types/monitor/transport.d.ts.map +0 -1
  168. package/dist/beacon/types/monitor/types.d.ts.map +0 -1
  169. package/dist/beacon/types/transport/submit.d.ts +0 -3
  170. package/dist/beacon/types/transport/submit.d.ts.map +0 -1
  171. package/dist/beacon/types/ui/button.d.ts +0 -2
  172. package/dist/beacon/types/ui/button.d.ts.map +0 -1
  173. package/dist/beacon/types/ui/drawer.d.ts +0 -33
  174. package/dist/beacon/types/ui/drawer.d.ts.map +0 -1
  175. package/dist/beacon/types/ui/icons.d.ts +0 -9
  176. package/dist/beacon/types/ui/icons.d.ts.map +0 -1
  177. package/dist/beacon/types/ui/monitor-panel.d.ts +0 -19
  178. package/dist/beacon/types/ui/monitor-panel.d.ts.map +0 -1
  179. package/dist/beacon/types/ui/pick-mode-overlay.d.ts.map +0 -1
  180. package/dist/beacon/types/ui/pin-popover.d.ts.map +0 -1
  181. package/dist/deck-client/assets/channel-CRdozqbp.js +0 -1
  182. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-lIZMp57W.js +0 -1
  183. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-lIZMp57W.js +0 -1
  184. package/dist/deck-client/assets/clone-BtWeSTyJ.js +0 -1
  185. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BrV78NDR.js +0 -1
  186. package/dist/deck-client/assets/wardley-RL74JXVD-C010F8l4.js +0 -162
  187. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-array.md +0 -92
  188. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-clear.md +0 -68
  189. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-pulse.md +0 -80
  190. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-scan.md +0 -62
  191. /package/dist/beacon/types/{capture → internal}/selector.d.ts +0 -0
@@ -1752,7 +1752,7 @@ var require_usage_reader = __commonJS({
1752
1752
  async readJsonlFile(filePath, cutoffTime) {
1753
1753
  const entries = [];
1754
1754
  const fileProcessedEntries = /* @__PURE__ */ new Set();
1755
- return new Promise((resolve5) => {
1755
+ return new Promise((resolve6) => {
1756
1756
  const rl = readline.createInterface({
1757
1757
  input: createReadStream(filePath),
1758
1758
  crlfDelay: Infinity
@@ -1810,11 +1810,11 @@ var require_usage_reader = __commonJS({
1810
1810
  }
1811
1811
  });
1812
1812
  rl.on("close", () => {
1813
- resolve5(entries);
1813
+ resolve6(entries);
1814
1814
  });
1815
1815
  rl.on("error", (error) => {
1816
1816
  console.error("Error reading file:", filePath, error);
1817
- resolve5(entries);
1817
+ resolve6(entries);
1818
1818
  });
1819
1819
  });
1820
1820
  }
@@ -3623,7 +3623,7 @@ var require_src = __commonJS({
3623
3623
  if (session.active) throw new Error(`Agent already running in session ${sessionId}`);
3624
3624
  const { command, args = [], env = {} } = options;
3625
3625
  if (!command) throw new Error("startScriptInSession requires a command");
3626
- return new Promise((resolve5, reject) => {
3626
+ return new Promise((resolve6, reject) => {
3627
3627
  this.scriptBridge.startSession(sessionId, {
3628
3628
  command,
3629
3629
  args,
@@ -3645,7 +3645,7 @@ var require_src = __commonJS({
3645
3645
  session.lastActivity = /* @__PURE__ */ new Date();
3646
3646
  this.broadcastToSession(sessionId, { type: "script_stopped", sessionId });
3647
3647
  if (exitCode === 0) {
3648
- resolve5({ code: exitCode, signal });
3648
+ resolve6({ code: exitCode, signal });
3649
3649
  } else {
3650
3650
  reject(new Error(`Script exited with code ${exitCode}`));
3651
3651
  }
@@ -5567,9 +5567,9 @@ var require_dispatcher_base = __commonJS({
5567
5567
  }
5568
5568
  close(callback) {
5569
5569
  if (callback === void 0) {
5570
- return new Promise((resolve5, reject) => {
5570
+ return new Promise((resolve6, reject) => {
5571
5571
  this.close((err2, data) => {
5572
- return err2 ? reject(err2) : resolve5(data);
5572
+ return err2 ? reject(err2) : resolve6(data);
5573
5573
  });
5574
5574
  });
5575
5575
  }
@@ -5607,12 +5607,12 @@ var require_dispatcher_base = __commonJS({
5607
5607
  err2 = null;
5608
5608
  }
5609
5609
  if (callback === void 0) {
5610
- return new Promise((resolve5, reject) => {
5610
+ return new Promise((resolve6, reject) => {
5611
5611
  this.destroy(err2, (err3, data) => {
5612
5612
  return err3 ? (
5613
5613
  /* istanbul ignore next: should never error */
5614
5614
  reject(err3)
5615
- ) : resolve5(data);
5615
+ ) : resolve6(data);
5616
5616
  });
5617
5617
  });
5618
5618
  }
@@ -7879,8 +7879,8 @@ var require_util2 = __commonJS({
7879
7879
  function createDeferredPromise() {
7880
7880
  let res;
7881
7881
  let rej;
7882
- const promise = new Promise((resolve5, reject) => {
7883
- res = resolve5;
7882
+ const promise = new Promise((resolve6, reject) => {
7883
+ res = resolve6;
7884
7884
  rej = reject;
7885
7885
  });
7886
7886
  return { promise, resolve: res, reject: rej };
@@ -10021,12 +10021,12 @@ upgrade: ${upgrade}\r
10021
10021
  cb();
10022
10022
  }
10023
10023
  }
10024
- const waitForDrain = () => new Promise((resolve5, reject) => {
10024
+ const waitForDrain = () => new Promise((resolve6, reject) => {
10025
10025
  assert(callback === null);
10026
10026
  if (socket[kError]) {
10027
10027
  reject(socket[kError]);
10028
10028
  } else {
10029
- callback = resolve5;
10029
+ callback = resolve6;
10030
10030
  }
10031
10031
  });
10032
10032
  socket.on("close", onDrain).on("drain", onDrain);
@@ -10663,12 +10663,12 @@ var require_client_h2 = __commonJS({
10663
10663
  cb();
10664
10664
  }
10665
10665
  }
10666
- const waitForDrain = () => new Promise((resolve5, reject) => {
10666
+ const waitForDrain = () => new Promise((resolve6, reject) => {
10667
10667
  assert(callback === null);
10668
10668
  if (socket[kError]) {
10669
10669
  reject(socket[kError]);
10670
10670
  } else {
10671
- callback = resolve5;
10671
+ callback = resolve6;
10672
10672
  }
10673
10673
  });
10674
10674
  h2stream.on("close", onDrain).on("drain", onDrain);
@@ -11146,16 +11146,16 @@ var require_client = __commonJS({
11146
11146
  return this[kNeedDrain] < 2;
11147
11147
  }
11148
11148
  async [kClose]() {
11149
- return new Promise((resolve5) => {
11149
+ return new Promise((resolve6) => {
11150
11150
  if (this[kSize]) {
11151
- this[kClosedResolve] = resolve5;
11151
+ this[kClosedResolve] = resolve6;
11152
11152
  } else {
11153
- resolve5(null);
11153
+ resolve6(null);
11154
11154
  }
11155
11155
  });
11156
11156
  }
11157
11157
  async [kDestroy](err2) {
11158
- return new Promise((resolve5) => {
11158
+ return new Promise((resolve6) => {
11159
11159
  const requests = this[kQueue].splice(this[kPendingIdx]);
11160
11160
  for (let i = 0; i < requests.length; i++) {
11161
11161
  const request = requests[i];
@@ -11166,7 +11166,7 @@ var require_client = __commonJS({
11166
11166
  this[kClosedResolve]();
11167
11167
  this[kClosedResolve] = null;
11168
11168
  }
11169
- resolve5(null);
11169
+ resolve6(null);
11170
11170
  };
11171
11171
  if (this[kHTTPContext]) {
11172
11172
  this[kHTTPContext].destroy(err2, callback);
@@ -11217,7 +11217,7 @@ var require_client = __commonJS({
11217
11217
  });
11218
11218
  }
11219
11219
  try {
11220
- const socket = await new Promise((resolve5, reject) => {
11220
+ const socket = await new Promise((resolve6, reject) => {
11221
11221
  client[kConnector]({
11222
11222
  host,
11223
11223
  hostname,
@@ -11229,7 +11229,7 @@ var require_client = __commonJS({
11229
11229
  if (err2) {
11230
11230
  reject(err2);
11231
11231
  } else {
11232
- resolve5(socket2);
11232
+ resolve6(socket2);
11233
11233
  }
11234
11234
  });
11235
11235
  });
@@ -11565,8 +11565,8 @@ var require_pool_base = __commonJS({
11565
11565
  if (this[kQueue].isEmpty()) {
11566
11566
  await Promise.all(this[kClients].map((c) => c.close()));
11567
11567
  } else {
11568
- await new Promise((resolve5) => {
11569
- this[kClosedResolve] = resolve5;
11568
+ await new Promise((resolve6) => {
11569
+ this[kClosedResolve] = resolve6;
11570
11570
  });
11571
11571
  }
11572
11572
  }
@@ -12781,7 +12781,7 @@ var require_readable = __commonJS({
12781
12781
  if (this._readableState.closeEmitted) {
12782
12782
  return null;
12783
12783
  }
12784
- return await new Promise((resolve5, reject) => {
12784
+ return await new Promise((resolve6, reject) => {
12785
12785
  if (this[kContentLength] > limit) {
12786
12786
  this.destroy(new AbortError());
12787
12787
  }
@@ -12794,7 +12794,7 @@ var require_readable = __commonJS({
12794
12794
  if (signal?.aborted) {
12795
12795
  reject(signal.reason ?? new AbortError());
12796
12796
  } else {
12797
- resolve5(null);
12797
+ resolve6(null);
12798
12798
  }
12799
12799
  }).on("error", noop).on("data", function(chunk) {
12800
12800
  limit -= chunk.length;
@@ -12813,7 +12813,7 @@ var require_readable = __commonJS({
12813
12813
  }
12814
12814
  async function consume(stream, type) {
12815
12815
  assert(!stream[kConsume]);
12816
- return new Promise((resolve5, reject) => {
12816
+ return new Promise((resolve6, reject) => {
12817
12817
  if (isUnusable(stream)) {
12818
12818
  const rState = stream._readableState;
12819
12819
  if (rState.destroyed && rState.closeEmitted === false) {
@@ -12830,7 +12830,7 @@ var require_readable = __commonJS({
12830
12830
  stream[kConsume] = {
12831
12831
  type,
12832
12832
  stream,
12833
- resolve: resolve5,
12833
+ resolve: resolve6,
12834
12834
  reject,
12835
12835
  length: 0,
12836
12836
  body: []
@@ -12900,18 +12900,18 @@ var require_readable = __commonJS({
12900
12900
  return buffer;
12901
12901
  }
12902
12902
  function consumeEnd(consume2) {
12903
- const { type, body, resolve: resolve5, stream, length } = consume2;
12903
+ const { type, body, resolve: resolve6, stream, length } = consume2;
12904
12904
  try {
12905
12905
  if (type === "text") {
12906
- resolve5(chunksDecode(body, length));
12906
+ resolve6(chunksDecode(body, length));
12907
12907
  } else if (type === "json") {
12908
- resolve5(JSON.parse(chunksDecode(body, length)));
12908
+ resolve6(JSON.parse(chunksDecode(body, length)));
12909
12909
  } else if (type === "arrayBuffer") {
12910
- resolve5(chunksConcat(body, length).buffer);
12910
+ resolve6(chunksConcat(body, length).buffer);
12911
12911
  } else if (type === "blob") {
12912
- resolve5(new Blob(body, { type: stream[kContentType] }));
12912
+ resolve6(new Blob(body, { type: stream[kContentType] }));
12913
12913
  } else if (type === "bytes") {
12914
- resolve5(chunksConcat(body, length));
12914
+ resolve6(chunksConcat(body, length));
12915
12915
  }
12916
12916
  consumeFinish(consume2);
12917
12917
  } catch (err2) {
@@ -13168,9 +13168,9 @@ var require_api_request = __commonJS({
13168
13168
  };
13169
13169
  function request(opts, callback) {
13170
13170
  if (callback === void 0) {
13171
- return new Promise((resolve5, reject) => {
13171
+ return new Promise((resolve6, reject) => {
13172
13172
  request.call(this, opts, (err2, data) => {
13173
- return err2 ? reject(err2) : resolve5(data);
13173
+ return err2 ? reject(err2) : resolve6(data);
13174
13174
  });
13175
13175
  });
13176
13176
  }
@@ -13393,9 +13393,9 @@ var require_api_stream = __commonJS({
13393
13393
  };
13394
13394
  function stream(opts, factory, callback) {
13395
13395
  if (callback === void 0) {
13396
- return new Promise((resolve5, reject) => {
13396
+ return new Promise((resolve6, reject) => {
13397
13397
  stream.call(this, opts, factory, (err2, data) => {
13398
- return err2 ? reject(err2) : resolve5(data);
13398
+ return err2 ? reject(err2) : resolve6(data);
13399
13399
  });
13400
13400
  });
13401
13401
  }
@@ -13680,9 +13680,9 @@ var require_api_upgrade = __commonJS({
13680
13680
  };
13681
13681
  function upgrade(opts, callback) {
13682
13682
  if (callback === void 0) {
13683
- return new Promise((resolve5, reject) => {
13683
+ return new Promise((resolve6, reject) => {
13684
13684
  upgrade.call(this, opts, (err2, data) => {
13685
- return err2 ? reject(err2) : resolve5(data);
13685
+ return err2 ? reject(err2) : resolve6(data);
13686
13686
  });
13687
13687
  });
13688
13688
  }
@@ -13774,9 +13774,9 @@ var require_api_connect = __commonJS({
13774
13774
  };
13775
13775
  function connect(opts, callback) {
13776
13776
  if (callback === void 0) {
13777
- return new Promise((resolve5, reject) => {
13777
+ return new Promise((resolve6, reject) => {
13778
13778
  connect.call(this, opts, (err2, data) => {
13779
- return err2 ? reject(err2) : resolve5(data);
13779
+ return err2 ? reject(err2) : resolve6(data);
13780
13780
  });
13781
13781
  });
13782
13782
  }
@@ -17638,7 +17638,7 @@ var require_fetch = __commonJS({
17638
17638
  function dispatch({ body }) {
17639
17639
  const url = requestCurrentURL(request);
17640
17640
  const agent = fetchParams.controller.dispatcher;
17641
- return new Promise((resolve5, reject) => agent.dispatch(
17641
+ return new Promise((resolve6, reject) => agent.dispatch(
17642
17642
  {
17643
17643
  path: url.pathname + url.search,
17644
17644
  origin: url.origin,
@@ -17714,7 +17714,7 @@ var require_fetch = __commonJS({
17714
17714
  }
17715
17715
  }
17716
17716
  const onError = this.onError.bind(this);
17717
- resolve5({
17717
+ resolve6({
17718
17718
  status,
17719
17719
  statusText,
17720
17720
  headersList,
@@ -17760,7 +17760,7 @@ var require_fetch = __commonJS({
17760
17760
  for (let i = 0; i < rawHeaders.length; i += 2) {
17761
17761
  headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString("latin1"), true);
17762
17762
  }
17763
- resolve5({
17763
+ resolve6({
17764
17764
  status,
17765
17765
  statusText: STATUS_CODES[status],
17766
17766
  headersList,
@@ -21436,8 +21436,8 @@ var require_util8 = __commonJS({
21436
21436
  return true;
21437
21437
  }
21438
21438
  function delay(ms) {
21439
- return new Promise((resolve5) => {
21440
- setTimeout(resolve5, ms).unref();
21439
+ return new Promise((resolve6) => {
21440
+ setTimeout(resolve6, ms).unref();
21441
21441
  });
21442
21442
  }
21443
21443
  module2.exports = {
@@ -22628,7 +22628,7 @@ function resolveWorkerPath() {
22628
22628
  );
22629
22629
  }
22630
22630
  function runParseInWorker(req) {
22631
- return new Promise((resolve5, reject) => {
22631
+ return new Promise((resolve6, reject) => {
22632
22632
  let workerPath;
22633
22633
  try {
22634
22634
  workerPath = resolveWorkerPath();
@@ -22647,7 +22647,7 @@ function runParseInWorker(req) {
22647
22647
  };
22648
22648
  worker.on("message", (reply) => {
22649
22649
  if (reply.ok) {
22650
- finish(() => resolve5({ results: reply.results, failedFiles: reply.failedFiles }));
22650
+ finish(() => resolve6({ results: reply.results, failedFiles: reply.failedFiles }));
22651
22651
  } else {
22652
22652
  const err2 = new Error(reply.error.message);
22653
22653
  err2.name = reply.error.name;
@@ -22891,7 +22891,7 @@ var init_freshness = __esm({
22891
22891
  function getAvailableLayers(rootDir) {
22892
22892
  const dir = (0, import_node_path13.join)(rootDir, GRAPHS_DIR2);
22893
22893
  if (!(0, import_node_fs11.existsSync)(dir)) return [];
22894
- return (0, import_node_fs11.readdirSync)(dir).filter((f) => f.endsWith(".json") && !NON_LAYER_GRAPH_FILES.has(f)).map((f) => f.replace(".json", ""));
22894
+ return (0, import_node_fs11.readdirSync)(dir).filter((f) => f.endsWith(".json") && !f.startsWith(".") && !NON_LAYER_GRAPH_FILES.has(f)).map((f) => f.replace(".json", ""));
22895
22895
  }
22896
22896
  function graphsDir(rootDir) {
22897
22897
  return (0, import_node_path13.join)(rootDir, GRAPHS_DIR2);
@@ -24089,6 +24089,8 @@ function extractDeep(absPath) {
24089
24089
  false
24090
24090
  );
24091
24091
  const hasEffects = Object.keys(fileEffects).length > 0;
24092
+ const uiLabels = collectUiLabels(root);
24093
+ const notes = collectNotes(root);
24092
24094
  return {
24093
24095
  elements,
24094
24096
  stateVars,
@@ -24096,10 +24098,77 @@ function extractDeep(absPath) {
24096
24098
  variables,
24097
24099
  responses,
24098
24100
  params,
24099
- ...hasEffects ? { effects: fileEffects } : {}
24101
+ ...hasEffects ? { effects: fileEffects } : {},
24102
+ ...uiLabels.length > 0 ? { ui_labels: uiLabels } : {},
24103
+ ...notes.length > 0 ? { notes } : {}
24100
24104
  };
24101
24105
  }
24102
- var import_node_fs15, 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;
24106
+ function collectNotes(root) {
24107
+ const out = [];
24108
+ const seen = /* @__PURE__ */ new Set();
24109
+ function visit(node) {
24110
+ if (out.length >= NOTES_MAX) return;
24111
+ if (node.type === "comment") {
24112
+ const text = node.text;
24113
+ const startRow = node.startPosition.row;
24114
+ NOTE_REGEX.lastIndex = 0;
24115
+ let m;
24116
+ while ((m = NOTE_REGEX.exec(text)) !== null) {
24117
+ const kind = m[1];
24118
+ const author = m[2];
24119
+ const body = m[3];
24120
+ if (!kind || !body) continue;
24121
+ const newlinesBefore = (text.slice(0, m.index).match(/\n/g) ?? []).length;
24122
+ const line = startRow + 1 + newlinesBefore;
24123
+ const key = `${line}:${kind}`;
24124
+ if (seen.has(key)) continue;
24125
+ seen.add(key);
24126
+ const note = {
24127
+ kind,
24128
+ text: body.length <= 200 ? body : body.slice(0, 200) + "...",
24129
+ line
24130
+ };
24131
+ if (author) note.author = author;
24132
+ out.push(note);
24133
+ if (out.length >= NOTES_MAX) return;
24134
+ }
24135
+ }
24136
+ for (const child of node.namedChildren) {
24137
+ visit(child);
24138
+ if (out.length >= NOTES_MAX) return;
24139
+ }
24140
+ }
24141
+ visit(root);
24142
+ return out;
24143
+ }
24144
+ function collectUiLabels(root) {
24145
+ const out = [];
24146
+ const seen = /* @__PURE__ */ new Set();
24147
+ function visit(node) {
24148
+ if (out.length >= UI_LABELS_MAX) return;
24149
+ if (node.type === "pair") {
24150
+ const key = node.childForFieldName("key");
24151
+ const val = node.childForFieldName("value");
24152
+ if (key && val) {
24153
+ const keyText = key.type === "property_identifier" ? key.text : stringLiteralValue(key) ?? key.text;
24154
+ if (UI_LABEL_KEYS.has(keyText)) {
24155
+ const strVal = stringLiteralValue(val);
24156
+ if (strVal && strVal.length > 0 && strVal.length <= 200 && !seen.has(strVal)) {
24157
+ seen.add(strVal);
24158
+ out.push(strVal);
24159
+ }
24160
+ }
24161
+ }
24162
+ }
24163
+ for (const child of node.namedChildren) {
24164
+ visit(child);
24165
+ if (out.length >= UI_LABELS_MAX) return;
24166
+ }
24167
+ }
24168
+ visit(root);
24169
+ return out;
24170
+ }
24171
+ var import_node_fs15, 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;
24103
24172
  var init_ts_extractor = __esm({
24104
24173
  "src/server/graph/core/ts-extractor.ts"() {
24105
24174
  "use strict";
@@ -24218,6 +24287,27 @@ var init_ts_extractor = __esm({
24218
24287
  "selected",
24219
24288
  "disabled"
24220
24289
  ]);
24290
+ UI_LABEL_KEYS = /* @__PURE__ */ new Set([
24291
+ "label",
24292
+ "title",
24293
+ "name",
24294
+ "text",
24295
+ "description",
24296
+ "placeholder",
24297
+ "tooltip",
24298
+ "heading",
24299
+ "subheading",
24300
+ "sheetTitle",
24301
+ "sheetDescription",
24302
+ "caption",
24303
+ "cta",
24304
+ "buttonText",
24305
+ "emptyText",
24306
+ "subtitle"
24307
+ ]);
24308
+ UI_LABELS_MAX = 200;
24309
+ NOTE_REGEX = /^\s*(?:\/\/|\/\*+|\*)\s*([A-Z][A-Z0-9_]{1,15})(?:\(([^)]+)\))?:\s*(\S.*?)\s*(?:\*\/)?$/gm;
24310
+ NOTES_MAX = 100;
24221
24311
  }
24222
24312
  });
24223
24313
 
@@ -24229,7 +24319,7 @@ __export(watcher_exports, {
24229
24319
  function isIgnoredPath(rel) {
24230
24320
  if (rel.startsWith(GRAPHS_RELATIVE)) return true;
24231
24321
  if (rel.endsWith(".lock") || rel.endsWith(".log")) return true;
24232
- for (const part of rel.split(import_node_path30.sep)) {
24322
+ for (const part of rel.split(import_node_path32.sep)) {
24233
24323
  if (IGNORE_SEGMENTS.has(part)) return true;
24234
24324
  }
24235
24325
  return false;
@@ -24271,7 +24361,7 @@ function startGraphWatcher(rootDir, opts = {}) {
24271
24361
  regenerating = false;
24272
24362
  }
24273
24363
  }
24274
- const watcher = (0, import_node_fs26.watch)(rootDir, { recursive: true }, (event, filename) => {
24364
+ const watcher = (0, import_node_fs27.watch)(rootDir, { recursive: true }, (event, filename) => {
24275
24365
  if (!filename) return;
24276
24366
  const rel = filename.toString();
24277
24367
  if (process.env.LAUNCH_CHART_WATCH_TRACE === "1") {
@@ -24304,12 +24394,12 @@ function startGraphWatcher(rootDir, opts = {}) {
24304
24394
  freshness: () => getFreshnessTracker(rootDir).get()
24305
24395
  };
24306
24396
  }
24307
- var import_node_fs26, import_node_path30, IGNORE_SEGMENTS, TRIGGER_EXTENSIONS, GRAPHS_RELATIVE;
24397
+ var import_node_fs27, import_node_path32, IGNORE_SEGMENTS, TRIGGER_EXTENSIONS, GRAPHS_RELATIVE;
24308
24398
  var init_watcher = __esm({
24309
24399
  "src/server/graph/core/watcher.ts"() {
24310
24400
  "use strict";
24311
- import_node_fs26 = require("node:fs");
24312
- import_node_path30 = require("node:path");
24401
+ import_node_fs27 = require("node:fs");
24402
+ import_node_path32 = require("node:path");
24313
24403
  init_launch_kit_paths();
24314
24404
  init_graph();
24315
24405
  init_freshness();
@@ -24338,7 +24428,7 @@ var init_watcher = __esm({
24338
24428
  ".prisma",
24339
24429
  ".sql"
24340
24430
  ]);
24341
- GRAPHS_RELATIVE = (0, import_node_path30.join)(LAUNCHSECURE_DIR, "graphs");
24431
+ GRAPHS_RELATIVE = (0, import_node_path32.join)(LAUNCHSECURE_DIR, "graphs");
24342
24432
  }
24343
24433
  });
24344
24434
 
@@ -26015,7 +26105,7 @@ var PostImplLaunchExecutor = class {
26015
26105
  return 3001;
26016
26106
  }
26017
26107
  startDevServer(port, databaseUrl) {
26018
- return new Promise((resolve5) => {
26108
+ return new Promise((resolve6) => {
26019
26109
  const env = { ...process.env, PORT: String(port), ...databaseUrl ? { DATABASE_URL: databaseUrl } : {} };
26020
26110
  this.devProcess = (0, import_child_process3.spawn)("npm", ["run", "dev"], {
26021
26111
  cwd: this.workingDir,
@@ -26027,7 +26117,7 @@ var PostImplLaunchExecutor = class {
26027
26117
  const timeout = setTimeout(() => {
26028
26118
  if (!resolved) {
26029
26119
  resolved = true;
26030
- this.healthCheck(port).then(resolve5);
26120
+ this.healthCheck(port).then(resolve6);
26031
26121
  }
26032
26122
  }, 15e3);
26033
26123
  const onData = (data) => {
@@ -26036,7 +26126,7 @@ var PostImplLaunchExecutor = class {
26036
26126
  if (!resolved) {
26037
26127
  resolved = true;
26038
26128
  clearTimeout(timeout);
26039
- resolve5(true);
26129
+ resolve6(true);
26040
26130
  }
26041
26131
  }
26042
26132
  };
@@ -26047,7 +26137,7 @@ var PostImplLaunchExecutor = class {
26047
26137
  if (!resolved) {
26048
26138
  resolved = true;
26049
26139
  clearTimeout(timeout);
26050
- resolve5(false);
26140
+ resolve6(false);
26051
26141
  }
26052
26142
  });
26053
26143
  this.devProcess.unref();
@@ -27392,7 +27482,7 @@ var ProjectMcpClient = class {
27392
27482
  this.initialized = true;
27393
27483
  }
27394
27484
  send(body) {
27395
- return new Promise((resolve5, reject) => {
27485
+ return new Promise((resolve6, reject) => {
27396
27486
  const headers = {
27397
27487
  ...this.headers,
27398
27488
  "Content-Length": String(Buffer.byteLength(body))
@@ -27417,7 +27507,7 @@ var ProjectMcpClient = class {
27417
27507
  return;
27418
27508
  }
27419
27509
  const sid = res.headers["mcp-session-id"];
27420
- resolve5({ body: text, sessionId: typeof sid === "string" ? sid : void 0 });
27510
+ resolve6({ body: text, sessionId: typeof sid === "string" ? sid : void 0 });
27421
27511
  });
27422
27512
  }
27423
27513
  );
@@ -28344,16 +28434,16 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28344
28434
  const tun = this.tunnel;
28345
28435
  this.tunnel = null;
28346
28436
  if (!tun) return;
28347
- return new Promise((resolve5) => {
28437
+ return new Promise((resolve6) => {
28348
28438
  tun.once("exit", () => {
28349
28439
  this.emit("stopped");
28350
- resolve5();
28440
+ resolve6();
28351
28441
  });
28352
28442
  try {
28353
28443
  tun.stop();
28354
28444
  } catch {
28355
28445
  }
28356
- setTimeout(() => resolve5(), 6e3);
28446
+ setTimeout(() => resolve6(), 6e3);
28357
28447
  });
28358
28448
  }
28359
28449
  spawnOnce() {
@@ -29007,10 +29097,10 @@ function streamTranscript(opts) {
29007
29097
  }
29008
29098
 
29009
29099
  // src/server/graph-mcp.ts
29010
- var import_node_fs27 = require("node:fs");
29011
- var import_node_path31 = require("node:path");
29100
+ var import_node_fs28 = require("node:fs");
29101
+ var import_node_path33 = require("node:path");
29012
29102
  var import_node_child_process3 = require("node:child_process");
29013
- var import_node_os5 = require("node:os");
29103
+ var import_node_os6 = require("node:os");
29014
29104
  init_launch_kit_paths();
29015
29105
  init_graph();
29016
29106
 
@@ -29753,6 +29843,7 @@ function generate(rootDir) {
29753
29843
  responses: deep.responses,
29754
29844
  params: deep.params,
29755
29845
  ...deep.effects ? { effects: deep.effects } : {},
29846
+ ...deep.notes ? { notes: deep.notes } : {},
29756
29847
  _dbCalls: dbCalls
29757
29848
  // temp: used for cross-ref building below
29758
29849
  });
@@ -29773,6 +29864,8 @@ function generate(rootDir) {
29773
29864
  conditions: deep.conditions,
29774
29865
  variables: deep.variables,
29775
29866
  ...deep.effects ? { effects: deep.effects } : {},
29867
+ ...deep.ui_labels ? { ui_labels: deep.ui_labels } : {},
29868
+ ...deep.notes ? { notes: deep.notes } : {},
29776
29869
  ...authWrappers.length > 0 ? { auth: authWrappers } : {},
29777
29870
  ...dbCalls.length > 0 ? { _dbCalls: dbCalls } : {}
29778
29871
  });
@@ -30374,6 +30467,7 @@ var prismaSchemaParser = {
30374
30467
  // src/server/graph/parsers/db/sql-migrations.ts
30375
30468
  var import_node_fs18 = require("node:fs");
30376
30469
  var import_node_path19 = require("node:path");
30470
+ var import_pgsql_parser = require("pgsql-parser");
30377
30471
  init_config();
30378
30472
  var PG_TO_PRISMA = {
30379
30473
  "TEXT": "String",
@@ -30405,243 +30499,6 @@ function pgTypeToPrisma(pgType) {
30405
30499
  const upper = pgType.toUpperCase().trim();
30406
30500
  return PG_TO_PRISMA[upper] ?? upper;
30407
30501
  }
30408
- var ID = `(?:"[\\w$]+"|[\\w$]+)`;
30409
- var QID = `(?:${ID}\\.)?${ID}`;
30410
- function bareName(captured) {
30411
- const parts = captured.split(".");
30412
- const last = parts[parts.length - 1];
30413
- return last.replace(/^"(.*)"$/, "$1").trim();
30414
- }
30415
- function parseCreateTable(sql, state) {
30416
- const re = new RegExp(
30417
- `CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
30418
- "gi"
30419
- );
30420
- let m;
30421
- while ((m = re.exec(sql)) !== null) {
30422
- const tableName = bareName(m[1]);
30423
- const body = m[2];
30424
- const columns = /* @__PURE__ */ new Map();
30425
- let primaryCol = null;
30426
- const inlineFks = [];
30427
- const lines = splitTopLevelCommas(body);
30428
- for (const raw of lines) {
30429
- const trimmed = raw.trim().replace(/,\s*$/, "");
30430
- if (!trimmed || trimmed.startsWith("--")) continue;
30431
- const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
30432
- if (namedPk) {
30433
- primaryCol = bareName(namedPk[1]);
30434
- continue;
30435
- }
30436
- const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
30437
- if (tablePk) {
30438
- primaryCol = bareName(tablePk[1]);
30439
- continue;
30440
- }
30441
- if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
30442
- const namedFk = trimmed.match(new RegExp(
30443
- `^CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
30444
- "i"
30445
- ));
30446
- if (namedFk) {
30447
- inlineFks.push({
30448
- constraintName: bareName(namedFk[1]),
30449
- sourceTable: tableName,
30450
- sourceColumn: bareName(namedFk[2]),
30451
- targetTable: bareName(namedFk[3]),
30452
- targetColumn: bareName(namedFk[4]),
30453
- onDelete: namedFk[5] ?? null
30454
- });
30455
- continue;
30456
- }
30457
- const bareFk = trimmed.match(new RegExp(
30458
- `^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
30459
- "i"
30460
- ));
30461
- if (bareFk) {
30462
- inlineFks.push({
30463
- constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
30464
- sourceTable: tableName,
30465
- sourceColumn: bareName(bareFk[1]),
30466
- targetTable: bareName(bareFk[2]),
30467
- targetColumn: bareName(bareFk[3]),
30468
- onDelete: bareFk[4] ?? null
30469
- });
30470
- continue;
30471
- }
30472
- if (/^CONSTRAINT\s/i.test(trimmed)) continue;
30473
- const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
30474
- if (!colMatch) continue;
30475
- const colName = bareName(colMatch[1]);
30476
- let rest = colMatch[2];
30477
- const inlineRefMatch = rest.match(new RegExp(
30478
- `\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
30479
- "i"
30480
- ));
30481
- if (inlineRefMatch) {
30482
- inlineFks.push({
30483
- constraintName: `${tableName}_${colName}_fkey`,
30484
- sourceTable: tableName,
30485
- sourceColumn: colName,
30486
- targetTable: bareName(inlineRefMatch[1]),
30487
- targetColumn: bareName(inlineRefMatch[2]),
30488
- onDelete: inlineRefMatch[3] ?? null
30489
- });
30490
- rest = rest.replace(inlineRefMatch[0], "").trim();
30491
- }
30492
- const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
30493
- const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
30494
- const isUnique = /\bUNIQUE\b/i.test(rest);
30495
- const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
30496
- const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
30497
- let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bPRIMARY\s+KEY\b/gi, "").replace(/\bUNIQUE\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
30498
- columns.set(colName, {
30499
- name: colName,
30500
- type: colType,
30501
- nullable: !isNotNull && !isPrimaryKey,
30502
- primary: isPrimaryKey,
30503
- unique: isUnique,
30504
- default: defaultVal
30505
- });
30506
- if (isPrimaryKey) primaryCol = colName;
30507
- }
30508
- if (primaryCol && columns.has(primaryCol)) {
30509
- columns.get(primaryCol).primary = true;
30510
- }
30511
- state.tables.set(tableName, { name: tableName, columns });
30512
- state.fks.push(...inlineFks);
30513
- }
30514
- }
30515
- function splitTopLevelCommas(body) {
30516
- const out = [];
30517
- let depth = 0;
30518
- let buf = "";
30519
- let inString = null;
30520
- for (const ch of body) {
30521
- if (inString) {
30522
- buf += ch;
30523
- if (ch === inString) inString = null;
30524
- continue;
30525
- }
30526
- if (ch === "'" || ch === '"') {
30527
- inString = ch;
30528
- buf += ch;
30529
- continue;
30530
- }
30531
- if (ch === "(") depth++;
30532
- else if (ch === ")") depth--;
30533
- if (ch === "," && depth === 0) {
30534
- out.push(buf);
30535
- buf = "";
30536
- continue;
30537
- }
30538
- buf += ch;
30539
- }
30540
- if (buf.trim()) out.push(buf);
30541
- return out;
30542
- }
30543
- function parseCreateEnum(sql, state) {
30544
- const re = new RegExp(
30545
- `CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
30546
- "gi"
30547
- );
30548
- let m;
30549
- while ((m = re.exec(sql)) !== null) {
30550
- const enumName = bareName(m[1]);
30551
- const valuesStr = m[2];
30552
- const values = new Set(
30553
- valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
30554
- );
30555
- state.enums.set(enumName, { name: enumName, values });
30556
- }
30557
- }
30558
- function parseAlterTable(sql, state) {
30559
- const addColRe = new RegExp(
30560
- `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
30561
- "gi"
30562
- );
30563
- let m;
30564
- while ((m = addColRe.exec(sql)) !== null) {
30565
- const tableName = bareName(m[1]);
30566
- const colName = bareName(m[2]);
30567
- let rest = m[3];
30568
- const table = state.tables.get(tableName);
30569
- if (!table) continue;
30570
- const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
30571
- const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)$/i);
30572
- const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
30573
- let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim();
30574
- table.columns.set(colName, {
30575
- name: colName,
30576
- type: colType,
30577
- nullable: !isNotNull,
30578
- primary: false,
30579
- unique: false,
30580
- default: defaultVal
30581
- });
30582
- }
30583
- const dropColRe = new RegExp(
30584
- `ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
30585
- "gi"
30586
- );
30587
- while ((m = dropColRe.exec(sql)) !== null) {
30588
- const table = state.tables.get(bareName(m[1]));
30589
- if (table) table.columns.delete(bareName(m[2]));
30590
- }
30591
- const fkRe = new RegExp(
30592
- `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
30593
- "gi"
30594
- );
30595
- while ((m = fkRe.exec(sql)) !== null) {
30596
- state.fks.push({
30597
- constraintName: bareName(m[2]),
30598
- sourceTable: bareName(m[1]),
30599
- sourceColumn: bareName(m[3]),
30600
- targetTable: bareName(m[4]),
30601
- targetColumn: bareName(m[5]),
30602
- onDelete: m[6] ?? null
30603
- });
30604
- }
30605
- }
30606
- function parseAlterEnum(sql, state) {
30607
- const re = new RegExp(
30608
- `ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
30609
- "gi"
30610
- );
30611
- let m;
30612
- while ((m = re.exec(sql)) !== null) {
30613
- const en = state.enums.get(bareName(m[1]));
30614
- if (en) en.values.add(m[2]);
30615
- }
30616
- }
30617
- function parseDropTable(sql, state) {
30618
- const re = new RegExp(
30619
- `DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
30620
- "gi"
30621
- );
30622
- let m;
30623
- while ((m = re.exec(sql)) !== null) {
30624
- const dropped = bareName(m[1]);
30625
- state.tables.delete(dropped);
30626
- state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
30627
- }
30628
- }
30629
- function parseUniqueIndex(sql, state) {
30630
- const re = new RegExp(
30631
- `CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
30632
- "gi"
30633
- );
30634
- let m;
30635
- while ((m = re.exec(sql)) !== null) {
30636
- const tableName = bareName(m[1]);
30637
- const colName = bareName(m[2]);
30638
- const table = state.tables.get(tableName);
30639
- const col = table?.columns.get(colName);
30640
- if (col) col.unique = true;
30641
- if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
30642
- state.uniqueIndexes.get(tableName).add(colName);
30643
- }
30644
- }
30645
30502
  function discoverMigrationFiles(migrationsDir) {
30646
30503
  if (!(0, import_node_fs18.existsSync)(migrationsDir)) return [];
30647
30504
  const out = [];
@@ -30656,25 +30513,614 @@ function discoverMigrationFiles(migrationsDir) {
30656
30513
  }
30657
30514
  return out;
30658
30515
  }
30659
- function parseMigrations(migrationsDir) {
30516
+ var postgresDialect = {
30517
+ parse(sql) {
30518
+ return (0, import_pgsql_parser.parseSync)(sql);
30519
+ },
30520
+ applyAll(ast, state, filepath) {
30521
+ const stmts = ast.stmts ?? [];
30522
+ extractTablesFromStmts(stmts, state);
30523
+ extractEnumsFromStmts(stmts, state);
30524
+ extractIndexesFromStmts(stmts, state, filepath);
30525
+ extractPoliciesFromStmts(stmts, state, filepath);
30526
+ extractExtensionsFromStmts(stmts, state, filepath);
30527
+ extractTriggersFromStmts(stmts, state, filepath);
30528
+ extractFunctionsFromStmts(stmts, state, filepath);
30529
+ extractViewsFromStmts(stmts, state, filepath);
30530
+ applyDropIndexes(stmts, state);
30531
+ applyDropPolicies(stmts, state);
30532
+ applyDropsForSchemaObjects(stmts, state);
30533
+ applyAstAlterEnums(stmts, state);
30534
+ applyAstAlterations(stmts, state);
30535
+ },
30536
+ extractMigrationInfo(ast, name, filepath) {
30537
+ const stmts = ast.stmts ?? [];
30538
+ return extractMigrationInfoFromStmts(stmts, name, filepath);
30539
+ }
30540
+ };
30541
+ function parseMigrations(migrationsDir, dialect = postgresDialect) {
30660
30542
  const state = {
30661
30543
  tables: /* @__PURE__ */ new Map(),
30662
30544
  enums: /* @__PURE__ */ new Map(),
30663
30545
  fks: [],
30664
- uniqueIndexes: /* @__PURE__ */ new Map()
30546
+ uniqueIndexes: /* @__PURE__ */ new Map(),
30547
+ indexes: [],
30548
+ policies: [],
30549
+ extensions: [],
30550
+ triggers: [],
30551
+ functions: [],
30552
+ views: []
30665
30553
  };
30666
30554
  if (!migrationsDir) return state;
30667
30555
  for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
30668
30556
  const sql = (0, import_node_fs18.readFileSync)(sqlPath, "utf-8");
30669
- parseCreateEnum(sql, state);
30670
- parseCreateTable(sql, state);
30671
- parseAlterTable(sql, state);
30672
- parseAlterEnum(sql, state);
30673
- parseDropTable(sql, state);
30674
- parseUniqueIndex(sql, state);
30557
+ let ast;
30558
+ try {
30559
+ ast = dialect.parse(sql);
30560
+ } catch {
30561
+ continue;
30562
+ }
30563
+ dialect.applyAll(ast, state, sqlPath);
30675
30564
  }
30676
30565
  return state;
30677
30566
  }
30567
+ function extractIndexesFromStmts(stmts, state, filepath) {
30568
+ for (const wrap of stmts) {
30569
+ const stmt = wrap.stmt ?? {};
30570
+ const ix = stmt.IndexStmt;
30571
+ if (!ix) continue;
30572
+ const name = ix.idxname ?? "";
30573
+ if (!name) continue;
30574
+ const table = ix.relation?.relname ?? "";
30575
+ const unique = !!ix.unique;
30576
+ const method = String(ix.accessMethod ?? "btree").toLowerCase();
30577
+ const params = ix.indexParams ?? [];
30578
+ const columns = [];
30579
+ let hasExpressions = false;
30580
+ for (const p of params) {
30581
+ const elem = p.IndexElem;
30582
+ if (!elem) continue;
30583
+ if (elem.name) columns.push(elem.name);
30584
+ else if (elem.expr) hasExpressions = true;
30585
+ }
30586
+ const hasPredicate = !!ix.whereClause;
30587
+ const existing = state.indexes.findIndex((i) => i.name === name);
30588
+ const next = { name, table, unique, method, columns, hasExpressions, hasPredicate, filepath };
30589
+ if (existing >= 0) state.indexes[existing] = next;
30590
+ else state.indexes.push(next);
30591
+ if (unique && columns.length === 1 && !hasPredicate && !hasExpressions) {
30592
+ const t = state.tables.get(table);
30593
+ const col = t?.columns.get(columns[0]);
30594
+ if (col) col.unique = true;
30595
+ if (!state.uniqueIndexes.has(table)) state.uniqueIndexes.set(table, /* @__PURE__ */ new Set());
30596
+ state.uniqueIndexes.get(table).add(columns[0]);
30597
+ }
30598
+ }
30599
+ }
30600
+ function applyDropIndexes(stmts, state) {
30601
+ for (const wrap of stmts) {
30602
+ const drop = wrap.stmt?.DropStmt;
30603
+ if (!drop || drop.removeType !== "OBJECT_INDEX") continue;
30604
+ const objects = drop.objects ?? [];
30605
+ const droppedNames = /* @__PURE__ */ new Set();
30606
+ for (const obj of objects) {
30607
+ const items = obj.List?.items ?? [];
30608
+ const last = items[items.length - 1]?.String?.sval;
30609
+ if (last) droppedNames.add(last);
30610
+ }
30611
+ if (droppedNames.size > 0) {
30612
+ state.indexes = state.indexes.filter((i) => !droppedNames.has(i.name));
30613
+ }
30614
+ }
30615
+ }
30616
+ function formatPgTypeName(typeName) {
30617
+ const names = (typeName?.names ?? []).map((n) => n.String?.sval ?? "").filter(Boolean);
30618
+ const base = (names[names.length - 1] ?? "").toLowerCase();
30619
+ const PG_INTERNAL_MAP = {
30620
+ int4: "INTEGER",
30621
+ int8: "BIGINT",
30622
+ int2: "SMALLINT",
30623
+ float8: "DOUBLE PRECISION",
30624
+ float4: "REAL",
30625
+ bool: "BOOLEAN",
30626
+ bpchar: "CHAR",
30627
+ timestamptz: "TIMESTAMPTZ",
30628
+ timestamp: "TIMESTAMP",
30629
+ numeric: "NUMERIC",
30630
+ text: "TEXT",
30631
+ varchar: "VARCHAR",
30632
+ jsonb: "JSONB",
30633
+ json: "JSON",
30634
+ uuid: "UUID",
30635
+ date: "DATE",
30636
+ bytea: "BYTEA"
30637
+ };
30638
+ return PG_INTERNAL_MAP[base] ?? base.toUpperCase();
30639
+ }
30640
+ function applyAstAlterations(stmts, state) {
30641
+ for (const wrap of stmts) {
30642
+ const stmt = wrap.stmt ?? {};
30643
+ const kind = Object.keys(stmt)[0];
30644
+ if (!kind) continue;
30645
+ if (kind === "AlterTableStmt") {
30646
+ const body = stmt.AlterTableStmt;
30647
+ const tableName = body.relation?.relname ?? "";
30648
+ const table = state.tables.get(tableName);
30649
+ if (!table) continue;
30650
+ const cmds = body.cmds ?? [];
30651
+ for (const c of cmds) {
30652
+ const cmd = c.AlterTableCmd;
30653
+ if (!cmd) continue;
30654
+ const subtype = cmd.subtype ?? "";
30655
+ const colName = cmd.name ?? "";
30656
+ const col = colName ? table.columns.get(colName) : void 0;
30657
+ switch (subtype) {
30658
+ case "AT_AlterColumnType": {
30659
+ if (!col) break;
30660
+ const typeName = cmd.def?.ColumnDef?.typeName ?? cmd.def?.typeName;
30661
+ if (typeName) col.type = formatPgTypeNameWithMods(typeName);
30662
+ break;
30663
+ }
30664
+ case "AT_SetNotNull":
30665
+ if (col) col.nullable = false;
30666
+ break;
30667
+ case "AT_DropNotNull":
30668
+ if (col) col.nullable = true;
30669
+ break;
30670
+ case "AT_AddColumn": {
30671
+ const cd = cmd.def?.ColumnDef;
30672
+ if (!cd) break;
30673
+ const newColName = cd.colname ?? "";
30674
+ if (!newColName) break;
30675
+ if (table.columns.has(newColName)) break;
30676
+ let nullable = true;
30677
+ let primary = false;
30678
+ let unique = false;
30679
+ let defaultVal = null;
30680
+ for (const c2 of cd.constraints ?? []) {
30681
+ const ct = c2.Constraint;
30682
+ if (!ct) continue;
30683
+ if (ct.contype === "CONSTR_NOTNULL") nullable = false;
30684
+ else if (ct.contype === "CONSTR_PRIMARY") {
30685
+ primary = true;
30686
+ nullable = false;
30687
+ } else if (ct.contype === "CONSTR_UNIQUE") unique = true;
30688
+ else if (ct.contype === "CONSTR_DEFAULT") defaultVal = "<expr>";
30689
+ }
30690
+ table.columns.set(newColName, {
30691
+ name: newColName,
30692
+ type: formatPgTypeNameWithMods(cd.typeName),
30693
+ nullable,
30694
+ primary,
30695
+ unique,
30696
+ default: defaultVal
30697
+ });
30698
+ break;
30699
+ }
30700
+ case "AT_DropColumn":
30701
+ if (colName) table.columns.delete(colName);
30702
+ break;
30703
+ case "AT_AddConstraint": {
30704
+ const ct = cmd.def?.Constraint;
30705
+ if (!ct) break;
30706
+ if (ct.contype !== "CONSTR_FOREIGN") break;
30707
+ const fkCols = (ct.fk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30708
+ const pkCols = (ct.pk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30709
+ const pkTable = ct.pktable?.relname ?? "";
30710
+ if (fkCols.length && pkCols.length && pkTable) {
30711
+ state.fks.push({
30712
+ constraintName: ct.conname || `${tableName}_${fkCols[0]}_fkey`,
30713
+ sourceTable: tableName,
30714
+ sourceColumn: fkCols[0],
30715
+ targetTable: pkTable,
30716
+ targetColumn: pkCols[0],
30717
+ onDelete: mapFkAction(ct.fk_del_action)
30718
+ });
30719
+ }
30720
+ break;
30721
+ }
30722
+ }
30723
+ }
30724
+ } else if (kind === "RenameStmt") {
30725
+ const body = stmt.RenameStmt;
30726
+ const renameType = body.renameType ?? "";
30727
+ const newName = body.newname ?? "";
30728
+ if (renameType === "OBJECT_COLUMN") {
30729
+ const tableName = body.relation?.relname ?? "";
30730
+ const oldName = body.subname ?? "";
30731
+ const table = state.tables.get(tableName);
30732
+ if (!table || !oldName || !newName) continue;
30733
+ const col = table.columns.get(oldName);
30734
+ if (col) {
30735
+ col.name = newName;
30736
+ table.columns.delete(oldName);
30737
+ table.columns.set(newName, col);
30738
+ }
30739
+ } else if (renameType === "OBJECT_TABLE") {
30740
+ const oldName = body.relation?.relname ?? "";
30741
+ if (!oldName || !newName) continue;
30742
+ const t = state.tables.get(oldName);
30743
+ if (!t) continue;
30744
+ state.tables.delete(oldName);
30745
+ t.name = newName;
30746
+ state.tables.set(newName, t);
30747
+ for (const fk of state.fks) {
30748
+ if (fk.sourceTable === oldName) fk.sourceTable = newName;
30749
+ if (fk.targetTable === oldName) fk.targetTable = newName;
30750
+ }
30751
+ }
30752
+ }
30753
+ }
30754
+ }
30755
+ function extractPoliciesFromStmts(stmts, state, filepath) {
30756
+ for (const wrap of stmts) {
30757
+ const body = wrap.stmt?.CreatePolicyStmt;
30758
+ if (!body) continue;
30759
+ const name = body.policy_name ?? "";
30760
+ if (!name) continue;
30761
+ const table = body.table?.relname ?? "";
30762
+ const cmdRaw = String(body.cmd_name ?? "all").toUpperCase();
30763
+ const command = ["SELECT", "INSERT", "UPDATE", "DELETE", "ALL"].includes(cmdRaw) ? cmdRaw : "ALL";
30764
+ const permissive = body.permissive === true;
30765
+ const roles = (body.roles ?? []).map((r) => {
30766
+ const rs = r.RoleSpec;
30767
+ if (!rs) return "";
30768
+ if (rs.roletype === "ROLESPEC_PUBLIC") return "public";
30769
+ if (rs.roletype === "ROLESPEC_CURRENT_USER") return "current_user";
30770
+ if (rs.roletype === "ROLESPEC_CSTRING" && rs.rolename) return rs.rolename;
30771
+ return "";
30772
+ }).filter(Boolean);
30773
+ const hasUsing = !!body.qual;
30774
+ const hasWithCheck = !!body.with_check;
30775
+ const existing = state.policies.findIndex((p) => p.table === table && p.name === name);
30776
+ const next = { name, table, command, permissive, roles, hasUsing, hasWithCheck, filepath };
30777
+ if (existing >= 0) state.policies[existing] = next;
30778
+ else state.policies.push(next);
30779
+ }
30780
+ }
30781
+ function applyDropPolicies(stmts, state) {
30782
+ for (const wrap of stmts) {
30783
+ const drop = wrap.stmt?.DropStmt;
30784
+ if (!drop || drop.removeType !== "OBJECT_POLICY") continue;
30785
+ const objects = drop.objects ?? [];
30786
+ for (const obj of objects) {
30787
+ const items = obj.List?.items ?? [];
30788
+ if (items.length < 2) continue;
30789
+ const table = items[0]?.String?.sval ?? "";
30790
+ const policyName = items[items.length - 1]?.String?.sval ?? "";
30791
+ if (!table || !policyName) continue;
30792
+ state.policies = state.policies.filter((p) => !(p.table === table && p.name === policyName));
30793
+ }
30794
+ }
30795
+ }
30796
+ function mapFkAction(action) {
30797
+ if (!action) return null;
30798
+ const m = {
30799
+ r: "RESTRICT",
30800
+ c: "CASCADE",
30801
+ s: "SET NULL",
30802
+ d: "SET DEFAULT",
30803
+ a: "NO ACTION",
30804
+ // pgsql-parser may also emit FKCONSTR_ACTION_* enum strings:
30805
+ FKCONSTR_ACTION_RESTRICT: "RESTRICT",
30806
+ FKCONSTR_ACTION_CASCADE: "CASCADE",
30807
+ FKCONSTR_ACTION_SETNULL: "SET NULL",
30808
+ FKCONSTR_ACTION_SETDEFAULT: "SET DEFAULT",
30809
+ FKCONSTR_ACTION_NOACTION: "NO ACTION"
30810
+ };
30811
+ return m[action] ?? null;
30812
+ }
30813
+ function formatPgTypeNameWithMods(typeName) {
30814
+ const base = formatPgTypeName(typeName);
30815
+ if (base === "String" || base === "unknown") return base;
30816
+ const typmods = [];
30817
+ for (const m of typeName?.typmods ?? []) {
30818
+ const v = m.A_Const?.ival?.ival;
30819
+ if (typeof v === "number") typmods.push(v);
30820
+ }
30821
+ return typmods.length ? `${base}(${typmods.join(",")})` : base;
30822
+ }
30823
+ function extractTablesFromStmts(stmts, state) {
30824
+ for (const wrap of stmts) {
30825
+ const body = wrap.stmt?.CreateStmt;
30826
+ if (!body) continue;
30827
+ const tableName = body.relation?.relname ?? "";
30828
+ if (!tableName) continue;
30829
+ const columns = /* @__PURE__ */ new Map();
30830
+ const fks = [];
30831
+ let primaryCol = null;
30832
+ for (const elt of body.tableElts ?? []) {
30833
+ if (elt.ColumnDef) {
30834
+ const cd = elt.ColumnDef;
30835
+ const colName = cd.colname ?? "";
30836
+ if (!colName) continue;
30837
+ const colType = formatPgTypeNameWithMods(cd.typeName);
30838
+ let nullable = true;
30839
+ let primary = false;
30840
+ let unique = false;
30841
+ let defaultVal = null;
30842
+ for (const c of cd.constraints ?? []) {
30843
+ const ct = c.Constraint;
30844
+ if (!ct) continue;
30845
+ switch (ct.contype) {
30846
+ case "CONSTR_NOTNULL":
30847
+ nullable = false;
30848
+ break;
30849
+ case "CONSTR_PRIMARY":
30850
+ primary = true;
30851
+ nullable = false;
30852
+ primaryCol = colName;
30853
+ break;
30854
+ case "CONSTR_UNIQUE":
30855
+ unique = true;
30856
+ break;
30857
+ case "CONSTR_DEFAULT":
30858
+ defaultVal = "<expr>";
30859
+ break;
30860
+ case "CONSTR_FOREIGN": {
30861
+ const pkTable = ct.pktable?.relname ?? "";
30862
+ const pkCols = (ct.pk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30863
+ if (pkTable && pkCols.length) {
30864
+ fks.push({
30865
+ constraintName: ct.conname || `${tableName}_${colName}_fkey`,
30866
+ sourceTable: tableName,
30867
+ sourceColumn: colName,
30868
+ targetTable: pkTable,
30869
+ targetColumn: pkCols[0],
30870
+ onDelete: mapFkAction(ct.fk_del_action)
30871
+ });
30872
+ }
30873
+ break;
30874
+ }
30875
+ }
30876
+ }
30877
+ columns.set(colName, {
30878
+ name: colName,
30879
+ type: colType,
30880
+ nullable,
30881
+ primary,
30882
+ unique,
30883
+ default: defaultVal
30884
+ });
30885
+ } else if (elt.Constraint) {
30886
+ const ct = elt.Constraint;
30887
+ switch (ct.contype) {
30888
+ case "CONSTR_PRIMARY": {
30889
+ const keys = (ct.keys ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30890
+ if (keys.length) primaryCol = keys[0];
30891
+ break;
30892
+ }
30893
+ case "CONSTR_FOREIGN": {
30894
+ const fkCols = (ct.fk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30895
+ const pkCols = (ct.pk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30896
+ const pkTable = ct.pktable?.relname ?? "";
30897
+ if (fkCols.length && pkCols.length && pkTable) {
30898
+ fks.push({
30899
+ constraintName: ct.conname || `${tableName}_${fkCols[0]}_fkey`,
30900
+ sourceTable: tableName,
30901
+ sourceColumn: fkCols[0],
30902
+ targetTable: pkTable,
30903
+ targetColumn: pkCols[0],
30904
+ onDelete: mapFkAction(ct.fk_del_action)
30905
+ });
30906
+ }
30907
+ break;
30908
+ }
30909
+ }
30910
+ }
30911
+ }
30912
+ if (primaryCol && columns.has(primaryCol)) {
30913
+ columns.get(primaryCol).primary = true;
30914
+ columns.get(primaryCol).nullable = false;
30915
+ }
30916
+ state.tables.set(tableName, { name: tableName, columns });
30917
+ state.fks.push(...fks);
30918
+ }
30919
+ }
30920
+ function extractEnumsFromStmts(stmts, state) {
30921
+ for (const wrap of stmts) {
30922
+ const body = wrap.stmt?.CreateEnumStmt;
30923
+ if (!body) continue;
30924
+ const names = (body.typeName ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30925
+ const enumName = names[names.length - 1] ?? "";
30926
+ if (!enumName) continue;
30927
+ const vals = new Set(
30928
+ (body.vals ?? []).map((s) => s.String?.sval ?? "").filter(Boolean)
30929
+ );
30930
+ state.enums.set(enumName, { name: enumName, values: vals });
30931
+ }
30932
+ }
30933
+ function applyAstAlterEnums(stmts, state) {
30934
+ for (const wrap of stmts) {
30935
+ const body = wrap.stmt?.AlterEnumStmt;
30936
+ if (!body) continue;
30937
+ const names = (body.typeName ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
30938
+ const enumName = names[names.length - 1] ?? "";
30939
+ const en = state.enums.get(enumName);
30940
+ if (!en) continue;
30941
+ if (body.newVal) en.values.add(String(body.newVal));
30942
+ }
30943
+ }
30944
+ function extractExtensionsFromStmts(stmts, state, filepath) {
30945
+ for (const wrap of stmts) {
30946
+ const body = wrap.stmt?.CreateExtensionStmt;
30947
+ if (!body) continue;
30948
+ const name = body.extname ?? "";
30949
+ if (!name) continue;
30950
+ let schema = null;
30951
+ let version2 = null;
30952
+ for (const opt of body.options ?? []) {
30953
+ const de = opt.DefElem;
30954
+ if (!de) continue;
30955
+ if (de.defname === "schema" && de.arg?.String?.sval) schema = de.arg.String.sval;
30956
+ else if (de.defname === "new_version" && de.arg?.String?.sval) version2 = de.arg.String.sval;
30957
+ }
30958
+ const next = { name, schema, version: version2, filepath };
30959
+ const existing = state.extensions.findIndex((e) => e.name === name);
30960
+ if (existing >= 0) state.extensions[existing] = next;
30961
+ else state.extensions.push(next);
30962
+ }
30963
+ }
30964
+ function extractTriggersFromStmts(stmts, state, filepath) {
30965
+ for (const wrap of stmts) {
30966
+ const body = wrap.stmt?.CreateTrigStmt;
30967
+ if (!body) continue;
30968
+ const name = body.trigname ?? "";
30969
+ if (!name) continue;
30970
+ const table = body.relation?.relname ?? "";
30971
+ const timingVal = body.timing ?? 0;
30972
+ const eventsVal = body.events ?? 0;
30973
+ const timing = timingVal & 2 ? "BEFORE" : timingVal & 64 ? "INSTEAD OF" : "AFTER";
30974
+ const events = [];
30975
+ if (eventsVal & 4) events.push("INSERT");
30976
+ if (eventsVal & 8) events.push("DELETE");
30977
+ if (eventsVal & 16) events.push("UPDATE");
30978
+ if (eventsVal & 32) events.push("TRUNCATE");
30979
+ const funcname = body.funcname ?? [];
30980
+ const funcCall = funcname[funcname.length - 1]?.String?.sval ?? "";
30981
+ const forEach = body.row ? "ROW" : "STATEMENT";
30982
+ const hasWhen = !!body.whenClause;
30983
+ const next = { name, table, timing, events, function: funcCall, hasWhen, forEach, filepath };
30984
+ const existing = state.triggers.findIndex((t) => t.table === table && t.name === name);
30985
+ if (existing >= 0) state.triggers[existing] = next;
30986
+ else state.triggers.push(next);
30987
+ }
30988
+ }
30989
+ function functionIdFor(name, schema) {
30990
+ return schema ? `${schema}.${name}` : name;
30991
+ }
30992
+ function extractFunctionsFromStmts(stmts, state, filepath) {
30993
+ for (const wrap of stmts) {
30994
+ const body = wrap.stmt?.CreateFunctionStmt;
30995
+ if (!body) continue;
30996
+ const fn = body.funcname ?? [];
30997
+ if (fn.length === 0) continue;
30998
+ const name = fn[fn.length - 1]?.String?.sval ?? "";
30999
+ if (!name) continue;
31000
+ const schema = fn.length > 1 ? fn[fn.length - 2]?.String?.sval ?? null : null;
31001
+ let language = "sql";
31002
+ for (const opt of body.options ?? []) {
31003
+ const de = opt.DefElem;
31004
+ if (de?.defname === "language" && de.arg?.String?.sval) language = de.arg.String.sval;
31005
+ }
31006
+ const returnType = body.returnType ? formatPgTypeName(body.returnType) : "";
31007
+ const isProcedure = !!body.is_procedure;
31008
+ const next = { name, schema, language, returnType, isProcedure, filepath };
31009
+ const id = functionIdFor(name, schema);
31010
+ const existing = state.functions.findIndex((f) => functionIdFor(f.name, f.schema) === id);
31011
+ if (existing >= 0) state.functions[existing] = next;
31012
+ else state.functions.push(next);
31013
+ }
31014
+ }
31015
+ function extractViewsFromStmts(stmts, state, filepath) {
31016
+ for (const wrap of stmts) {
31017
+ const stmt = wrap.stmt ?? {};
31018
+ const view = stmt.ViewStmt;
31019
+ if (view) {
31020
+ const name = view.view?.relname ?? "";
31021
+ if (!name) continue;
31022
+ const schema = view.view?.schemaname ?? null;
31023
+ const next = {
31024
+ name,
31025
+ schema,
31026
+ isMaterialized: false,
31027
+ withCheckOption: String(view.withCheckOption ?? "NO_CHECK_OPTION"),
31028
+ filepath
31029
+ };
31030
+ const id = functionIdFor(name, schema);
31031
+ const existing = state.views.findIndex((v) => functionIdFor(v.name, v.schema) === id);
31032
+ if (existing >= 0) state.views[existing] = next;
31033
+ else state.views.push(next);
31034
+ }
31035
+ const ctas = stmt.CreateTableAsStmt;
31036
+ if (ctas && ctas.objtype === "OBJECT_MATVIEW") {
31037
+ const name = ctas.into?.rel?.relname ?? "";
31038
+ if (!name) continue;
31039
+ const schema = ctas.into?.rel?.schemaname ?? null;
31040
+ const next = {
31041
+ name,
31042
+ schema,
31043
+ isMaterialized: true,
31044
+ withCheckOption: "N/A",
31045
+ filepath
31046
+ };
31047
+ const id = functionIdFor(name, schema);
31048
+ const existing = state.views.findIndex((v) => functionIdFor(v.name, v.schema) === id);
31049
+ if (existing >= 0) state.views[existing] = next;
31050
+ else state.views.push(next);
31051
+ }
31052
+ }
31053
+ }
31054
+ function applyDropsForSchemaObjects(stmts, state) {
31055
+ for (const wrap of stmts) {
31056
+ const drop = wrap.stmt?.DropStmt;
31057
+ if (!drop) continue;
31058
+ const removeType = drop.removeType ?? "";
31059
+ const objects = drop.objects ?? [];
31060
+ if (removeType === "OBJECT_TABLE") {
31061
+ const droppedTables = /* @__PURE__ */ new Set();
31062
+ for (const obj of objects) {
31063
+ const items = obj.List?.items ?? [];
31064
+ const last = items[items.length - 1]?.String?.sval;
31065
+ if (last) droppedTables.add(last);
31066
+ }
31067
+ if (droppedTables.size > 0) {
31068
+ for (const t of droppedTables) state.tables.delete(t);
31069
+ state.fks = state.fks.filter((fk) => !droppedTables.has(fk.sourceTable) && !droppedTables.has(fk.targetTable));
31070
+ }
31071
+ } else if (removeType === "OBJECT_TYPE") {
31072
+ const droppedEnums = /* @__PURE__ */ new Set();
31073
+ for (const obj of objects) {
31074
+ const tn = obj.TypeName;
31075
+ if (!tn) continue;
31076
+ const names = (tn.names ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
31077
+ const last = names[names.length - 1];
31078
+ if (last) droppedEnums.add(last);
31079
+ }
31080
+ for (const e of droppedEnums) state.enums.delete(e);
31081
+ } else if (removeType === "OBJECT_EXTENSION") {
31082
+ const names = /* @__PURE__ */ new Set();
31083
+ for (const obj of objects) {
31084
+ const sval = obj.String?.sval;
31085
+ if (sval) names.add(sval);
31086
+ }
31087
+ if (names.size > 0) state.extensions = state.extensions.filter((e) => !names.has(e.name));
31088
+ } else if (removeType === "OBJECT_TRIGGER") {
31089
+ for (const obj of objects) {
31090
+ const items = obj.List?.items ?? [];
31091
+ if (items.length < 2) continue;
31092
+ const table = items[0]?.String?.sval ?? "";
31093
+ const trigName = items[items.length - 1]?.String?.sval ?? "";
31094
+ if (!table || !trigName) continue;
31095
+ state.triggers = state.triggers.filter((t) => !(t.table === table && t.name === trigName));
31096
+ }
31097
+ } else if (removeType === "OBJECT_FUNCTION" || removeType === "OBJECT_PROCEDURE") {
31098
+ for (const obj of objects) {
31099
+ const items = obj.ObjectWithArgs?.objname?.items ?? obj.ObjectWithArgs?.objname ?? obj.List?.items ?? [];
31100
+ if (!items.length) continue;
31101
+ const segs = items.map((s) => s.String?.sval ?? "").filter(Boolean);
31102
+ if (!segs.length) continue;
31103
+ const name = segs[segs.length - 1];
31104
+ const schema = segs.length > 1 ? segs[segs.length - 2] : null;
31105
+ const id = functionIdFor(name, schema);
31106
+ state.functions = state.functions.filter((f) => functionIdFor(f.name, f.schema) !== id);
31107
+ }
31108
+ } else if (removeType === "OBJECT_VIEW" || removeType === "OBJECT_MATVIEW") {
31109
+ for (const obj of objects) {
31110
+ const items = obj.List?.items ?? [];
31111
+ if (!items.length) continue;
31112
+ const name = items[items.length - 1]?.String?.sval ?? "";
31113
+ const schema = items.length > 1 ? items[items.length - 2]?.String?.sval ?? null : null;
31114
+ if (!name) continue;
31115
+ const id = functionIdFor(name, schema);
31116
+ state.views = state.views.filter((v) => functionIdFor(v.name, v.schema) !== id);
31117
+ }
31118
+ }
31119
+ }
31120
+ }
31121
+ function indexIsPrismaUncoverable(idx) {
31122
+ return idx.hasPredicate || idx.hasExpressions || idx.method !== "btree";
31123
+ }
30678
31124
  function loadPrismaState(schemaPath) {
30679
31125
  if (!schemaPath || !(0, import_node_fs18.existsSync)(schemaPath)) return null;
30680
31126
  const content = (0, import_node_fs18.readFileSync)(schemaPath, "utf-8");
@@ -30841,6 +31287,96 @@ function verify(sqlState, prisma) {
30841
31287
  }
30842
31288
  return { contradictions, flaggedEdges };
30843
31289
  }
31290
+ function deriveMigrationName(sqlPath) {
31291
+ const segments = sqlPath.split(/[\\/]/);
31292
+ const last = segments[segments.length - 1];
31293
+ if (last === "migration.sql" && segments.length >= 2) {
31294
+ return segments[segments.length - 2];
31295
+ }
31296
+ return last.replace(/\.sql$/, "");
31297
+ }
31298
+ function extractMigrationInfoFromStmts(stmts, name, filepath) {
31299
+ let isDestructive = false;
31300
+ let hasOrphanCheck = false;
31301
+ let hasSidecarBackup = false;
31302
+ let hasPreFlightNotice = false;
31303
+ let containsBackfill = false;
31304
+ let containsDropColumn = false;
31305
+ let containsDropTable = false;
31306
+ for (const wrap of stmts) {
31307
+ const stmt = wrap.stmt ?? {};
31308
+ const kind = Object.keys(stmt)[0];
31309
+ if (!kind) continue;
31310
+ const body = stmt[kind] ?? {};
31311
+ switch (kind) {
31312
+ case "AlterTableStmt": {
31313
+ const cmds = body.cmds ?? [];
31314
+ for (const c of cmds) {
31315
+ const subtype = c.AlterTableCmd?.subtype;
31316
+ if (subtype === "AT_DropColumn") {
31317
+ containsDropColumn = true;
31318
+ isDestructive = true;
31319
+ } else if (subtype === "AT_AlterColumnType" || subtype === "AT_DropNotNull" || subtype === "AT_DropConstraint") {
31320
+ isDestructive = true;
31321
+ }
31322
+ }
31323
+ break;
31324
+ }
31325
+ case "DropStmt": {
31326
+ const removeType = body.removeType ?? "";
31327
+ if (removeType === "OBJECT_TABLE") {
31328
+ containsDropTable = true;
31329
+ isDestructive = true;
31330
+ } else if (removeType === "OBJECT_TYPE" || removeType === "OBJECT_COLUMN" || removeType === "OBJECT_INDEX" || removeType === "OBJECT_POLICY") {
31331
+ isDestructive = true;
31332
+ }
31333
+ break;
31334
+ }
31335
+ case "CreateStmt": {
31336
+ const relname = body.relation?.relname ?? "";
31337
+ if (relname.startsWith("_backup_")) hasSidecarBackup = true;
31338
+ break;
31339
+ }
31340
+ case "CreateTableAsStmt": {
31341
+ const relname = body.into?.rel?.relname ?? "";
31342
+ if (relname.startsWith("_backup_")) hasSidecarBackup = true;
31343
+ break;
31344
+ }
31345
+ case "UpdateStmt":
31346
+ case "InsertStmt":
31347
+ case "DeleteStmt": {
31348
+ containsBackfill = true;
31349
+ break;
31350
+ }
31351
+ case "DoStmt": {
31352
+ const args = body.args ?? [];
31353
+ for (const arg of args) {
31354
+ const def = arg.DefElem;
31355
+ if (!def || def.defname !== "as") continue;
31356
+ const code = def.arg?.String?.sval ?? "";
31357
+ if (/\bRAISE\s+EXCEPTION\b/i.test(code)) hasOrphanCheck = true;
31358
+ if (/\bRAISE\s+NOTICE\b/i.test(code)) hasPreFlightNotice = true;
31359
+ }
31360
+ break;
31361
+ }
31362
+ }
31363
+ }
31364
+ const tsMatch = name.match(/^(\d{8,14})/);
31365
+ const timestamp = tsMatch ? tsMatch[1] : null;
31366
+ return {
31367
+ name,
31368
+ filepath,
31369
+ timestamp,
31370
+ isDestructive,
31371
+ hasOrphanCheck,
31372
+ hasSidecarBackup,
31373
+ hasPreFlightNotice,
31374
+ containsBackfill,
31375
+ containsDropColumn,
31376
+ containsDropTable,
31377
+ statementCount: stmts.length
31378
+ };
31379
+ }
30844
31380
  function migrationsDirFor(rootDir) {
30845
31381
  const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
30846
31382
  if (!paths) return null;
@@ -30895,6 +31431,132 @@ function generate3(rootDir) {
30895
31431
  values: [...sqlEnum.values]
30896
31432
  });
30897
31433
  }
31434
+ let indexNodeCount = 0;
31435
+ for (const idx of sqlState.indexes) {
31436
+ if (!indexIsPrismaUncoverable(idx)) continue;
31437
+ nodes.push({
31438
+ id: `index:${idx.name}`,
31439
+ type: "index",
31440
+ name: idx.name,
31441
+ source: "sql",
31442
+ table: idx.table,
31443
+ unique: idx.unique,
31444
+ method: idx.method,
31445
+ columns: idx.columns,
31446
+ has_expressions: idx.hasExpressions,
31447
+ has_predicate: idx.hasPredicate,
31448
+ filepath: idx.filepath
31449
+ });
31450
+ indexNodeCount++;
31451
+ }
31452
+ let extensionNodeCount = 0;
31453
+ for (const ext of sqlState.extensions) {
31454
+ nodes.push({
31455
+ id: `extension:${ext.name}`,
31456
+ type: "extension",
31457
+ name: ext.name,
31458
+ source: "sql",
31459
+ schema: ext.schema,
31460
+ version: ext.version,
31461
+ filepath: ext.filepath
31462
+ });
31463
+ extensionNodeCount++;
31464
+ }
31465
+ let triggerNodeCount = 0;
31466
+ for (const trg of sqlState.triggers) {
31467
+ nodes.push({
31468
+ id: `trigger:${trg.table}:${trg.name}`,
31469
+ type: "trigger",
31470
+ name: trg.name,
31471
+ source: "sql",
31472
+ table: trg.table,
31473
+ timing: trg.timing,
31474
+ events: trg.events,
31475
+ function: trg.function,
31476
+ has_when: trg.hasWhen,
31477
+ for_each: trg.forEach,
31478
+ filepath: trg.filepath
31479
+ });
31480
+ triggerNodeCount++;
31481
+ }
31482
+ let functionNodeCount = 0;
31483
+ for (const fn of sqlState.functions) {
31484
+ const qualified = fn.schema ? `${fn.schema}.${fn.name}` : fn.name;
31485
+ nodes.push({
31486
+ id: `function:${qualified}`,
31487
+ type: "function",
31488
+ name: fn.name,
31489
+ source: "sql",
31490
+ schema: fn.schema,
31491
+ language: fn.language,
31492
+ return_type: fn.returnType,
31493
+ is_procedure: fn.isProcedure,
31494
+ filepath: fn.filepath
31495
+ });
31496
+ functionNodeCount++;
31497
+ }
31498
+ let viewNodeCount = 0;
31499
+ for (const vw of sqlState.views) {
31500
+ const qualified = vw.schema ? `${vw.schema}.${vw.name}` : vw.name;
31501
+ nodes.push({
31502
+ id: `${vw.isMaterialized ? "matview" : "view"}:${qualified}`,
31503
+ type: vw.isMaterialized ? "materialized_view" : "view",
31504
+ name: vw.name,
31505
+ source: "sql",
31506
+ schema: vw.schema,
31507
+ is_materialized: vw.isMaterialized,
31508
+ with_check_option: vw.withCheckOption,
31509
+ filepath: vw.filepath
31510
+ });
31511
+ viewNodeCount++;
31512
+ }
31513
+ let policyNodeCount = 0;
31514
+ for (const pol of sqlState.policies) {
31515
+ nodes.push({
31516
+ id: `policy:${pol.table}:${pol.name}`,
31517
+ type: "policy",
31518
+ name: pol.name,
31519
+ source: "sql",
31520
+ table: pol.table,
31521
+ command: pol.command,
31522
+ permissive: pol.permissive,
31523
+ roles: pol.roles,
31524
+ has_using: pol.hasUsing,
31525
+ has_with_check: pol.hasWithCheck,
31526
+ filepath: pol.filepath
31527
+ });
31528
+ policyNodeCount++;
31529
+ }
31530
+ const migrationFiles = migrationsDir ? discoverMigrationFiles(migrationsDir) : [];
31531
+ let migrationNodeCount = 0;
31532
+ for (const sqlPath of migrationFiles) {
31533
+ const sql = (0, import_node_fs18.readFileSync)(sqlPath, "utf-8");
31534
+ const name = deriveMigrationName(sqlPath);
31535
+ let ast;
31536
+ try {
31537
+ ast = postgresDialect.parse(sql);
31538
+ } catch {
31539
+ ast = { stmts: [] };
31540
+ }
31541
+ const info = postgresDialect.extractMigrationInfo(ast, name, sqlPath);
31542
+ nodes.push({
31543
+ id: `migration:${name}`,
31544
+ type: "migration",
31545
+ name,
31546
+ source: "sql",
31547
+ filepath: info.filepath,
31548
+ timestamp: info.timestamp,
31549
+ is_destructive: info.isDestructive,
31550
+ has_orphan_check: info.hasOrphanCheck,
31551
+ has_sidecar_backup: info.hasSidecarBackup,
31552
+ has_pre_flight_notice: info.hasPreFlightNotice,
31553
+ contains_backfill: info.containsBackfill,
31554
+ contains_drop_column: info.containsDropColumn,
31555
+ contains_drop_table: info.containsDropTable,
31556
+ statement_count: info.statementCount
31557
+ });
31558
+ migrationNodeCount++;
31559
+ }
30898
31560
  const sqlOnlyTables = new Set(nodes.filter((n) => n.type === "table").map((n) => n.id));
30899
31561
  const edges = sqlState.fks.filter((fk) => sqlOnlyTables.has(fk.sourceTable)).map((fk) => ({
30900
31562
  source: fk.sourceTable,
@@ -30913,6 +31575,13 @@ function generate3(rootDir) {
30913
31575
  sql_tables: sqlState.tables.size,
30914
31576
  sql_enums: sqlState.enums.size,
30915
31577
  sql_fks: sqlState.fks.length,
31578
+ sql_index_nodes: indexNodeCount,
31579
+ sql_policy_nodes: policyNodeCount,
31580
+ sql_extension_nodes: extensionNodeCount,
31581
+ sql_trigger_nodes: triggerNodeCount,
31582
+ sql_function_nodes: functionNodeCount,
31583
+ sql_view_nodes: viewNodeCount,
31584
+ sql_migration_nodes: migrationNodeCount,
30916
31585
  additive_nodes: nodes.length,
30917
31586
  contradictions_found: contradictions.length,
30918
31587
  flagged_edges_found: flaggedEdges.length
@@ -33053,15 +33722,75 @@ function runAudit(rootDir, layer, check) {
33053
33722
  }
33054
33723
 
33055
33724
  // src/server/graph/core/projects.ts
33725
+ var import_node_path31 = require("node:path");
33726
+
33727
+ // src/server/lib/worktree.ts
33728
+ var import_node_path30 = require("node:path");
33729
+
33730
+ // src/server/orbit/registry.ts
33731
+ var import_node_fs26 = require("node:fs");
33732
+ var import_node_os5 = require("node:os");
33056
33733
  var import_node_path29 = require("node:path");
33734
+ init_launch_kit_paths();
33735
+ var REGISTRY_DIR = (0, import_node_path29.join)((0, import_node_os5.homedir)(), LAUNCHSECURE_DIR, "orbit");
33736
+ var REGISTRY_PATH = (0, import_node_path29.join)(REGISTRY_DIR, "state.json");
33737
+ var LOCK_PATH = (0, import_node_path29.join)(REGISTRY_DIR, "state.json.lock");
33738
+ function emptyRegistry() {
33739
+ return { version: 1, worktrees: {} };
33740
+ }
33741
+ function readRegistry() {
33742
+ if (!(0, import_node_fs26.existsSync)(REGISTRY_PATH)) return emptyRegistry();
33743
+ try {
33744
+ const parsed = JSON.parse((0, import_node_fs26.readFileSync)(REGISTRY_PATH, "utf-8"));
33745
+ if (parsed?.version === 1 && parsed.worktrees && typeof parsed.worktrees === "object") {
33746
+ return parsed;
33747
+ }
33748
+ } catch {
33749
+ }
33750
+ return emptyRegistry();
33751
+ }
33752
+ function listWorktrees() {
33753
+ return Object.values(readRegistry().worktrees);
33754
+ }
33755
+
33756
+ // src/server/lib/worktree.ts
33757
+ var 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`.";
33758
+ var 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.";
33759
+ function resolveWorktreeRoot(slug, monorepoRoot) {
33760
+ const local = listWorktrees().filter((w) => w.projectRoot === monorepoRoot);
33761
+ const match = local.find((w) => w.slug === slug);
33762
+ if (match) return match.path;
33763
+ if (local.length === 0) {
33764
+ throw new Error(
33765
+ `worktree="${slug}" requested but no worktrees are registered for this project. Run \`launch-orbit create <branch>\` first, or use \`project_root\` to point at an arbitrary path.`
33766
+ );
33767
+ }
33768
+ const available = local.map((w) => `"${w.slug}" (${w.branch})`).join(", ");
33769
+ throw new Error(`Unknown worktree "${slug}". Available: ${available}.`);
33770
+ }
33771
+ function resolveWorktreeOrProjectRoot(args, monorepoRoot) {
33772
+ const projectRoot = typeof args.project_root === "string" ? args.project_root.trim() : "";
33773
+ if (projectRoot) {
33774
+ return (0, import_node_path30.isAbsolute)(projectRoot) ? projectRoot : (0, import_node_path30.resolve)(monorepoRoot, projectRoot);
33775
+ }
33776
+ const worktree = typeof args.worktree === "string" ? args.worktree.trim() : "";
33777
+ if (worktree) {
33778
+ return resolveWorktreeRoot(worktree, monorepoRoot);
33779
+ }
33780
+ return null;
33781
+ }
33782
+
33783
+ // src/server/graph/core/projects.ts
33057
33784
  init_config();
33785
+ var WORKTREE_PARAM_DESCRIPTION2 = WORKTREE_PARAM_DESCRIPTION;
33786
+ var PROJECT_ROOT_PARAM_DESCRIPTION2 = PROJECT_ROOT_PARAM_DESCRIPTION;
33058
33787
  function listProjects(monorepoRoot) {
33059
33788
  const cfg = loadConfig(monorepoRoot);
33060
33789
  const entries = cfg.projects ?? [];
33061
33790
  return entries.map((p) => ({
33062
33791
  name: p.name,
33063
33792
  root: p.root,
33064
- absoluteRoot: (0, import_node_path29.resolve)(monorepoRoot, p.root)
33793
+ absoluteRoot: (0, import_node_path31.resolve)(monorepoRoot, p.root)
33065
33794
  }));
33066
33795
  }
33067
33796
  function resolveProject(name, projects) {
@@ -33084,6 +33813,12 @@ function resolveProjectRoot(project, monorepoRoot) {
33084
33813
  return resolveProject(raw, projects).absoluteRoot;
33085
33814
  }
33086
33815
  var PROJECT_PARAM_DESCRIPTION = "Optional sub-project name (or root path) from .launchchart.json projects[]. Defaults to the monorepo root. Run detect_project_stack to list configured projects.";
33816
+ function resolveRequestRoot(args, monorepoRoot) {
33817
+ const fromArgs = resolveWorktreeOrProjectRoot(args, monorepoRoot);
33818
+ if (fromArgs) return fromArgs;
33819
+ const project = typeof args.project === "string" ? args.project : void 0;
33820
+ return resolveProjectRoot(project, monorepoRoot);
33821
+ }
33087
33822
 
33088
33823
  // src/server/graph-mcp.ts
33089
33824
  init_freshness();
@@ -33105,13 +33840,21 @@ var TOOLS = [
33105
33840
  project: {
33106
33841
  type: "string",
33107
33842
  description: PROJECT_PARAM_DESCRIPTION + " Special: omit to regenerate ALL configured projects."
33843
+ },
33844
+ worktree: {
33845
+ type: "string",
33846
+ description: WORKTREE_PARAM_DESCRIPTION2
33847
+ },
33848
+ project_root: {
33849
+ type: "string",
33850
+ description: PROJECT_ROOT_PARAM_DESCRIPTION2
33108
33851
  }
33109
33852
  }
33110
33853
  }
33111
33854
  },
33112
33855
  {
33113
33856
  name: "read_graph",
33114
- description: 'Query the structural project graph \u2014 use INSTEAD of Glob and Grep for locating files, understanding structure, and navigating the codebase. Faster and more accurate than file-system search because it returns typed nodes with metadata and relationships. \n\nUSE THIS FOR: "where is X", "what files are in module Y", "what pages exist under /admin", "what components does Z render", "what tables relate to User", "list all hooks in auth module", "which endpoints touch the User table", "what auth strategy does this endpoint use". \n\nDO NOT USE FOR: understanding what\'s INSIDE a component (use inspect_node for elements, conditions, state, variables, responses), reading actual source code (use Read). \n\nQUERY PARAMS (at least one required for node data \u2014 unfiltered calls return summary only to stay in context):\n- search: substring match on node id, name, or route\n- type: filter by node type (ui layer: page, layout, component, ui, hook, context, config, util; api layer: endpoint; db layer: table, enum)\n- module: filter by module tag (computed from directory structure, e.g. "auth", "admin", "settings")\n- node_id: return this node + its neighborhood (incoming+outgoing edges within `hops`)\n- hops: neighborhood radius when node_id is set (default 1)\n- minimal: return only id/type/name/module/route per node (skip heavy fields like columns, exports)\n- include_edges: return the actual edge list. Default: TRUE for neighborhood queries (node_id), FALSE for filter queries (search/type/module). Filter responses always include `edge_count`; only pass include_edges:true when you actually need to inspect individual edges (e.g. "which components render X"). This default cuts typical filter responses in half.\n\nBATCH MODE: pass `queries` (array of query objects) to run multiple independent queries in a single call. Each query object uses the same params (layer/search/type/module/node_id/hops/minimal). Returns { batch: true, count, results: [{index, query, result}, ...] }. Use this when you need multiple graph views up-front (e.g. scoping a feature across ui+api+db layers) to save round-trips. When batch mode is used, top-level params are ignored.\n\nReturns: filtered nodes + edges between them. If no filter given, returns per-layer counts and type breakdown only.\n\nWIRE FORMAT (compact): responses that include nodes/edges use short keys and edge-by-index refs to cut payload ~40-60%. Every such response carries a `_schema` legend. Quick reference:\n nodes[]: { i: id, t: type, n: name, m: module, r: route, mt: methods, x: exports, c: columns }\n edges[]: { s: source_node_index, d: target_node_index, t: type, l: label }\nedges.s / edges.d are 0-based indices into THIS response\'s nodes array. If a referenced node is not in the response (boundary case), s/d may instead contain the full node id string \u2014 always check the type.\n\nPAGINATION (filter queries):\n- Use `offset` and `limit` to paginate through large result sets.\n- Response includes: `total` (matched), `returned` (in this page), `has_more`, `next_offset`.\n- If `has_more: true`, call again with `offset: next_offset` to get the next page.\n\nBUDGET GUARDS:\n- Neighborhood queries stop expanding when the projected response exceeds budget. The response then contains `budget_exceeded: true` plus `hops_traversed < hops_requested`. When this happens, drill into a specific neighbor with another node_id call rather than retrying with larger hops \u2014 it will just truncate again.\n- Batch mode caps total response size. Once the budget is hit, later queries return `{skipped: true, reason: "batch_budget_exhausted"}` and you must re-run them individually.\n\nMONOREPOS: pass `project: "<name>"` to query a sub-project graph (defined in .launchchart.json projects[]). Omitting `project` targets the monorepo root. In batch mode the top-level `project` is inherited by sub-queries that do not set their own. Run detect_project_stack to list configured projects.',
33857
+ description: 'Query the structural project graph \u2014 use INSTEAD of Glob and Grep for locating files, understanding structure, and navigating the codebase. Faster and more accurate than file-system search because it returns typed nodes with metadata and relationships. \n\nUSE THIS FOR: "where is X", "what files are in module Y", "what pages exist under /admin", "what components does Z render", "what tables relate to User", "list all hooks in auth module", "which endpoints touch the User table", "what auth strategy does this endpoint use". \n\nDO NOT USE FOR: understanding what\'s INSIDE a component (use inspect_node for elements, conditions, state, variables, responses), reading actual source code (use Read). \n\nQUERY PARAMS (at least one required for node data \u2014 unfiltered calls return summary only to stay in context):\n- search: substring match on node id, name, route, JSX element text/string-prop literals, ui_labels (strings from `const X = [{label:\'\u2026\'}]` data arrays), and notes (tagged comments). Lets queries like search:"Briefs" find a page where "Briefs" is a tab label inside an array, or search:"FIXME" find every file with a FIXME comment. For exhaustive note listings use list_notes.\n- type: filter by node type (ui layer: page, layout, component, ui, hook, context, config, util; api layer: endpoint; db layer: table, enum, migration). Migration nodes carry safety attributes \u2014 is_destructive, has_orphan_check, has_sidecar_backup, has_pre_flight_notice, contains_backfill, contains_drop_column, contains_drop_table, statement_count, timestamp \u2014 queryable via tag_key filters or by inspecting returned node fields.\n- include_findings: db layer only. When true, response includes `contradictions` and `flagged_edges` arrays surfacing SQL\u2194ORM schema drift detected by the SQL migrations parser. Use this to audit "schema vs migrations" disagreement (missing columns, type mismatches, nullability drift, FKs declared in SQL but not ORM).\n- module: filter by module tag (computed from directory structure, e.g. "auth", "admin", "settings")\n- node_id: return this node + its neighborhood (incoming+outgoing edges within `hops`)\n- hops: neighborhood radius when node_id is set (default 1)\n- minimal: return only id/type/name/module/route per node (skip heavy fields like columns, exports)\n- include_edges: return the actual edge list. Default: TRUE for neighborhood queries (node_id), FALSE for filter queries (search/type/module). Filter responses always include `edge_count`; only pass include_edges:true when you actually need to inspect individual edges (e.g. "which components render X"). This default cuts typical filter responses in half.\n\nBATCH MODE: pass `queries` (array of query objects) to run multiple independent queries in a single call. Each query object uses the same params (layer/search/type/module/node_id/hops/minimal). Returns { batch: true, count, results: [{index, query, result}, ...] }. Use this when you need multiple graph views up-front (e.g. scoping a feature across ui+api+db layers) to save round-trips. When batch mode is used, top-level params are ignored.\n\nReturns: filtered nodes + edges between them. If no filter given, returns per-layer counts and type breakdown only.\n\nWIRE FORMAT (compact): responses that include nodes/edges use short keys and edge-by-index refs to cut payload ~40-60%. Every such response carries a `_schema` legend. Quick reference:\n nodes[]: { i: id, t: type, n: name, m: module, r: route, mt: methods, x: exports, c: columns }\n edges[]: { s: source_node_index, d: target_node_index, t: type, l: label }\nedges.s / edges.d are 0-based indices into THIS response\'s nodes array. If a referenced node is not in the response (boundary case), s/d may instead contain the full node id string \u2014 always check the type.\n\nPAGINATION (filter queries):\n- Use `offset` and `limit` to paginate through large result sets.\n- Response includes: `total` (matched), `returned` (in this page), `has_more`, `next_offset`.\n- If `has_more: true`, call again with `offset: next_offset` to get the next page.\n\nBUDGET GUARDS:\n- Neighborhood queries stop expanding when the projected response exceeds budget. The response then contains `budget_exceeded: true` plus `hops_traversed < hops_requested`. When this happens, drill into a specific neighbor with another node_id call rather than retrying with larger hops \u2014 it will just truncate again.\n- Batch mode caps total response size. Once the budget is hit, later queries return `{skipped: true, reason: "batch_budget_exhausted"}` and you must re-run them individually.\n\nMONOREPOS: pass `project: "<name>"` to query a sub-project graph (defined in .launchchart.json projects[]). Omitting `project` targets the monorepo root. In batch mode the top-level `project` is inherited by sub-queries that do not set their own. Run detect_project_stack to list configured projects.',
33115
33858
  inputSchema: {
33116
33859
  type: "object",
33117
33860
  properties: {
@@ -33121,7 +33864,7 @@ var TOOLS = [
33121
33864
  },
33122
33865
  search: {
33123
33866
  type: "string",
33124
- description: "Case-insensitive substring match against node id, name, or route."
33867
+ description: "Case-insensitive substring match against node id, name, route, JSX element text/string-prop literals, and ui_labels (strings from `const X = [{label:'\u2026'}]` data arrays)."
33125
33868
  },
33126
33869
  type: {
33127
33870
  type: "string",
@@ -33155,6 +33898,10 @@ var TOOLS = [
33155
33898
  type: "boolean",
33156
33899
  description: "Include the edge list in the response. Default TRUE for neighborhood queries (node_id), FALSE for filter queries. Filter responses always include edge_count. Only set true on filter queries when you actually need edge data."
33157
33900
  },
33901
+ include_findings: {
33902
+ type: "boolean",
33903
+ description: "DB layer only. When true, response includes `contradictions[]` and `flagged_edges[]` arrays from the SQL migrations parser \u2014 SQL\u2194ORM schema drift findings (missing columns/tables, type mismatches, nullability drift, FKs in SQL but no ORM @relation). Default false."
33904
+ },
33158
33905
  offset: {
33159
33906
  type: "number",
33160
33907
  description: "Skip first N matched nodes (pagination). Default 0. Use next_offset from a previous response to get the next page."
@@ -33165,7 +33912,7 @@ var TOOLS = [
33165
33912
  },
33166
33913
  queries: {
33167
33914
  type: "array",
33168
- description: "Batch mode \u2014 array of query objects to run in a single call. Each uses the same param schema (including `project`). When set, top-level params are ignored. Subject to an aggregate size budget \u2014 later queries may return a skipped stub.",
33915
+ description: "Batch mode \u2014 array of query objects to run in a single call. Each uses the same param schema (including `project` / `worktree` / `project_root`). Top-level root args are inherited by sub-queries that don't specify their own. Subject to an aggregate size budget \u2014 later queries may return a skipped stub.",
33169
33916
  items: {
33170
33917
  type: "object",
33171
33918
  properties: {
@@ -33177,13 +33924,24 @@ var TOOLS = [
33177
33924
  hops: { type: "number" },
33178
33925
  minimal: { type: "boolean" },
33179
33926
  include_edges: { type: "boolean" },
33180
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
33927
+ include_findings: { type: "boolean" },
33928
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
33929
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
33930
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33181
33931
  }
33182
33932
  }
33183
33933
  },
33184
33934
  project: {
33185
33935
  type: "string",
33186
33936
  description: PROJECT_PARAM_DESCRIPTION
33937
+ },
33938
+ worktree: {
33939
+ type: "string",
33940
+ description: WORKTREE_PARAM_DESCRIPTION2
33941
+ },
33942
+ project_root: {
33943
+ type: "string",
33944
+ description: PROJECT_ROOT_PARAM_DESCRIPTION2
33187
33945
  }
33188
33946
  }
33189
33947
  }
@@ -33231,7 +33989,9 @@ Returns: { pattern, filter, files_searched, total_matches, matches: [{file, line
33231
33989
  context: { type: "number", description: "Context lines around each match. Default 2." },
33232
33990
  max_matches: { type: "number", description: "Max matches to return total. Default 50." },
33233
33991
  max_files: { type: "number", description: "Max files to search. Default 50." },
33234
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
33992
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
33993
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
33994
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33235
33995
  },
33236
33996
  required: ["layer", "pattern"]
33237
33997
  }
@@ -33273,7 +34033,9 @@ Returns deep fields only \u2014 not structural metadata (use read_graph for that
33273
34033
  type: "boolean",
33274
34034
  description: "Case-insensitive filter matching. Default true."
33275
34035
  },
33276
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
34036
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
34037
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
34038
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33277
34039
  },
33278
34040
  required: ["layer"]
33279
34041
  }
@@ -33324,7 +34086,9 @@ Use this when the user asks "is the chart running", "show me the project graph U
33324
34086
  type: "string",
33325
34087
  description: 'Optional specific key to look up within the chosen kind (e.g. "moon-shadow-blur"). When omitted, returns the full {key:nodes} map for the kind.'
33326
34088
  },
33327
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
34089
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
34090
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
34091
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33328
34092
  }
33329
34093
  }
33330
34094
  },
@@ -33354,7 +34118,9 @@ Use this when the user asks "is the chart running", "show me the project graph U
33354
34118
  type: "string",
33355
34119
  description: 'Tag value (e.g. "auth", "alice", "true").'
33356
34120
  },
33357
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
34121
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
34122
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
34123
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33358
34124
  },
33359
34125
  required: ["node_id", "key", "value"]
33360
34126
  }
@@ -33373,7 +34139,9 @@ Use this when the user asks "is the chart running", "show me the project graph U
33373
34139
  type: "string",
33374
34140
  description: "Tag key to remove."
33375
34141
  },
33376
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
34142
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
34143
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
34144
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33377
34145
  },
33378
34146
  required: ["node_id", "key"]
33379
34147
  }
@@ -33392,7 +34160,9 @@ Use this when the user asks "is the chart running", "show me the project graph U
33392
34160
  type: "string",
33393
34161
  description: "Specific check to run (e.g. 'schema_drift', 'unprotected_routes'). Omit to run all checks for the layer."
33394
34162
  },
33395
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
34163
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
34164
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
34165
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33396
34166
  },
33397
34167
  required: ["layer"]
33398
34168
  }
@@ -33428,10 +34198,56 @@ Example: blast_points(node_id: "server/auth/middleware.ts", hops: 2) \u2192 retu
33428
34198
  enum: ["reverse", "both"],
33429
34199
  description: "'reverse' (default) = only what depends on this node. 'both' = full neighborhood."
33430
34200
  },
33431
- project: { type: "string", description: PROJECT_PARAM_DESCRIPTION }
34201
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
34202
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
34203
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
33432
34204
  },
33433
34205
  required: ["node_id"]
33434
34206
  }
34207
+ },
34208
+ {
34209
+ name: "list_notes",
34210
+ description: 'List tagged comments across the project graph \u2014 TODO, FIXME, HACK, NOTE, SECURITY, etc. Any `// KIND: body` or `/* KIND: body */` comment where KIND is an all-caps identifier (2\u201316 chars) is captured automatically; team conventions like `// CLAUDE:` are discovered without configuration.\n\nKinds are categorized at read time:\n actionable: TODO, FIXME, HACK, XXX, REFACTOR, OPTIMIZE, REVIEW\n warning: SECURITY, WARNING, IMPORTANT, CAUTION, DANGER, DEPRECATED\n doc: NOTE, TIP, SEE, NB, INFO, EXAMPLE\n custom: anything else (team-specific conventions)\n\nDefault category filter is `actionable,warning` \u2014 the "what should I act on" view. Pass category:"all" for everything including doc + custom.\n\nReturns: { total, returned, has_more, items: [{file, line, kind, category, text, author?, module?}] }.',
34211
+ inputSchema: {
34212
+ type: "object",
34213
+ properties: {
34214
+ layer: {
34215
+ type: "string",
34216
+ description: "Restrict to one layer ('ui', 'api', 'db'). Default: scan all layers that have notes."
34217
+ },
34218
+ kind: {
34219
+ type: "string",
34220
+ description: 'Exact kind match, case-insensitive (e.g. "TODO", "FIXME", "SECURITY").'
34221
+ },
34222
+ category: {
34223
+ type: "string",
34224
+ description: "'actionable' | 'warning' | 'doc' | 'custom' | 'all'. Comma-separated list also accepted. Default: 'actionable,warning'."
34225
+ },
34226
+ module: {
34227
+ type: "string",
34228
+ description: 'Restrict to nodes carrying this module tag (e.g. "auth", "work-items").'
34229
+ },
34230
+ pattern: {
34231
+ type: "string",
34232
+ description: 'Regex applied to note body text (case-insensitive). Use to grep within bodies, e.g. "race condition".'
34233
+ },
34234
+ author: {
34235
+ type: "string",
34236
+ description: "Match author from `// TODO(alice): \u2026` syntax, case-insensitive."
34237
+ },
34238
+ limit: {
34239
+ type: "number",
34240
+ description: "Max items returned. Default 100. Pair with offset for pagination."
34241
+ },
34242
+ offset: {
34243
+ type: "number",
34244
+ description: "Skip first N items. Default 0."
34245
+ },
34246
+ project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
34247
+ worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
34248
+ project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
34249
+ }
34250
+ }
33435
34251
  }
33436
34252
  ];
33437
34253
  function matchesSearch(node, query) {
@@ -33440,14 +34256,44 @@ function matchesSearch(node, query) {
33440
34256
  if (node.name.toLowerCase().includes(q)) return true;
33441
34257
  const route = node.route;
33442
34258
  if (route && route.toLowerCase().includes(q)) return true;
34259
+ const elements = node.elements;
34260
+ if (elements) {
34261
+ for (const el of elements) {
34262
+ if (el.text && el.text.toLowerCase().includes(q)) return true;
34263
+ if (el.props) {
34264
+ for (const v of Object.values(el.props)) {
34265
+ if (typeof v !== "string") continue;
34266
+ if (v.includes("=>") || v.startsWith("(") || v.startsWith("{")) continue;
34267
+ if (v.toLowerCase().includes(q)) return true;
34268
+ }
34269
+ }
34270
+ }
34271
+ }
34272
+ const uiLabels = node.ui_labels;
34273
+ if (uiLabels) {
34274
+ for (const lbl of uiLabels) {
34275
+ if (typeof lbl === "string" && lbl.toLowerCase().includes(q)) return true;
34276
+ }
34277
+ }
34278
+ const notes = node.notes;
34279
+ if (notes) {
34280
+ for (const n of notes) {
34281
+ if (n.kind && n.kind.toLowerCase().includes(q)) return true;
34282
+ if (n.text && n.text.toLowerCase().includes(q)) return true;
34283
+ }
34284
+ }
33443
34285
  return false;
33444
34286
  }
34287
+ var MINIMAL_STRIP_FIELDS = /* @__PURE__ */ new Set(["columns"]);
33445
34288
  function toMinimal(nodes) {
33446
34289
  return nodes.map((n) => {
33447
34290
  const out = { id: n.id, type: n.type, name: n.name };
33448
- if (n.tags != null) out.tags = n.tags;
33449
- if (n.route != null) out.route = n.route;
33450
- if (n.methods != null) out.methods = n.methods;
34291
+ for (const [k, v] of Object.entries(n)) {
34292
+ if (k === "id" || k === "type" || k === "name") continue;
34293
+ if (MINIMAL_STRIP_FIELDS.has(k)) continue;
34294
+ if (DEEP_FIELDS.has(k)) continue;
34295
+ if (v != null) out[k] = v;
34296
+ }
33451
34297
  return out;
33452
34298
  });
33453
34299
  }
@@ -33498,8 +34344,34 @@ var DEEP_FIELDS = /* @__PURE__ */ new Set([
33498
34344
  "variables",
33499
34345
  "responses",
33500
34346
  "params",
33501
- "effects"
34347
+ "effects",
34348
+ "ui_labels",
34349
+ "notes"
33502
34350
  ]);
34351
+ var NOTE_KIND_CATEGORY = {
34352
+ TODO: "actionable",
34353
+ FIXME: "actionable",
34354
+ HACK: "actionable",
34355
+ XXX: "actionable",
34356
+ REFACTOR: "actionable",
34357
+ OPTIMIZE: "actionable",
34358
+ REVIEW: "actionable",
34359
+ SECURITY: "warning",
34360
+ WARNING: "warning",
34361
+ IMPORTANT: "warning",
34362
+ CAUTION: "warning",
34363
+ DANGER: "warning",
34364
+ DEPRECATED: "warning",
34365
+ NOTE: "doc",
34366
+ TIP: "doc",
34367
+ SEE: "doc",
34368
+ NB: "doc",
34369
+ INFO: "doc",
34370
+ EXAMPLE: "doc"
34371
+ };
34372
+ function categorizeNoteKind(kind) {
34373
+ return NOTE_KIND_CATEGORY[kind] ?? "custom";
34374
+ }
33503
34375
  var EST_CHARS_PER_NODE_FULL = {
33504
34376
  ui: 300,
33505
34377
  api: 300,
@@ -33775,7 +34647,7 @@ function withFreshnessMeta(result, args) {
33775
34647
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return result;
33776
34648
  let rootDir;
33777
34649
  try {
33778
- rootDir = resolveProjectRoot(args.project, process.cwd());
34650
+ rootDir = resolveRequestRoot(args, process.cwd());
33779
34651
  } catch {
33780
34652
  return result;
33781
34653
  }
@@ -33790,7 +34662,7 @@ function withFreshnessMeta(result, args) {
33790
34662
  }
33791
34663
  function resolveOrErr(args) {
33792
34664
  try {
33793
- return { rootDir: resolveProjectRoot(args.project, process.cwd()) };
34665
+ return { rootDir: resolveRequestRoot(args, process.cwd()) };
33794
34666
  } catch (e) {
33795
34667
  return err(e.message);
33796
34668
  }
@@ -33799,6 +34671,8 @@ async function handleGenerateGraph(args) {
33799
34671
  const monorepoRoot = process.cwd();
33800
34672
  const layer = args.layer;
33801
34673
  const projectArg = typeof args.project === "string" ? args.project.trim() : "";
34674
+ const worktreeArg = typeof args.worktree === "string" ? args.worktree.trim() : "";
34675
+ const projectRootArg = typeof args.project_root === "string" ? args.project_root.trim() : "";
33802
34676
  function formatProjectResult(results2, relativeRoot) {
33803
34677
  return results2.map((r) => {
33804
34678
  const warnings = r.output.warnings.length;
@@ -33806,25 +34680,27 @@ async function handleGenerateGraph(args) {
33806
34680
  }).join("\n") + `
33807
34681
  \u2192 ${relativeRoot}/.launchsecure/graphs/`;
33808
34682
  }
33809
- if (projectArg) {
34683
+ if (projectArg || worktreeArg || projectRootArg) {
33810
34684
  let rootDir;
33811
34685
  try {
33812
- rootDir = resolveProjectRoot(projectArg, monorepoRoot);
34686
+ rootDir = resolveRequestRoot(args, monorepoRoot);
33813
34687
  } catch (e) {
33814
34688
  return err(e.message);
33815
34689
  }
33816
34690
  const results2 = await generateGraph(rootDir, layer);
34691
+ const label = worktreeArg ? `worktree "${worktreeArg}"` : projectArg ? `project "${projectArg}"` : `root "${projectRootArg}"`;
34692
+ const queryHint = worktreeArg ? `read_graph (with worktree="${worktreeArg}")` : projectArg ? `read_graph (with project="${projectArg}")` : `read_graph (with project_root="${projectRootArg}")`;
33817
34693
  if (results2.length === 0) {
33818
34694
  return err(
33819
- layer ? `No parser detected for the "${layer}" layer in project "${projectArg}".` : `No parsers detected for project "${projectArg}". Check that the project root has the expected structure.`
34695
+ layer ? `No parser detected for the "${layer}" layer in ${label}.` : `No parsers detected for ${label}. Check that the root has the expected structure.`
33820
34696
  );
33821
34697
  }
33822
34698
  return ok(
33823
- `Graph generated successfully for project "${projectArg}".
34699
+ `Graph generated successfully for ${label}.
33824
34700
 
33825
- ${formatProjectResult(results2, projectArg)}
34701
+ ${formatProjectResult(results2, rootDir)}
33826
34702
 
33827
- Use read_graph (with project="${projectArg}") to query.`
34703
+ Use ${queryHint} to query.`
33828
34704
  );
33829
34705
  }
33830
34706
  const projects = listProjects(monorepoRoot);
@@ -33887,6 +34763,7 @@ function runReadGraphQueryRaw(rootDir, args) {
33887
34763
  const layerIsDb = args.layer === "db";
33888
34764
  const minimal = args.minimal ?? layerIsDb;
33889
34765
  const includeEdges = args.include_edges;
34766
+ const includeFindings = args.include_findings === true;
33890
34767
  const offset = args.offset ?? 0;
33891
34768
  const limit = args.limit;
33892
34769
  const hasFilter = !!(search || type || module_ || nodeId || tagKey && tagValue);
@@ -33936,14 +34813,23 @@ function runReadGraphQueryRaw(rootDir, args) {
33936
34813
  result2.budget_exceeded = true;
33937
34814
  result2.hint = `Neighborhood truncated at hop ${nb.stoppedAtHop} (projected size exceeded budget). To explore further, call read_graph with node_id set to a specific neighbor from the returned nodes, or rerun with hops=${Math.max(1, nb.stoppedAtHop)} to confirm the partial view is what you wanted.`;
33938
34815
  }
34816
+ if (includeFindings && layer === "db") {
34817
+ result2.contradictions = graph.contradictions ?? [];
34818
+ result2.flagged_edges = graph.flagged_edges ?? [];
34819
+ }
33939
34820
  return result2;
33940
34821
  }
33941
34822
  if (!hasFilter) {
33942
- return {
34823
+ const summaryResult = {
33943
34824
  hint: "No filter specified \u2014 returning summary only. Use search/type/module/node_id to retrieve nodes.",
33944
34825
  layer,
33945
34826
  summary: layerSummary(graph)
33946
34827
  };
34828
+ if (includeFindings && layer === "db") {
34829
+ summaryResult.contradictions = graph.contradictions ?? [];
34830
+ summaryResult.flagged_edges = graph.flagged_edges ?? [];
34831
+ }
34832
+ return summaryResult;
33947
34833
  }
33948
34834
  const matched = graph.nodes.filter((n) => {
33949
34835
  if (search && !matchesSearch(n, search)) return false;
@@ -33994,6 +34880,10 @@ function runReadGraphQueryRaw(rootDir, args) {
33994
34880
  } else if (returnedEdges.length > 0) {
33995
34881
  result.edges_hint = `${returnedEdges.length} edges between matched nodes omitted. Pass include_edges:true to retrieve them (only do this when you actually need edge data).`;
33996
34882
  }
34883
+ if (includeFindings && layer === "db") {
34884
+ result.contradictions = graph.contradictions ?? [];
34885
+ result.flagged_edges = graph.flagged_edges ?? [];
34886
+ }
33997
34887
  return result;
33998
34888
  }
33999
34889
  function runReadGraphQuery(rootDir, args) {
@@ -34008,6 +34898,8 @@ function handleReadGraph(args) {
34008
34898
  return err("queries array is empty. Provide at least one query object.");
34009
34899
  }
34010
34900
  const inheritedProject = typeof args.project === "string" ? args.project : void 0;
34901
+ const inheritedWorktree = typeof args.worktree === "string" ? args.worktree : void 0;
34902
+ const inheritedProjectRoot = typeof args.project_root === "string" ? args.project_root : void 0;
34011
34903
  const results = [];
34012
34904
  let cumulativeChars = 0;
34013
34905
  let budgetHit = false;
@@ -34025,15 +34917,18 @@ function handleReadGraph(args) {
34025
34917
  });
34026
34918
  continue;
34027
34919
  }
34028
- const qWithProject = inheritedProject && !q.project ? { ...q, project: inheritedProject } : q;
34920
+ const qInherited = { ...q };
34921
+ if (inheritedProject && !qInherited.project) qInherited.project = inheritedProject;
34922
+ if (inheritedWorktree && !qInherited.worktree) qInherited.worktree = inheritedWorktree;
34923
+ if (inheritedProjectRoot && !qInherited.project_root) qInherited.project_root = inheritedProjectRoot;
34029
34924
  let perQueryRoot;
34030
34925
  try {
34031
- perQueryRoot = resolveProjectRoot(qWithProject.project, monorepoRoot);
34926
+ perQueryRoot = resolveRequestRoot(qInherited, monorepoRoot);
34032
34927
  } catch (e) {
34033
34928
  results.push({ index: i, query: q, result: { error: e.message } });
34034
34929
  continue;
34035
34930
  }
34036
- const r = runReadGraphQuery(perQueryRoot, qWithProject);
34931
+ const r = runReadGraphQuery(perQueryRoot, qInherited);
34037
34932
  const entry = { index: i, query: q, result: r };
34038
34933
  const entrySize = JSON.stringify(entry, null, 2).length;
34039
34934
  if (cumulativeChars + entrySize > BATCH_BUDGET_CHARS && results.length > 0) {
@@ -34066,12 +34961,12 @@ function handleReadGraph(args) {
34066
34961
  return okJson(result);
34067
34962
  }
34068
34963
  function nodeToFilePath(rootDir, layer, nodeId) {
34069
- if (layer === "ui" || layer === "api") return (0, import_node_path31.join)(rootDir, "src", nodeId);
34070
- if (layer === "db") return (0, import_node_path31.join)(rootDir, "prisma", "schema.prisma");
34071
- const withSrc = (0, import_node_path31.join)(rootDir, "src", nodeId);
34072
- if ((0, import_node_fs27.existsSync)(withSrc)) return withSrc;
34073
- const direct = (0, import_node_path31.join)(rootDir, nodeId);
34074
- if ((0, import_node_fs27.existsSync)(direct)) return direct;
34964
+ if (layer === "ui" || layer === "api") return (0, import_node_path33.join)(rootDir, "src", nodeId);
34965
+ if (layer === "db") return (0, import_node_path33.join)(rootDir, "prisma", "schema.prisma");
34966
+ const withSrc = (0, import_node_path33.join)(rootDir, "src", nodeId);
34967
+ if ((0, import_node_fs28.existsSync)(withSrc)) return withSrc;
34968
+ const direct = (0, import_node_path33.join)(rootDir, nodeId);
34969
+ if ((0, import_node_fs28.existsSync)(direct)) return direct;
34075
34970
  return null;
34076
34971
  }
34077
34972
  function handleInspectNode(args) {
@@ -34101,7 +34996,7 @@ function handleInspectNode(args) {
34101
34996
  } else {
34102
34997
  matched = graph.nodes;
34103
34998
  }
34104
- const allDeepFields = ["elements", "stateVars", "conditions", "variables", "responses", "params", "effects"];
34999
+ const allDeepFields = ["elements", "stateVars", "conditions", "variables", "responses", "params", "effects", "ui_labels", "notes"];
34105
35000
  const requestedFields = fields ?? allDeepFields;
34106
35001
  let filterRegex = null;
34107
35002
  if (filter) {
@@ -34156,6 +35051,101 @@ function handleInspectNode(args) {
34156
35051
  nodes: results
34157
35052
  });
34158
35053
  }
35054
+ function handleListNotes(args) {
35055
+ const __resolved = resolveOrErr(args);
35056
+ if ("content" in __resolved) return __resolved;
35057
+ const { rootDir } = __resolved;
35058
+ const layerArg = args.layer;
35059
+ const kindArg = args.kind?.toUpperCase();
35060
+ const categoryArg = args.category ?? "actionable,warning";
35061
+ const moduleArg = args.module;
35062
+ const patternArg = args.pattern;
35063
+ const authorArg = args.author?.toLowerCase();
35064
+ const limit = args.limit ?? 100;
35065
+ const offset = args.offset ?? 0;
35066
+ let patternRegex = null;
35067
+ if (patternArg) {
35068
+ try {
35069
+ patternRegex = new RegExp(patternArg, "i");
35070
+ } catch {
35071
+ return err(`Invalid regex pattern: "${patternArg}"`);
35072
+ }
35073
+ }
35074
+ const wantedCategories = (() => {
35075
+ const trimmed = categoryArg.trim().toLowerCase();
35076
+ if (trimmed === "all") return "all";
35077
+ const out = /* @__PURE__ */ new Set();
35078
+ for (const part of trimmed.split(",").map((s) => s.trim()).filter(Boolean)) {
35079
+ if (part === "actionable" || part === "warning" || part === "doc" || part === "custom") {
35080
+ out.add(part);
35081
+ }
35082
+ }
35083
+ if (out.size === 0) {
35084
+ out.add("actionable");
35085
+ out.add("warning");
35086
+ }
35087
+ return out;
35088
+ })();
35089
+ const layers = layerArg ? [layerArg] : getAvailableLayers(rootDir);
35090
+ const items = [];
35091
+ for (const layer of layers) {
35092
+ const graph = readGraph(rootDir, layer);
35093
+ if (!graph) continue;
35094
+ for (const node of graph.nodes) {
35095
+ const nodeNotes = node.notes;
35096
+ if (!nodeNotes || nodeNotes.length === 0) continue;
35097
+ const tags = node.tags;
35098
+ const nodeModule = tags?.module;
35099
+ if (moduleArg && nodeModule !== moduleArg) continue;
35100
+ for (const n of nodeNotes) {
35101
+ if (!n.kind || !n.text || typeof n.line !== "number") continue;
35102
+ const category = categorizeNoteKind(n.kind);
35103
+ if (wantedCategories !== "all" && !wantedCategories.has(category)) continue;
35104
+ if (kindArg && n.kind.toUpperCase() !== kindArg) continue;
35105
+ if (authorArg && (!n.author || n.author.toLowerCase() !== authorArg)) continue;
35106
+ if (patternRegex && !patternRegex.test(n.text)) continue;
35107
+ const item = {
35108
+ file: node.id,
35109
+ line: n.line,
35110
+ kind: n.kind,
35111
+ category,
35112
+ text: n.text
35113
+ };
35114
+ if (n.author) item.author = n.author;
35115
+ if (nodeModule) item.module = nodeModule;
35116
+ items.push(item);
35117
+ }
35118
+ }
35119
+ }
35120
+ const catOrder = { actionable: 0, warning: 1, doc: 2, custom: 3 };
35121
+ items.sort((a, b) => {
35122
+ const c = catOrder[a.category] - catOrder[b.category];
35123
+ if (c !== 0) return c;
35124
+ const k = a.kind.localeCompare(b.kind);
35125
+ if (k !== 0) return k;
35126
+ const f = a.file.localeCompare(b.file);
35127
+ if (f !== 0) return f;
35128
+ return a.line - b.line;
35129
+ });
35130
+ const total = items.length;
35131
+ const paged = items.slice(offset, offset + limit);
35132
+ const hasMore = offset + paged.length < total;
35133
+ return okJson({
35134
+ total,
35135
+ returned: paged.length,
35136
+ has_more: hasMore,
35137
+ ...hasMore ? { next_offset: offset + paged.length } : {},
35138
+ filter: {
35139
+ layer: layerArg ?? "all",
35140
+ kind: kindArg ?? null,
35141
+ category: categoryArg,
35142
+ module: moduleArg ?? null,
35143
+ pattern: patternArg ?? null,
35144
+ author: authorArg ?? null
35145
+ },
35146
+ items: paged
35147
+ });
35148
+ }
34159
35149
  function handleGrepNodes(args) {
34160
35150
  const __resolved = resolveOrErr(args);
34161
35151
  if ("content" in __resolved) return __resolved;
@@ -34218,11 +35208,11 @@ function handleGrepNodes(args) {
34218
35208
  let filesSearched = 0;
34219
35209
  let truncated = false;
34220
35210
  for (const [filePath, nodeId] of filePaths) {
34221
- if (!(0, import_node_fs27.existsSync)(filePath)) continue;
35211
+ if (!(0, import_node_fs28.existsSync)(filePath)) continue;
34222
35212
  filesSearched++;
34223
35213
  let content;
34224
35214
  try {
34225
- content = (0, import_node_fs27.readFileSync)(filePath, "utf-8");
35215
+ content = (0, import_node_fs28.readFileSync)(filePath, "utf-8");
34226
35216
  } catch {
34227
35217
  continue;
34228
35218
  }
@@ -34344,11 +35334,11 @@ function handleStartChartServer(args) {
34344
35334
  });
34345
35335
  }
34346
35336
  const entryPath = process.argv[1];
34347
- const logDir = (0, import_node_path31.join)((0, import_node_os5.homedir)(), LAUNCHSECURE_DIR);
34348
- (0, import_node_fs27.mkdirSync)(logDir, { recursive: true });
34349
- const logPath = (0, import_node_path31.join)(logDir, "launch-chart.log");
34350
- const out = (0, import_node_fs27.openSync)(logPath, "a");
34351
- const err2 = (0, import_node_fs27.openSync)(logPath, "a");
35337
+ const logDir = (0, import_node_path33.join)((0, import_node_os6.homedir)(), LAUNCHSECURE_DIR);
35338
+ (0, import_node_fs28.mkdirSync)(logDir, { recursive: true });
35339
+ const logPath = (0, import_node_path33.join)(logDir, "launch-chart.log");
35340
+ const out = (0, import_node_fs28.openSync)(logPath, "a");
35341
+ const err2 = (0, import_node_fs28.openSync)(logPath, "a");
34352
35342
  const portArgs = args.port ? ["--port", String(args.port)] : [];
34353
35343
  const child = (0, import_node_child_process3.spawn)(process.execPath, [entryPath, "serve", ...portArgs], {
34354
35344
  detached: true,
@@ -34477,20 +35467,20 @@ function handleDetectProjectStack() {
34477
35467
  if (ref.type === "references_api") stats.references_api++;
34478
35468
  }
34479
35469
  }
34480
- const srcDir = (0, import_node_path31.join)(rootDir, "src");
34481
- if ((0, import_node_fs27.existsSync)(srcDir)) {
35470
+ const srcDir = (0, import_node_path33.join)(rootDir, "src");
35471
+ if ((0, import_node_fs28.existsSync)(srcDir)) {
34482
35472
  const scanDir = (dir) => {
34483
- if (!(0, import_node_fs27.existsSync)(dir)) return;
34484
- for (const entry of (0, import_node_fs27.readdirSync)(dir, { withFileTypes: true })) {
35473
+ if (!(0, import_node_fs28.existsSync)(dir)) return;
35474
+ for (const entry of (0, import_node_fs28.readdirSync)(dir, { withFileTypes: true })) {
34485
35475
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
34486
- const full = (0, import_node_path31.join)(dir, entry.name);
35476
+ const full = (0, import_node_path33.join)(dir, entry.name);
34487
35477
  if (entry.isDirectory()) {
34488
35478
  scanDir(full);
34489
35479
  continue;
34490
35480
  }
34491
- if (![".ts", ".tsx"].includes((0, import_node_path31.extname)(entry.name))) continue;
35481
+ if (![".ts", ".tsx"].includes((0, import_node_path33.extname)(entry.name))) continue;
34492
35482
  try {
34493
- const content = (0, import_node_fs27.readFileSync)(full, "utf-8");
35483
+ const content = (0, import_node_fs28.readFileSync)(full, "utf-8");
34494
35484
  const matches = content.match(/@api\s+(GET|POST|PUT|DELETE|PATCH)\s+\/\S+/g);
34495
35485
  if (matches) stats.annotations += matches.length;
34496
35486
  } catch {
@@ -34509,7 +35499,7 @@ function handleDetectProjectStack() {
34509
35499
  name: p.name,
34510
35500
  root: p.root,
34511
35501
  absolute_root: p.absoluteRoot,
34512
- has_graph: (0, import_node_fs27.existsSync)((0, import_node_path31.join)(p.absoluteRoot, LAUNCHSECURE_DIR, "graphs"))
35502
+ has_graph: (0, import_node_fs28.existsSync)((0, import_node_path33.join)(p.absoluteRoot, LAUNCHSECURE_DIR, "graphs"))
34513
35503
  }));
34514
35504
  return okJson({
34515
35505
  languages,
@@ -34623,6 +35613,10 @@ async function handleMessage(msg) {
34623
35613
  respond(id ?? null, withFreshnessMeta(handleBlastPoints(args), args));
34624
35614
  return;
34625
35615
  }
35616
+ if (toolName === "list_notes") {
35617
+ respond(id ?? null, withFreshnessMeta(handleListNotes(args), args));
35618
+ return;
35619
+ }
34626
35620
  respondError(id ?? null, -32601, `Unknown tool: ${toolName}`);
34627
35621
  return;
34628
35622
  }
@@ -34797,7 +35791,7 @@ function parseArgs() {
34797
35791
  return { port, token, serverUrl: LAUNCHSECURE_URL, subcommand };
34798
35792
  }
34799
35793
  function tryListen(server, port, maxRetries = 10) {
34800
- return new Promise((resolve5, reject) => {
35794
+ return new Promise((resolve6, reject) => {
34801
35795
  let attempts = 0;
34802
35796
  function attempt(p) {
34803
35797
  server.once("error", (err2) => {
@@ -34808,7 +35802,7 @@ function tryListen(server, port, maxRetries = 10) {
34808
35802
  reject(err2);
34809
35803
  }
34810
35804
  });
34811
- server.listen(p, "127.0.0.1", () => resolve5(p));
35805
+ server.listen(p, "127.0.0.1", () => resolve6(p));
34812
35806
  }
34813
35807
  attempt(port);
34814
35808
  });
@@ -34829,7 +35823,7 @@ function saveCredentials(creds) {
34829
35823
  });
34830
35824
  }
34831
35825
  function verifyToken(serverUrl, token) {
34832
- return new Promise((resolve5) => {
35826
+ return new Promise((resolve6) => {
34833
35827
  const url = new URL("/api/mcp/verify", serverUrl);
34834
35828
  const body = JSON.stringify({ token });
34835
35829
  const mod = url.protocol === "https:" ? import_https.default : import_http.default;
@@ -34844,30 +35838,30 @@ function verifyToken(serverUrl, token) {
34844
35838
  res.on("data", (chunk) => data += chunk);
34845
35839
  res.on("end", () => {
34846
35840
  try {
34847
- resolve5(JSON.parse(data));
35841
+ resolve6(JSON.parse(data));
34848
35842
  } catch {
34849
- resolve5({ valid: false, error: "Invalid response from server" });
35843
+ resolve6({ valid: false, error: "Invalid response from server" });
34850
35844
  }
34851
35845
  });
34852
35846
  });
34853
35847
  req.on("error", (err2) => {
34854
- resolve5({ valid: false, error: `Cannot reach server: ${err2.message}` });
35848
+ resolve6({ valid: false, error: `Cannot reach server: ${err2.message}` });
34855
35849
  });
34856
35850
  req.setTimeout(1e4, () => {
34857
35851
  req.destroy();
34858
- resolve5({ valid: false, error: "Connection timed out" });
35852
+ resolve6({ valid: false, error: "Connection timed out" });
34859
35853
  });
34860
35854
  req.write(body);
34861
35855
  req.end();
34862
35856
  });
34863
35857
  }
34864
35858
  function httpRequest2(reqUrl, options, body, timeout = 3e4) {
34865
- return new Promise((resolve5, reject) => {
35859
+ return new Promise((resolve6, reject) => {
34866
35860
  const mod = reqUrl.protocol === "https:" ? import_https.default : import_http.default;
34867
35861
  const r = mod.request(reqUrl, options, (resp) => {
34868
35862
  let data = "";
34869
35863
  resp.on("data", (chunk) => data += chunk);
34870
- resp.on("end", () => resolve5({ status: resp.statusCode || 0, headers: resp.headers, body: data }));
35864
+ resp.on("end", () => resolve6({ status: resp.statusCode || 0, headers: resp.headers, body: data }));
34871
35865
  });
34872
35866
  r.on("error", reject);
34873
35867
  r.setTimeout(timeout, () => {