@rulemetric/cli 0.2.0 → 0.2.2

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 (774) hide show
  1. package/dist/base-command.js +13 -52
  2. package/dist/base-command.js.map +7 -1
  3. package/dist/chunk-2AM54TUK.js +59 -0
  4. package/dist/chunk-2AM54TUK.js.map +7 -0
  5. package/dist/chunk-3TIMQ3O6.js +96 -0
  6. package/dist/chunk-3TIMQ3O6.js.map +7 -0
  7. package/dist/chunk-4BHDHHKL.js +48 -0
  8. package/dist/chunk-4BHDHHKL.js.map +7 -0
  9. package/dist/chunk-4D537GXE.js +99 -0
  10. package/dist/chunk-4D537GXE.js.map +7 -0
  11. package/dist/chunk-4SCZK7AL.js +129 -0
  12. package/dist/chunk-4SCZK7AL.js.map +7 -0
  13. package/dist/chunk-4WFE4PFP.js +61 -0
  14. package/dist/chunk-4WFE4PFP.js.map +7 -0
  15. package/dist/chunk-52WIYRZH.js +73 -0
  16. package/dist/chunk-52WIYRZH.js.map +7 -0
  17. package/dist/chunk-7FAA3YNB.js +1549 -0
  18. package/dist/chunk-7FAA3YNB.js.map +7 -0
  19. package/dist/chunk-7NYKWN7U.js +12 -0
  20. package/dist/chunk-7NYKWN7U.js.map +7 -0
  21. package/dist/chunk-AULP2OWH.js +99 -0
  22. package/dist/chunk-AULP2OWH.js.map +7 -0
  23. package/dist/chunk-B5KNTGMJ.js +1788 -0
  24. package/dist/chunk-B5KNTGMJ.js.map +7 -0
  25. package/dist/chunk-BD7CY42U.js +23 -0
  26. package/dist/chunk-BD7CY42U.js.map +7 -0
  27. package/dist/chunk-BO76WKJR.js +42 -0
  28. package/dist/chunk-BO76WKJR.js.map +7 -0
  29. package/dist/chunk-BRD5RUGM.js +53 -0
  30. package/dist/chunk-BRD5RUGM.js.map +7 -0
  31. package/dist/chunk-BT6Z6545.js +43 -0
  32. package/dist/chunk-BT6Z6545.js.map +7 -0
  33. package/dist/chunk-BZDKEQKU.js +39 -0
  34. package/dist/chunk-BZDKEQKU.js.map +7 -0
  35. package/dist/chunk-CROYS75W.js +161 -0
  36. package/dist/chunk-CROYS75W.js.map +7 -0
  37. package/dist/chunk-DGHWRQXL.js +17 -0
  38. package/dist/chunk-DGHWRQXL.js.map +7 -0
  39. package/dist/chunk-DQ3KELXD.js +74 -0
  40. package/dist/chunk-DQ3KELXD.js.map +7 -0
  41. package/dist/chunk-DTFXCHHI.js +108 -0
  42. package/dist/chunk-DTFXCHHI.js.map +7 -0
  43. package/dist/chunk-DU73QUS3.js +75 -0
  44. package/dist/chunk-DU73QUS3.js.map +7 -0
  45. package/dist/chunk-EHZJ6OXD.js +307 -0
  46. package/dist/chunk-EHZJ6OXD.js.map +7 -0
  47. package/dist/chunk-EJOI2ZGU.js +109 -0
  48. package/dist/chunk-EJOI2ZGU.js.map +7 -0
  49. package/dist/chunk-EKJ2CABV.js +76 -0
  50. package/dist/chunk-EKJ2CABV.js.map +7 -0
  51. package/dist/chunk-EKP32DLN.js +16 -0
  52. package/dist/chunk-EKP32DLN.js.map +7 -0
  53. package/dist/chunk-EOOP6WTC.js +148 -0
  54. package/dist/chunk-EOOP6WTC.js.map +7 -0
  55. package/dist/chunk-ERPMDAO3.js +20 -0
  56. package/dist/chunk-ERPMDAO3.js.map +7 -0
  57. package/dist/chunk-FTJRMUID.js +96 -0
  58. package/dist/chunk-FTJRMUID.js.map +7 -0
  59. package/dist/chunk-FZKLLNDS.js +228 -0
  60. package/dist/chunk-FZKLLNDS.js.map +7 -0
  61. package/dist/chunk-GQCISMAH.js +157 -0
  62. package/dist/chunk-GQCISMAH.js.map +7 -0
  63. package/dist/chunk-IGXX624H.js +55 -0
  64. package/dist/chunk-IGXX624H.js.map +7 -0
  65. package/dist/chunk-IJGF2ETG.js +68 -0
  66. package/dist/chunk-IJGF2ETG.js.map +7 -0
  67. package/dist/chunk-IWYCRLEK.js +220 -0
  68. package/dist/chunk-IWYCRLEK.js.map +7 -0
  69. package/dist/chunk-J7N3DLH6.js +117 -0
  70. package/dist/chunk-J7N3DLH6.js.map +7 -0
  71. package/dist/chunk-JX5UI6RW.js +99 -0
  72. package/dist/chunk-JX5UI6RW.js.map +7 -0
  73. package/dist/chunk-K3BFZ7KG.js +154 -0
  74. package/dist/chunk-K3BFZ7KG.js.map +7 -0
  75. package/dist/chunk-KHJUQFIK.js +51 -0
  76. package/dist/chunk-KHJUQFIK.js.map +7 -0
  77. package/dist/chunk-KRBQLMOP.js +41 -0
  78. package/dist/chunk-KRBQLMOP.js.map +7 -0
  79. package/dist/chunk-KZRFUXGF.js +145 -0
  80. package/dist/chunk-KZRFUXGF.js.map +7 -0
  81. package/dist/chunk-L674RNKQ.js +492 -0
  82. package/dist/chunk-L674RNKQ.js.map +7 -0
  83. package/dist/chunk-N52AHNBH.js +47 -0
  84. package/dist/chunk-N52AHNBH.js.map +7 -0
  85. package/dist/chunk-NIDLJO6F.js +228 -0
  86. package/dist/chunk-NIDLJO6F.js.map +7 -0
  87. package/dist/chunk-NSBPE2FW.js +17 -0
  88. package/dist/chunk-NSBPE2FW.js.map +7 -0
  89. package/dist/chunk-OGVORIFM.js +70 -0
  90. package/dist/chunk-OGVORIFM.js.map +7 -0
  91. package/dist/chunk-OQSQC7VB.js +77 -0
  92. package/dist/chunk-OQSQC7VB.js.map +7 -0
  93. package/dist/chunk-PHLMIZKM.js +153 -0
  94. package/dist/chunk-PHLMIZKM.js.map +7 -0
  95. package/dist/chunk-PQU7GZ7A.js +92 -0
  96. package/dist/chunk-PQU7GZ7A.js.map +7 -0
  97. package/dist/chunk-PXVQLD7S.js +196 -0
  98. package/dist/chunk-PXVQLD7S.js.map +7 -0
  99. package/dist/chunk-QD6X4L4L.js +79 -0
  100. package/dist/chunk-QD6X4L4L.js.map +7 -0
  101. package/dist/chunk-QJQS6TUN.js +44 -0
  102. package/dist/chunk-QJQS6TUN.js.map +7 -0
  103. package/dist/chunk-QJXAULRC.js +191 -0
  104. package/dist/chunk-QJXAULRC.js.map +7 -0
  105. package/dist/chunk-QN34TGD3.js +83 -0
  106. package/dist/chunk-QN34TGD3.js.map +7 -0
  107. package/dist/chunk-R5MFHGHR.js +122 -0
  108. package/dist/chunk-R5MFHGHR.js.map +7 -0
  109. package/dist/chunk-RH7NHVSK.js +16 -0
  110. package/dist/chunk-RH7NHVSK.js.map +7 -0
  111. package/dist/chunk-RJ7BHDLM.js +121 -0
  112. package/dist/chunk-RJ7BHDLM.js.map +7 -0
  113. package/dist/chunk-RQ2TMLKG.js +142 -0
  114. package/dist/chunk-RQ2TMLKG.js.map +7 -0
  115. package/dist/chunk-S56LOTGQ.js +63 -0
  116. package/dist/chunk-S56LOTGQ.js.map +7 -0
  117. package/dist/chunk-UF73WX2J.js +49 -0
  118. package/dist/chunk-UF73WX2J.js.map +7 -0
  119. package/dist/chunk-W53GKIZQ.js +50 -0
  120. package/dist/chunk-W53GKIZQ.js.map +7 -0
  121. package/dist/chunk-WA4MWYRW.js +254 -0
  122. package/dist/chunk-WA4MWYRW.js.map +7 -0
  123. package/dist/chunk-WFULKPEQ.js +269 -0
  124. package/dist/chunk-WFULKPEQ.js.map +7 -0
  125. package/dist/chunk-XC6M4CSW.js +44 -0
  126. package/dist/chunk-XC6M4CSW.js.map +7 -0
  127. package/dist/chunk-XPUEGHXN.js +243 -0
  128. package/dist/chunk-XPUEGHXN.js.map +7 -0
  129. package/dist/chunk-XZXS2W24.js +148 -0
  130. package/dist/chunk-XZXS2W24.js.map +7 -0
  131. package/dist/chunk-YBNW7ARH.js +167 -0
  132. package/dist/chunk-YBNW7ARH.js.map +7 -0
  133. package/dist/chunk-YNIH3KMU.js +121 -0
  134. package/dist/chunk-YNIH3KMU.js.map +7 -0
  135. package/dist/commands/antigravity/backfill.js +135 -0
  136. package/dist/commands/antigravity/backfill.js.map +7 -0
  137. package/dist/commands/auth/create-key.js +48 -33
  138. package/dist/commands/auth/create-key.js.map +7 -1
  139. package/dist/commands/auth/login.js +58 -46
  140. package/dist/commands/auth/login.js.map +7 -1
  141. package/dist/commands/auth/logout.js +28 -13
  142. package/dist/commands/auth/logout.js.map +7 -1
  143. package/dist/commands/auth/revoke-key.js +32 -18
  144. package/dist/commands/auth/revoke-key.js.map +7 -1
  145. package/dist/commands/auth/status.js +40 -22
  146. package/dist/commands/auth/status.js.map +7 -1
  147. package/dist/commands/catalog/index.js +50 -34
  148. package/dist/commands/catalog/index.js.map +7 -1
  149. package/dist/commands/catalog/recommend.js +41 -26
  150. package/dist/commands/catalog/recommend.js.map +7 -1
  151. package/dist/commands/convert.js +72 -54
  152. package/dist/commands/convert.js.map +7 -1
  153. package/dist/commands/converters.js +52 -38
  154. package/dist/commands/converters.js.map +7 -1
  155. package/dist/commands/crons/list.js +50 -24
  156. package/dist/commands/crons/list.js.map +7 -1
  157. package/dist/commands/crons/run.js +72 -47
  158. package/dist/commands/crons/run.js.map +7 -1
  159. package/dist/commands/dashboard.js +45 -24
  160. package/dist/commands/dashboard.js.map +7 -1
  161. package/dist/commands/eval-targets/create.js +51 -39
  162. package/dist/commands/eval-targets/create.js.map +7 -1
  163. package/dist/commands/eval-targets/list.js +52 -35
  164. package/dist/commands/eval-targets/list.js.map +7 -1
  165. package/dist/commands/evals/agent.js +292 -0
  166. package/dist/commands/evals/agent.js.map +7 -0
  167. package/dist/commands/evals/benchmark.js +70 -51
  168. package/dist/commands/evals/benchmark.js.map +7 -1
  169. package/dist/commands/evals/compare.js +90 -78
  170. package/dist/commands/evals/compare.js.map +7 -1
  171. package/dist/commands/evals/create.js +64 -50
  172. package/dist/commands/evals/create.js.map +7 -1
  173. package/dist/commands/evals/optimize-description.js +225 -222
  174. package/dist/commands/evals/optimize-description.js.map +7 -1
  175. package/dist/commands/evals/optimize.js +206 -196
  176. package/dist/commands/evals/optimize.js.map +7 -1
  177. package/dist/commands/evals/run.js +178 -164
  178. package/dist/commands/evals/run.js.map +7 -1
  179. package/dist/commands/gateway/ensure.js +33 -19
  180. package/dist/commands/gateway/ensure.js.map +7 -1
  181. package/dist/commands/hooks/install.js +335 -275
  182. package/dist/commands/hooks/install.js.map +7 -1
  183. package/dist/commands/hooks/run.js +72 -53
  184. package/dist/commands/hooks/run.js.map +7 -1
  185. package/dist/commands/hooks/uninstall.js +117 -94
  186. package/dist/commands/hooks/uninstall.js.map +7 -1
  187. package/dist/commands/import.js +63 -53
  188. package/dist/commands/import.js.map +7 -1
  189. package/dist/commands/instructions/create.js +71 -58
  190. package/dist/commands/instructions/create.js.map +7 -1
  191. package/dist/commands/instructions/delete.js +53 -36
  192. package/dist/commands/instructions/delete.js.map +7 -1
  193. package/dist/commands/instructions/fork.js +33 -19
  194. package/dist/commands/instructions/fork.js.map +7 -1
  195. package/dist/commands/instructions/get.js +66 -49
  196. package/dist/commands/instructions/get.js.map +7 -1
  197. package/dist/commands/instructions/list.js +63 -46
  198. package/dist/commands/instructions/list.js.map +7 -1
  199. package/dist/commands/instructions/promote.js +41 -27
  200. package/dist/commands/instructions/promote.js.map +7 -1
  201. package/dist/commands/instructions/pull.js +37 -21
  202. package/dist/commands/instructions/pull.js.map +7 -1
  203. package/dist/commands/instructions/upstream.js +36 -21
  204. package/dist/commands/instructions/upstream.js.map +7 -1
  205. package/dist/commands/instructions/versions.js +51 -33
  206. package/dist/commands/instructions/versions.js.map +7 -1
  207. package/dist/commands/launcher.js +39 -0
  208. package/dist/commands/launcher.js.map +7 -0
  209. package/dist/commands/org/current.js +74 -68
  210. package/dist/commands/org/current.js.map +7 -1
  211. package/dist/commands/org/list.js +50 -36
  212. package/dist/commands/org/list.js.map +7 -1
  213. package/dist/commands/org/switch.js +69 -51
  214. package/dist/commands/org/switch.js.map +7 -1
  215. package/dist/commands/packs/add-instruction.js +36 -22
  216. package/dist/commands/packs/add-instruction.js.map +7 -1
  217. package/dist/commands/packs/apply.js +38 -24
  218. package/dist/commands/packs/apply.js.map +7 -1
  219. package/dist/commands/packs/create.js +47 -33
  220. package/dist/commands/packs/create.js.map +7 -1
  221. package/dist/commands/packs/fork.js +33 -19
  222. package/dist/commands/packs/fork.js.map +7 -1
  223. package/dist/commands/packs/get.js +54 -35
  224. package/dist/commands/packs/get.js.map +7 -1
  225. package/dist/commands/packs/list.js +64 -47
  226. package/dist/commands/packs/list.js.map +7 -1
  227. package/dist/commands/packs/remove-instruction.js +34 -20
  228. package/dist/commands/packs/remove-instruction.js.map +7 -1
  229. package/dist/commands/proxy/env.js +126 -116
  230. package/dist/commands/proxy/env.js.map +7 -1
  231. package/dist/commands/proxy/logs.js +83 -74
  232. package/dist/commands/proxy/logs.js.map +7 -1
  233. package/dist/commands/proxy/restart.js +34 -36
  234. package/dist/commands/proxy/restart.js.map +7 -1
  235. package/dist/commands/proxy/setup.js +432 -375
  236. package/dist/commands/proxy/setup.js.map +7 -1
  237. package/dist/commands/proxy/start.js +289 -289
  238. package/dist/commands/proxy/start.js.map +7 -1
  239. package/dist/commands/proxy/status.js +74 -64
  240. package/dist/commands/proxy/status.js.map +7 -1
  241. package/dist/commands/proxy/stop.js +81 -75
  242. package/dist/commands/proxy/stop.js.map +7 -1
  243. package/dist/commands/research/backfill.js +58 -0
  244. package/dist/commands/research/backfill.js.map +7 -0
  245. package/dist/commands/research/tail-transcript.js +69 -0
  246. package/dist/commands/research/tail-transcript.js.map +7 -0
  247. package/dist/commands/service/install.js +639 -405
  248. package/dist/commands/service/install.js.map +7 -1
  249. package/dist/commands/service/status.js +178 -111
  250. package/dist/commands/service/status.js.map +7 -1
  251. package/dist/commands/service/uninstall.js +85 -110
  252. package/dist/commands/service/uninstall.js.map +7 -1
  253. package/dist/commands/sessions/analyze.js +46 -25
  254. package/dist/commands/sessions/analyze.js.map +7 -1
  255. package/dist/commands/sessions/end.js +81 -79
  256. package/dist/commands/sessions/end.js.map +7 -1
  257. package/dist/commands/sessions/import.js +44 -27
  258. package/dist/commands/sessions/import.js.map +7 -1
  259. package/dist/commands/sessions/list.js +46 -33
  260. package/dist/commands/sessions/list.js.map +7 -1
  261. package/dist/commands/sessions/start.js +88 -87
  262. package/dist/commands/sessions/start.js.map +7 -1
  263. package/dist/commands/signals/report.js +42 -34
  264. package/dist/commands/signals/report.js.map +7 -1
  265. package/dist/commands/skills/export-approved.js +44 -30
  266. package/dist/commands/skills/export-approved.js.map +7 -1
  267. package/dist/commands/skills/install.js +99 -84
  268. package/dist/commands/skills/install.js.map +7 -1
  269. package/dist/commands/skills/list.js +59 -42
  270. package/dist/commands/skills/list.js.map +7 -1
  271. package/dist/commands/skills/publish.js +95 -78
  272. package/dist/commands/skills/publish.js.map +7 -1
  273. package/dist/commands/skills/search.js +68 -53
  274. package/dist/commands/skills/search.js.map +7 -1
  275. package/dist/commands/skills/update.js +52 -39
  276. package/dist/commands/skills/update.js.map +7 -1
  277. package/dist/commands/suggestions/accept.js +82 -59
  278. package/dist/commands/suggestions/accept.js.map +7 -1
  279. package/dist/commands/suggestions/dismiss.js +44 -26
  280. package/dist/commands/suggestions/dismiss.js.map +7 -1
  281. package/dist/commands/suggestions/list.js +59 -39
  282. package/dist/commands/suggestions/list.js.map +7 -1
  283. package/dist/commands/suggestions/refresh.js +26 -11
  284. package/dist/commands/suggestions/refresh.js.map +7 -1
  285. package/dist/cursor-BGQJ4CWI.js +134 -0
  286. package/dist/cursor-BGQJ4CWI.js.map +7 -0
  287. package/dist/dashboard/Dashboard.js +229 -126
  288. package/dist/dashboard/Dashboard.js.map +7 -1
  289. package/dist/dashboard/data.js +13 -137
  290. package/dist/dashboard/data.js.map +7 -1
  291. package/dist/dashboard/launcher/ActiveJobsList.js +10 -0
  292. package/dist/dashboard/launcher/ActiveJobsList.js.map +7 -0
  293. package/dist/dashboard/launcher/LauncherOverlay.js +14 -0
  294. package/dist/dashboard/launcher/LauncherOverlay.js.map +7 -0
  295. package/dist/dashboard/launcher/NewLaunchForm.js +10 -0
  296. package/dist/dashboard/launcher/NewLaunchForm.js.map +7 -0
  297. package/dist/dashboard/launcher/api.js +14 -0
  298. package/dist/dashboard/launcher/api.js.map +7 -0
  299. package/dist/dashboard/launcher/tool-labels.js +10 -0
  300. package/dist/dashboard/launcher/tool-labels.js.map +7 -0
  301. package/dist/dashboard/launcher/types.js +1 -0
  302. package/dist/dashboard/launcher/types.js.map +7 -0
  303. package/dist/dashboard/launcher/useLaunchJobs.js +9 -0
  304. package/dist/dashboard/launcher/useLaunchJobs.js.map +7 -0
  305. package/dist/dashboard/panels/friction.js +10 -22
  306. package/dist/dashboard/panels/friction.js.map +7 -1
  307. package/dist/dashboard/panels/insights.js +10 -109
  308. package/dist/dashboard/panels/insights.js.map +7 -1
  309. package/dist/dashboard/panels/instructions.js +10 -17
  310. package/dist/dashboard/panels/instructions.js.map +7 -1
  311. package/dist/dashboard/panels/outcomes.js +9 -28
  312. package/dist/dashboard/panels/outcomes.js.map +7 -1
  313. package/dist/dashboard/panels/overview.js +10 -20
  314. package/dist/dashboard/panels/overview.js.map +7 -1
  315. package/dist/dashboard/panels/shared.js +18 -61
  316. package/dist/dashboard/panels/shared.js.map +7 -1
  317. package/dist/dashboard/types.js +23 -26
  318. package/dist/dashboard/types.js.map +7 -1
  319. package/dist/dist-CSUYFYKI.js +52 -0
  320. package/dist/dist-CSUYFYKI.js.map +7 -0
  321. package/dist/index.js +8 -2
  322. package/dist/index.js.map +7 -1
  323. package/dist/lib/active-org-refresh.js +15 -108
  324. package/dist/lib/active-org-refresh.js.map +7 -1
  325. package/dist/lib/active-org.js +15 -95
  326. package/dist/lib/active-org.js.map +7 -1
  327. package/dist/lib/agent-loop.js +44 -0
  328. package/dist/lib/agent-loop.js.map +7 -0
  329. package/dist/lib/antigravity-transcript.js +22 -0
  330. package/dist/lib/antigravity-transcript.js.map +7 -0
  331. package/dist/lib/api-client.js +21 -92
  332. package/dist/lib/api-client.js.map +7 -1
  333. package/dist/lib/auth.js +26 -137
  334. package/dist/lib/auth.js.map +7 -1
  335. package/dist/lib/detect-languages.js +8 -113
  336. package/dist/lib/detect-languages.js.map +7 -1
  337. package/dist/lib/detect-tmux.js +9 -0
  338. package/dist/lib/detect-tmux.js.map +7 -0
  339. package/dist/lib/eval-analyzer.js +9 -89
  340. package/dist/lib/eval-analyzer.js.map +7 -1
  341. package/dist/lib/eval-benchmark.js +12 -92
  342. package/dist/lib/eval-benchmark.js.map +7 -1
  343. package/dist/lib/eval-conversation-handler.js +13 -200
  344. package/dist/lib/eval-conversation-handler.js.map +7 -1
  345. package/dist/lib/eval-executor.js +8 -83
  346. package/dist/lib/eval-executor.js.map +7 -1
  347. package/dist/lib/eval-grader.js +9 -123
  348. package/dist/lib/eval-grader.js.map +7 -1
  349. package/dist/lib/eval-meta-judge.js +9 -116
  350. package/dist/lib/eval-meta-judge.js.map +7 -1
  351. package/dist/lib/eval-trigger-tester.js +11 -96
  352. package/dist/lib/eval-trigger-tester.js.map +7 -1
  353. package/dist/lib/eval-worktree.js +8 -87
  354. package/dist/lib/eval-worktree.js.map +7 -1
  355. package/dist/lib/gateway-entry.js +20 -18
  356. package/dist/lib/gateway-entry.js.map +7 -1
  357. package/dist/lib/gateway-lifecycle.js +22 -97
  358. package/dist/lib/gateway-lifecycle.js.map +7 -1
  359. package/dist/lib/gateway.js +12 -216
  360. package/dist/lib/gateway.js.map +7 -1
  361. package/dist/lib/handlers/cron-close-stale-sessions.js +18 -7
  362. package/dist/lib/handlers/cron-close-stale-sessions.js.map +7 -1
  363. package/dist/lib/handlers/cron-data-integrity-audit.js +21 -15
  364. package/dist/lib/handlers/cron-data-integrity-audit.js.map +7 -1
  365. package/dist/lib/handlers/cron-refresh-skills.js +7 -90
  366. package/dist/lib/handlers/cron-refresh-skills.js.map +7 -1
  367. package/dist/lib/handlers/cron-suggest-instructions.js +14 -158
  368. package/dist/lib/handlers/cron-suggest-instructions.js.map +7 -1
  369. package/dist/lib/handlers/process-announcement.js +11 -0
  370. package/dist/lib/handlers/process-announcement.js.map +7 -0
  371. package/dist/lib/handlers/process-changelog.js +11 -0
  372. package/dist/lib/handlers/process-changelog.js.map +7 -0
  373. package/dist/lib/handlers/process-conversation.js +14 -35
  374. package/dist/lib/handlers/process-conversation.js.map +7 -1
  375. package/dist/lib/handlers/process-eval.js +15 -207
  376. package/dist/lib/handlers/process-eval.js.map +7 -1
  377. package/dist/lib/handlers/process-insights.js +14 -300
  378. package/dist/lib/handlers/process-insights.js.map +7 -1
  379. package/dist/lib/handlers/process-launch.js +16 -41
  380. package/dist/lib/handlers/process-launch.js.map +7 -1
  381. package/dist/lib/handlers/process-run-cleanup.js +13 -0
  382. package/dist/lib/handlers/process-run-cleanup.js.map +7 -0
  383. package/dist/lib/handlers/process-send-message.js +10 -0
  384. package/dist/lib/handlers/process-send-message.js.map +7 -0
  385. package/dist/lib/handlers/process-session-goal.js +11 -0
  386. package/dist/lib/handlers/process-session-goal.js.map +7 -0
  387. package/dist/lib/hooks-config.js +52 -544
  388. package/dist/lib/hooks-config.js.map +7 -1
  389. package/dist/lib/insights-prompts.js +12 -145
  390. package/dist/lib/insights-prompts.js.map +7 -1
  391. package/dist/lib/job-helpers.js +1 -0
  392. package/dist/lib/job-helpers.js.map +7 -0
  393. package/dist/lib/llm-client.js +16 -274
  394. package/dist/lib/llm-client.js.map +7 -1
  395. package/dist/lib/manual-tasks.js +22 -0
  396. package/dist/lib/manual-tasks.js.map +7 -0
  397. package/dist/lib/output.js +12 -36
  398. package/dist/lib/output.js.map +7 -1
  399. package/dist/lib/permanent-job-error.js +10 -23
  400. package/dist/lib/permanent-job-error.js.map +7 -1
  401. package/dist/lib/provider-aggregator.js +57 -55
  402. package/dist/lib/provider-aggregator.js.map +7 -1
  403. package/dist/lib/research-client.js +12 -0
  404. package/dist/lib/research-client.js.map +7 -0
  405. package/dist/lib/skills-loader.js +8 -51
  406. package/dist/lib/skills-loader.js.map +7 -1
  407. package/dist/lib/statusline-shim.js +16 -0
  408. package/dist/lib/statusline-shim.js.map +7 -0
  409. package/dist/lib/terminal-target-heartbeat.js +15 -0
  410. package/dist/lib/terminal-target-heartbeat.js.map +7 -0
  411. package/dist/lib/tmux.js +16 -0
  412. package/dist/lib/tmux.js.map +7 -0
  413. package/dist/lib/transcript-rate-limit-watcher.js +22 -0
  414. package/dist/lib/transcript-rate-limit-watcher.js.map +7 -0
  415. package/dist/lib/types.js +8 -7
  416. package/dist/lib/types.js.map +7 -1
  417. package/dist/lib/version-check.js +10 -106
  418. package/dist/lib/version-check.js.map +7 -1
  419. package/dist/lib/which.js +8 -0
  420. package/dist/lib/which.js.map +7 -0
  421. package/dist/lib/worktree.js +17 -0
  422. package/dist/lib/worktree.js.map +7 -0
  423. package/dist/opencode-IQ7X5YMJ.js +190 -0
  424. package/dist/opencode-IQ7X5YMJ.js.map +7 -0
  425. package/oclif.manifest.json +299 -66
  426. package/package.json +28 -10
  427. package/dist/base-command.d.ts +0 -12
  428. package/dist/base-command.d.ts.map +0 -1
  429. package/dist/commands/auth/create-key.d.ts +0 -11
  430. package/dist/commands/auth/create-key.d.ts.map +0 -1
  431. package/dist/commands/auth/login.d.ts +0 -11
  432. package/dist/commands/auth/login.d.ts.map +0 -1
  433. package/dist/commands/auth/logout.d.ts +0 -7
  434. package/dist/commands/auth/logout.d.ts.map +0 -1
  435. package/dist/commands/auth/revoke-key.d.ts +0 -10
  436. package/dist/commands/auth/revoke-key.d.ts.map +0 -1
  437. package/dist/commands/auth/status.d.ts +0 -7
  438. package/dist/commands/auth/status.d.ts.map +0 -1
  439. package/dist/commands/catalog/index.d.ts +0 -11
  440. package/dist/commands/catalog/index.d.ts.map +0 -1
  441. package/dist/commands/catalog/recommend.d.ts +0 -9
  442. package/dist/commands/catalog/recommend.d.ts.map +0 -1
  443. package/dist/commands/convert.d.ts +0 -15
  444. package/dist/commands/convert.d.ts.map +0 -1
  445. package/dist/commands/converters.d.ts +0 -12
  446. package/dist/commands/converters.d.ts.map +0 -1
  447. package/dist/commands/crons/list.d.ts +0 -7
  448. package/dist/commands/crons/list.d.ts.map +0 -1
  449. package/dist/commands/crons/run.d.ts +0 -13
  450. package/dist/commands/crons/run.d.ts.map +0 -1
  451. package/dist/commands/dashboard.d.ts +0 -10
  452. package/dist/commands/dashboard.d.ts.map +0 -1
  453. package/dist/commands/eval-targets/create.d.ts +0 -14
  454. package/dist/commands/eval-targets/create.d.ts.map +0 -1
  455. package/dist/commands/eval-targets/list.d.ts +0 -10
  456. package/dist/commands/eval-targets/list.d.ts.map +0 -1
  457. package/dist/commands/evals/benchmark.d.ts +0 -13
  458. package/dist/commands/evals/benchmark.d.ts.map +0 -1
  459. package/dist/commands/evals/compare.d.ts +0 -15
  460. package/dist/commands/evals/compare.d.ts.map +0 -1
  461. package/dist/commands/evals/create.d.ts +0 -17
  462. package/dist/commands/evals/create.d.ts.map +0 -1
  463. package/dist/commands/evals/listen.d.ts +0 -37
  464. package/dist/commands/evals/listen.d.ts.map +0 -1
  465. package/dist/commands/evals/listen.js +0 -188
  466. package/dist/commands/evals/listen.js.map +0 -1
  467. package/dist/commands/evals/listen.test.d.ts +0 -2
  468. package/dist/commands/evals/listen.test.d.ts.map +0 -1
  469. package/dist/commands/evals/listen.test.js +0 -48
  470. package/dist/commands/evals/listen.test.js.map +0 -1
  471. package/dist/commands/evals/optimize-description.d.ts +0 -22
  472. package/dist/commands/evals/optimize-description.d.ts.map +0 -1
  473. package/dist/commands/evals/optimize.d.ts +0 -22
  474. package/dist/commands/evals/optimize.d.ts.map +0 -1
  475. package/dist/commands/evals/run.d.ts +0 -21
  476. package/dist/commands/evals/run.d.ts.map +0 -1
  477. package/dist/commands/gateway/ensure.d.ts +0 -7
  478. package/dist/commands/gateway/ensure.d.ts.map +0 -1
  479. package/dist/commands/hooks/install.d.ts +0 -16
  480. package/dist/commands/hooks/install.d.ts.map +0 -1
  481. package/dist/commands/hooks/run.d.ts +0 -11
  482. package/dist/commands/hooks/run.d.ts.map +0 -1
  483. package/dist/commands/hooks/uninstall.d.ts +0 -7
  484. package/dist/commands/hooks/uninstall.d.ts.map +0 -1
  485. package/dist/commands/import.d.ts +0 -17
  486. package/dist/commands/import.d.ts.map +0 -1
  487. package/dist/commands/instructions/create.d.ts +0 -17
  488. package/dist/commands/instructions/create.d.ts.map +0 -1
  489. package/dist/commands/instructions/delete.d.ts +0 -13
  490. package/dist/commands/instructions/delete.d.ts.map +0 -1
  491. package/dist/commands/instructions/fork.d.ts +0 -10
  492. package/dist/commands/instructions/fork.d.ts.map +0 -1
  493. package/dist/commands/instructions/get.d.ts +0 -15
  494. package/dist/commands/instructions/get.d.ts.map +0 -1
  495. package/dist/commands/instructions/list.d.ts +0 -12
  496. package/dist/commands/instructions/list.d.ts.map +0 -1
  497. package/dist/commands/instructions/promote.d.ts +0 -14
  498. package/dist/commands/instructions/promote.d.ts.map +0 -1
  499. package/dist/commands/instructions/pull.d.ts +0 -9
  500. package/dist/commands/instructions/pull.d.ts.map +0 -1
  501. package/dist/commands/instructions/upstream.d.ts +0 -9
  502. package/dist/commands/instructions/upstream.d.ts.map +0 -1
  503. package/dist/commands/instructions/versions.d.ts +0 -12
  504. package/dist/commands/instructions/versions.d.ts.map +0 -1
  505. package/dist/commands/org/current.d.ts +0 -7
  506. package/dist/commands/org/current.d.ts.map +0 -1
  507. package/dist/commands/org/list.d.ts +0 -7
  508. package/dist/commands/org/list.d.ts.map +0 -1
  509. package/dist/commands/org/switch.d.ts +0 -13
  510. package/dist/commands/org/switch.d.ts.map +0 -1
  511. package/dist/commands/packs/add-instruction.d.ts +0 -11
  512. package/dist/commands/packs/add-instruction.d.ts.map +0 -1
  513. package/dist/commands/packs/apply.d.ts +0 -13
  514. package/dist/commands/packs/apply.d.ts.map +0 -1
  515. package/dist/commands/packs/create.d.ts +0 -13
  516. package/dist/commands/packs/create.d.ts.map +0 -1
  517. package/dist/commands/packs/fork.d.ts +0 -10
  518. package/dist/commands/packs/fork.d.ts.map +0 -1
  519. package/dist/commands/packs/get.d.ts +0 -10
  520. package/dist/commands/packs/get.d.ts.map +0 -1
  521. package/dist/commands/packs/list.d.ts +0 -22
  522. package/dist/commands/packs/list.d.ts.map +0 -1
  523. package/dist/commands/packs/remove-instruction.d.ts +0 -11
  524. package/dist/commands/packs/remove-instruction.d.ts.map +0 -1
  525. package/dist/commands/proxy/env.d.ts +0 -14
  526. package/dist/commands/proxy/env.d.ts.map +0 -1
  527. package/dist/commands/proxy/logs.d.ts +0 -11
  528. package/dist/commands/proxy/logs.d.ts.map +0 -1
  529. package/dist/commands/proxy/restart.d.ts +0 -11
  530. package/dist/commands/proxy/restart.d.ts.map +0 -1
  531. package/dist/commands/proxy/setup.d.ts +0 -23
  532. package/dist/commands/proxy/setup.d.ts.map +0 -1
  533. package/dist/commands/proxy/start.d.ts +0 -17
  534. package/dist/commands/proxy/start.d.ts.map +0 -1
  535. package/dist/commands/proxy/status.d.ts +0 -7
  536. package/dist/commands/proxy/status.d.ts.map +0 -1
  537. package/dist/commands/proxy/stop.d.ts +0 -8
  538. package/dist/commands/proxy/stop.d.ts.map +0 -1
  539. package/dist/commands/service/install.d.ts +0 -33
  540. package/dist/commands/service/install.d.ts.map +0 -1
  541. package/dist/commands/service/install.test.d.ts +0 -2
  542. package/dist/commands/service/install.test.d.ts.map +0 -1
  543. package/dist/commands/service/install.test.js +0 -345
  544. package/dist/commands/service/install.test.js.map +0 -1
  545. package/dist/commands/service/status.d.ts +0 -6
  546. package/dist/commands/service/status.d.ts.map +0 -1
  547. package/dist/commands/service/uninstall.d.ts +0 -6
  548. package/dist/commands/service/uninstall.d.ts.map +0 -1
  549. package/dist/commands/sessions/analyze.d.ts +0 -10
  550. package/dist/commands/sessions/analyze.d.ts.map +0 -1
  551. package/dist/commands/sessions/end.d.ts +0 -9
  552. package/dist/commands/sessions/end.d.ts.map +0 -1
  553. package/dist/commands/sessions/import.d.ts +0 -13
  554. package/dist/commands/sessions/import.d.ts.map +0 -1
  555. package/dist/commands/sessions/list.d.ts +0 -11
  556. package/dist/commands/sessions/list.d.ts.map +0 -1
  557. package/dist/commands/sessions/start.d.ts +0 -11
  558. package/dist/commands/sessions/start.d.ts.map +0 -1
  559. package/dist/commands/signals/report.d.ts +0 -10
  560. package/dist/commands/signals/report.d.ts.map +0 -1
  561. package/dist/commands/signals/report.test.d.ts +0 -2
  562. package/dist/commands/signals/report.test.d.ts.map +0 -1
  563. package/dist/commands/signals/report.test.js +0 -65
  564. package/dist/commands/signals/report.test.js.map +0 -1
  565. package/dist/commands/skills/export-approved.d.ts +0 -10
  566. package/dist/commands/skills/export-approved.d.ts.map +0 -1
  567. package/dist/commands/skills/install.d.ts +0 -15
  568. package/dist/commands/skills/install.d.ts.map +0 -1
  569. package/dist/commands/skills/list.d.ts +0 -11
  570. package/dist/commands/skills/list.d.ts.map +0 -1
  571. package/dist/commands/skills/publish.d.ts +0 -17
  572. package/dist/commands/skills/publish.d.ts.map +0 -1
  573. package/dist/commands/skills/search.d.ts +0 -17
  574. package/dist/commands/skills/search.d.ts.map +0 -1
  575. package/dist/commands/skills/update.d.ts +0 -10
  576. package/dist/commands/skills/update.d.ts.map +0 -1
  577. package/dist/commands/suggestions/accept.d.ts +0 -16
  578. package/dist/commands/suggestions/accept.d.ts.map +0 -1
  579. package/dist/commands/suggestions/accept.test.d.ts +0 -2
  580. package/dist/commands/suggestions/accept.test.d.ts.map +0 -1
  581. package/dist/commands/suggestions/accept.test.js +0 -52
  582. package/dist/commands/suggestions/accept.test.js.map +0 -1
  583. package/dist/commands/suggestions/dismiss.d.ts +0 -10
  584. package/dist/commands/suggestions/dismiss.d.ts.map +0 -1
  585. package/dist/commands/suggestions/list.d.ts +0 -10
  586. package/dist/commands/suggestions/list.d.ts.map +0 -1
  587. package/dist/commands/suggestions/refresh.d.ts +0 -7
  588. package/dist/commands/suggestions/refresh.d.ts.map +0 -1
  589. package/dist/dashboard/Dashboard.d.ts +0 -3
  590. package/dist/dashboard/Dashboard.d.ts.map +0 -1
  591. package/dist/dashboard/data.d.ts +0 -11
  592. package/dist/dashboard/data.d.ts.map +0 -1
  593. package/dist/dashboard/panels/friction.d.ts +0 -7
  594. package/dist/dashboard/panels/friction.d.ts.map +0 -1
  595. package/dist/dashboard/panels/insights.d.ts +0 -8
  596. package/dist/dashboard/panels/insights.d.ts.map +0 -1
  597. package/dist/dashboard/panels/instructions.d.ts +0 -9
  598. package/dist/dashboard/panels/instructions.d.ts.map +0 -1
  599. package/dist/dashboard/panels/outcomes.d.ts +0 -7
  600. package/dist/dashboard/panels/outcomes.d.ts.map +0 -1
  601. package/dist/dashboard/panels/overview.d.ts +0 -8
  602. package/dist/dashboard/panels/overview.d.ts.map +0 -1
  603. package/dist/dashboard/panels/shared.d.ts +0 -17
  604. package/dist/dashboard/panels/shared.d.ts.map +0 -1
  605. package/dist/dashboard/types.d.ts +0 -80
  606. package/dist/dashboard/types.d.ts.map +0 -1
  607. package/dist/index.d.ts +0 -2
  608. package/dist/index.d.ts.map +0 -1
  609. package/dist/lib/active-org-refresh.d.ts +0 -22
  610. package/dist/lib/active-org-refresh.d.ts.map +0 -1
  611. package/dist/lib/active-org-refresh.test.d.ts +0 -2
  612. package/dist/lib/active-org-refresh.test.d.ts.map +0 -1
  613. package/dist/lib/active-org-refresh.test.js +0 -190
  614. package/dist/lib/active-org-refresh.test.js.map +0 -1
  615. package/dist/lib/active-org.d.ts +0 -43
  616. package/dist/lib/active-org.d.ts.map +0 -1
  617. package/dist/lib/active-org.test.d.ts +0 -2
  618. package/dist/lib/active-org.test.d.ts.map +0 -1
  619. package/dist/lib/active-org.test.js +0 -147
  620. package/dist/lib/active-org.test.js.map +0 -1
  621. package/dist/lib/api-client.d.ts +0 -17
  622. package/dist/lib/api-client.d.ts.map +0 -1
  623. package/dist/lib/api-client.test.d.ts +0 -2
  624. package/dist/lib/api-client.test.d.ts.map +0 -1
  625. package/dist/lib/api-client.test.js +0 -161
  626. package/dist/lib/api-client.test.js.map +0 -1
  627. package/dist/lib/auth.d.ts +0 -27
  628. package/dist/lib/auth.d.ts.map +0 -1
  629. package/dist/lib/auth.test.d.ts +0 -2
  630. package/dist/lib/auth.test.d.ts.map +0 -1
  631. package/dist/lib/auth.test.js +0 -110
  632. package/dist/lib/auth.test.js.map +0 -1
  633. package/dist/lib/cron-registry.d.ts +0 -47
  634. package/dist/lib/cron-registry.d.ts.map +0 -1
  635. package/dist/lib/cron-registry.js +0 -102
  636. package/dist/lib/cron-registry.js.map +0 -1
  637. package/dist/lib/cron-registry.test.d.ts +0 -2
  638. package/dist/lib/cron-registry.test.d.ts.map +0 -1
  639. package/dist/lib/cron-registry.test.js +0 -136
  640. package/dist/lib/cron-registry.test.js.map +0 -1
  641. package/dist/lib/cron-runner.d.ts +0 -16
  642. package/dist/lib/cron-runner.d.ts.map +0 -1
  643. package/dist/lib/cron-runner.js +0 -68
  644. package/dist/lib/cron-runner.js.map +0 -1
  645. package/dist/lib/detect-languages.d.ts +0 -7
  646. package/dist/lib/detect-languages.d.ts.map +0 -1
  647. package/dist/lib/detect-languages.test.d.ts +0 -2
  648. package/dist/lib/detect-languages.test.d.ts.map +0 -1
  649. package/dist/lib/detect-languages.test.js +0 -29
  650. package/dist/lib/detect-languages.test.js.map +0 -1
  651. package/dist/lib/eval-analyzer.d.ts +0 -23
  652. package/dist/lib/eval-analyzer.d.ts.map +0 -1
  653. package/dist/lib/eval-benchmark.d.ts +0 -17
  654. package/dist/lib/eval-benchmark.d.ts.map +0 -1
  655. package/dist/lib/eval-conversation-handler.d.ts +0 -9
  656. package/dist/lib/eval-conversation-handler.d.ts.map +0 -1
  657. package/dist/lib/eval-executor.d.ts +0 -21
  658. package/dist/lib/eval-executor.d.ts.map +0 -1
  659. package/dist/lib/eval-executor.test.d.ts +0 -2
  660. package/dist/lib/eval-executor.test.d.ts.map +0 -1
  661. package/dist/lib/eval-executor.test.js +0 -8
  662. package/dist/lib/eval-executor.test.js.map +0 -1
  663. package/dist/lib/eval-grader.d.ts +0 -38
  664. package/dist/lib/eval-grader.d.ts.map +0 -1
  665. package/dist/lib/eval-grader.test.d.ts +0 -2
  666. package/dist/lib/eval-grader.test.d.ts.map +0 -1
  667. package/dist/lib/eval-grader.test.js +0 -8
  668. package/dist/lib/eval-grader.test.js.map +0 -1
  669. package/dist/lib/eval-meta-judge.d.ts +0 -28
  670. package/dist/lib/eval-meta-judge.d.ts.map +0 -1
  671. package/dist/lib/eval-trigger-tester.d.ts +0 -19
  672. package/dist/lib/eval-trigger-tester.d.ts.map +0 -1
  673. package/dist/lib/eval-worktree.d.ts +0 -11
  674. package/dist/lib/eval-worktree.d.ts.map +0 -1
  675. package/dist/lib/eval-worktree.test.d.ts +0 -2
  676. package/dist/lib/eval-worktree.test.d.ts.map +0 -1
  677. package/dist/lib/eval-worktree.test.js +0 -68
  678. package/dist/lib/eval-worktree.test.js.map +0 -1
  679. package/dist/lib/gateway-entry.d.ts +0 -3
  680. package/dist/lib/gateway-entry.d.ts.map +0 -1
  681. package/dist/lib/gateway-lifecycle.d.ts +0 -9
  682. package/dist/lib/gateway-lifecycle.d.ts.map +0 -1
  683. package/dist/lib/gateway.d.ts +0 -11
  684. package/dist/lib/gateway.d.ts.map +0 -1
  685. package/dist/lib/graphile-worker-runner.d.ts +0 -124
  686. package/dist/lib/graphile-worker-runner.d.ts.map +0 -1
  687. package/dist/lib/graphile-worker-runner.js +0 -526
  688. package/dist/lib/graphile-worker-runner.js.map +0 -1
  689. package/dist/lib/graphile-worker-runner.test.d.ts +0 -2
  690. package/dist/lib/graphile-worker-runner.test.d.ts.map +0 -1
  691. package/dist/lib/graphile-worker-runner.test.js +0 -153
  692. package/dist/lib/graphile-worker-runner.test.js.map +0 -1
  693. package/dist/lib/handlers/cron-close-stale-sessions.d.ts +0 -3
  694. package/dist/lib/handlers/cron-close-stale-sessions.d.ts.map +0 -1
  695. package/dist/lib/handlers/cron-data-integrity-audit.d.ts +0 -3
  696. package/dist/lib/handlers/cron-data-integrity-audit.d.ts.map +0 -1
  697. package/dist/lib/handlers/cron-refresh-skills.d.ts +0 -3
  698. package/dist/lib/handlers/cron-refresh-skills.d.ts.map +0 -1
  699. package/dist/lib/handlers/cron-refresh-skills.test.d.ts +0 -2
  700. package/dist/lib/handlers/cron-refresh-skills.test.d.ts.map +0 -1
  701. package/dist/lib/handlers/cron-refresh-skills.test.js +0 -114
  702. package/dist/lib/handlers/cron-refresh-skills.test.js.map +0 -1
  703. package/dist/lib/handlers/cron-regenerate-insights.d.ts +0 -3
  704. package/dist/lib/handlers/cron-regenerate-insights.d.ts.map +0 -1
  705. package/dist/lib/handlers/cron-regenerate-insights.js +0 -6
  706. package/dist/lib/handlers/cron-regenerate-insights.js.map +0 -1
  707. package/dist/lib/handlers/cron-suggest-instructions.d.ts +0 -3
  708. package/dist/lib/handlers/cron-suggest-instructions.d.ts.map +0 -1
  709. package/dist/lib/handlers/cron-suggest-instructions.test.d.ts +0 -2
  710. package/dist/lib/handlers/cron-suggest-instructions.test.d.ts.map +0 -1
  711. package/dist/lib/handlers/cron-suggest-instructions.test.js +0 -80
  712. package/dist/lib/handlers/cron-suggest-instructions.test.js.map +0 -1
  713. package/dist/lib/handlers/process-conversation.d.ts +0 -35
  714. package/dist/lib/handlers/process-conversation.d.ts.map +0 -1
  715. package/dist/lib/handlers/process-eval.d.ts +0 -32
  716. package/dist/lib/handlers/process-eval.d.ts.map +0 -1
  717. package/dist/lib/handlers/process-insights.d.ts +0 -39
  718. package/dist/lib/handlers/process-insights.d.ts.map +0 -1
  719. package/dist/lib/handlers/process-launch.d.ts +0 -29
  720. package/dist/lib/handlers/process-launch.d.ts.map +0 -1
  721. package/dist/lib/hooks-config.d.ts +0 -119
  722. package/dist/lib/hooks-config.d.ts.map +0 -1
  723. package/dist/lib/hooks-config.test.d.ts +0 -2
  724. package/dist/lib/hooks-config.test.d.ts.map +0 -1
  725. package/dist/lib/hooks-config.test.js +0 -231
  726. package/dist/lib/hooks-config.test.js.map +0 -1
  727. package/dist/lib/insights-prompts.d.ts +0 -13
  728. package/dist/lib/insights-prompts.d.ts.map +0 -1
  729. package/dist/lib/llm-client.d.ts +0 -26
  730. package/dist/lib/llm-client.d.ts.map +0 -1
  731. package/dist/lib/llm-client.test.d.ts +0 -2
  732. package/dist/lib/llm-client.test.d.ts.map +0 -1
  733. package/dist/lib/llm-client.test.js +0 -62
  734. package/dist/lib/llm-client.test.js.map +0 -1
  735. package/dist/lib/mirror-writer-db.d.ts +0 -12
  736. package/dist/lib/mirror-writer-db.d.ts.map +0 -1
  737. package/dist/lib/mirror-writer-db.js +0 -51
  738. package/dist/lib/mirror-writer-db.js.map +0 -1
  739. package/dist/lib/mirror-writer.d.ts +0 -35
  740. package/dist/lib/mirror-writer.d.ts.map +0 -1
  741. package/dist/lib/mirror-writer.js +0 -27
  742. package/dist/lib/mirror-writer.js.map +0 -1
  743. package/dist/lib/mirror-writer.test.d.ts +0 -2
  744. package/dist/lib/mirror-writer.test.d.ts.map +0 -1
  745. package/dist/lib/mirror-writer.test.js +0 -47
  746. package/dist/lib/mirror-writer.test.js.map +0 -1
  747. package/dist/lib/output.d.ts +0 -4
  748. package/dist/lib/output.d.ts.map +0 -1
  749. package/dist/lib/output.test.d.ts +0 -2
  750. package/dist/lib/output.test.d.ts.map +0 -1
  751. package/dist/lib/output.test.js +0 -71
  752. package/dist/lib/output.test.js.map +0 -1
  753. package/dist/lib/permanent-job-error.d.ts +0 -17
  754. package/dist/lib/permanent-job-error.d.ts.map +0 -1
  755. package/dist/lib/permanent-job-error.test.d.ts +0 -2
  756. package/dist/lib/permanent-job-error.test.d.ts.map +0 -1
  757. package/dist/lib/permanent-job-error.test.js +0 -29
  758. package/dist/lib/permanent-job-error.test.js.map +0 -1
  759. package/dist/lib/provider-aggregator.d.ts +0 -24
  760. package/dist/lib/provider-aggregator.d.ts.map +0 -1
  761. package/dist/lib/provider-aggregator.test.d.ts +0 -2
  762. package/dist/lib/provider-aggregator.test.d.ts.map +0 -1
  763. package/dist/lib/provider-aggregator.test.js +0 -103
  764. package/dist/lib/provider-aggregator.test.js.map +0 -1
  765. package/dist/lib/skills-loader.d.ts +0 -6
  766. package/dist/lib/skills-loader.d.ts.map +0 -1
  767. package/dist/lib/types.d.ts +0 -48
  768. package/dist/lib/types.d.ts.map +0 -1
  769. package/dist/lib/version-check.d.ts +0 -11
  770. package/dist/lib/version-check.d.ts.map +0 -1
  771. package/dist/test-helpers.d.ts +0 -58
  772. package/dist/test-helpers.d.ts.map +0 -1
  773. package/dist/test-helpers.js +0 -58
  774. package/dist/test-helpers.js.map +0 -1
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/lib/hooks-config.ts"],
4
+ "sourcesContent": ["import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport type DetectedTool = 'claude_code' | 'cursor' | 'copilot_agent' | 'antigravity';\n\n/**\n * Detect which AI coding tools are installed in the project by checking\n * for their config directories.\n */\nexport function detectInstalledTools(projectPath: string): DetectedTool[] {\n const tools: DetectedTool[] = ['claude_code'];\n\n if (existsSync(join(projectPath, '.cursor'))) {\n tools.push('cursor');\n }\n\n if (existsSync(join(projectPath, '.github'))) {\n tools.push('copilot_agent');\n }\n\n // Antigravity's workspace config lives at `.agents/`. The user-level\n // hooks file at ~/.gemini/config/hooks.json is installed unconditionally\n // by writeAntigravityUserHooks() so we don't gate on that here.\n if (existsSync(join(projectPath, '.agents'))) {\n tools.push('antigravity');\n }\n\n return tools;\n}\n\n/**\n * Generate Cursor hooks config object.\n *\n * Cursor uses event names like beforeSubmitPrompt, afterFileEdit, etc.\n * Each event maps to an array of hook objects with a `command` field.\n */\nexport function generateCursorHooksConfig(): object {\n // Event coverage matches Cursor 1.7+ hook API (cursor.com/docs/hooks).\n // `sessionStart` is required so the registry file is written with\n // conversation_id before any tool runs; without it the proxy-based linker\n // path would have nothing to map and we'd drop captures. `sessionEnd`\n // emits the session-end signal once per chat conversation (vs `stop`\n // which fires per-turn \u2014 those go through post-tool-use).\n return {\n version: 1,\n hooks: {\n sessionStart: [\n { command: 'rulemetric hooks run session-start' },\n ],\n beforeSubmitPrompt: [\n { command: 'rulemetric hooks run user-prompt' },\n ],\n afterFileEdit: [\n { command: 'rulemetric hooks run post-tool-use' },\n ],\n beforeShellExecution: [\n { command: 'rulemetric hooks run post-tool-use' },\n ],\n afterShellExecution: [\n { command: 'rulemetric hooks run post-tool-use' },\n ],\n beforeMCPExecution: [\n { command: 'rulemetric hooks run post-tool-use' },\n ],\n afterMCPExecution: [\n { command: 'rulemetric hooks run post-tool-use' },\n ],\n // `afterAgentResponse` carries the full assistant response text +\n // token usage. Verified empirically via a probe hook on\n // 2026-05-12 \u2014 Cursor passes `text`, `input_tokens`,\n // `output_tokens`, `cache_read_tokens`, `cache_write_tokens`. This\n // is the cleanest path to per-turn assistant content for Cursor\n // (chat traffic itself bypasses the proxy via HTTP/2 \u2014 see\n // docs/audits/2026-05-11-cursor-capture-architecture.md).\n afterAgentResponse: [\n { command: 'rulemetric hooks run assistant-response' },\n ],\n // `stop` fires when the agent loop ends for a single turn (status:\n // completed|aborted|error). Per-turn, NOT per-session \u2014 route it to\n // post-tool-use, not session-end. The real session boundary is\n // `sessionEnd` below.\n stop: [\n { command: 'rulemetric hooks run post-tool-use' },\n ],\n sessionEnd: [\n { command: 'rulemetric hooks run session-end' },\n ],\n },\n };\n}\n\n/**\n * Generate Copilot Agent hooks config object.\n *\n * Copilot uses event names like sessionStart, userPromptSubmitted, etc.\n * Each event maps to an array of hook objects with `type` and `bash` fields.\n */\nexport function generateCopilotHooksConfig(): object {\n return {\n version: 1,\n hooks: {\n sessionStart: [\n { type: 'command', bash: 'rulemetric hooks run session-start' },\n ],\n userPromptSubmitted: [\n { type: 'command', bash: 'rulemetric hooks run user-prompt' },\n ],\n postToolUse: [\n { type: 'command', bash: 'rulemetric hooks run post-tool-use' },\n ],\n sessionEnd: [\n { type: 'command', bash: 'rulemetric hooks run session-end' },\n ],\n },\n };\n}\n\n/**\n * Merge rulemetric hooks into a Cursor `hooks.json` at the given directory.\n *\n * Used by both the project (`<repo>/.cursor/`) and user (`~/.cursor/`) writers.\n * Returns the config file path, or null if the cursor dir doesn't exist.\n */\nfunction writeCursorHooksToDir(cursorDir: string): string | null {\n if (!existsSync(cursorDir)) {\n return null;\n }\n\n const configPath = join(cursorDir, 'hooks.json');\n const generated = generateCursorHooksConfig() as {\n version: number;\n hooks: Record<string, Array<{ command: string }>>;\n };\n\n let existing: { version?: number; hooks?: Record<string, unknown[]> } = {};\n if (existsSync(configPath)) {\n try {\n existing = JSON.parse(readFileSync(configPath, 'utf-8'));\n } catch {\n existing = {};\n }\n }\n\n const merged: Record<string, unknown[]> = { ...(existing.hooks ?? {}) };\n\n for (const [event, hooks] of Object.entries(generated.hooks)) {\n const current = merged[event] ?? [];\n const hasRulemetric = current.some(\n (h: unknown) =>\n typeof h === 'object' &&\n h !== null &&\n 'command' in h &&\n typeof (h as { command: string }).command === 'string' &&\n (h as { command: string }).command.includes('rulemetric'),\n );\n if (!hasRulemetric) {\n merged[event] = [...current, ...hooks];\n }\n }\n\n const result = {\n version: existing.version ?? generated.version,\n hooks: merged,\n };\n\n writeFileSync(configPath, JSON.stringify(result, null, 2) + '\\n');\n return configPath;\n}\n\n/**\n * Write Cursor hooks config to `<projectPath>/.cursor/hooks.json`.\n * Merges with existing config \u2014 appends rulemetric hooks without duplicating.\n * Returns the config file path, or null if `.cursor/` doesn't exist.\n */\nexport function writeCursorHooks(projectPath: string): string | null {\n return writeCursorHooksToDir(join(projectPath, '.cursor'));\n}\n\n/**\n * Write Cursor hooks config to user-level `~/.cursor/hooks.json` so capture\n * works for every Cursor conversation without per-project setup.\n *\n * Returns the config file path, or null if `~/.cursor/` doesn't exist\n * (i.e., Cursor has never been launched on this machine).\n */\nexport function writeCursorUserHooks(): string | null {\n return writeCursorHooksToDir(join(homedir(), '.cursor'));\n}\n\n/**\n * Write Copilot Agent hooks config to `.github/hooks/rulemetric.json`.\n * Creates the hooks directory if needed.\n * Returns the config file path, or null if `.github/` doesn't exist.\n */\nexport function writeCopilotHooks(projectPath: string): string | null {\n const githubDir = join(projectPath, '.github');\n if (!existsSync(githubDir)) {\n return null;\n }\n\n const hooksDir = join(githubDir, 'hooks');\n mkdirSync(hooksDir, { recursive: true });\n\n const configPath = join(hooksDir, 'rulemetric.json');\n const config = generateCopilotHooksConfig();\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n return configPath;\n}\n\n/**\n * Strip rulemetric hooks from a Cursor `hooks.json` at the given path.\n * Preserves other hooks and removes empty event arrays.\n * Returns true if changes were made.\n */\nfunction removeCursorHooksFromFile(configPath: string): boolean {\n if (!existsSync(configPath)) {\n return false;\n }\n\n let config: { version?: number; hooks?: Record<string, unknown[]> };\n try {\n config = JSON.parse(readFileSync(configPath, 'utf-8'));\n } catch {\n return false;\n }\n\n if (!config.hooks) {\n return false;\n }\n\n let changed = false;\n for (const [event, hooks] of Object.entries(config.hooks)) {\n const filtered = hooks.filter((h: unknown) => {\n if (typeof h !== 'object' || h === null || !('command' in h)) return true;\n const cmd = (h as { command: string }).command;\n if (typeof cmd === 'string' && cmd.includes('rulemetric')) {\n changed = true;\n return false;\n }\n return true;\n });\n\n if (filtered.length === 0) {\n delete config.hooks[event];\n } else {\n config.hooks[event] = filtered;\n }\n }\n\n if (changed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n }\n\n return changed;\n}\n\n/**\n * Remove rulemetric hooks from `<projectPath>/.cursor/hooks.json`.\n */\nexport function removeCursorHooks(projectPath: string): boolean {\n return removeCursorHooksFromFile(join(projectPath, '.cursor', 'hooks.json'));\n}\n\n/**\n * Remove rulemetric hooks from user-level `~/.cursor/hooks.json`.\n */\nexport function removeCursorUserHooks(): boolean {\n return removeCursorHooksFromFile(join(homedir(), '.cursor', 'hooks.json'));\n}\n\n/**\n * Write Cursor proxy config to `.cursor/settings.json`.\n * Sets `http.proxy` and `http.proxyStrictSSL` while preserving existing settings.\n * Returns true if `.cursor/` exists and config was written, false otherwise.\n */\nexport function writeCursorProxyConfig(projectPath: string, gatewayPort: number, certPath: string): boolean {\n const cursorDir = join(projectPath, '.cursor');\n if (!existsSync(cursorDir)) return false;\n\n const settingsPath = join(cursorDir, 'settings.json');\n let settings: Record<string, unknown> = {};\n if (existsSync(settingsPath)) {\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { /* empty */ }\n }\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = existsSync(certPath);\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Write VS Code proxy config to `.vscode/settings.json` for Copilot capture.\n * Sets `http.proxy`, `http.proxyStrictSSL`, and Copilot-specific override\n * while preserving existing settings.\n * Returns true if config was written, false if `.vscode/` doesn't exist.\n */\nexport function writeVSCodeProxyConfig(projectPath: string, gatewayPort: number, certPath: string): boolean {\n const vscodeDir = join(projectPath, '.vscode');\n mkdirSync(vscodeDir, { recursive: true });\n\n const settingsPath = join(vscodeDir, 'settings.json');\n let settings: Record<string, unknown> = {};\n if (existsSync(settingsPath)) {\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { /* empty */ }\n }\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = existsSync(certPath);\n\n // Copilot-specific override for surgical proxy targeting\n const copilotAdvanced = (settings['github.copilot.advanced'] ?? {}) as Record<string, unknown>;\n copilotAdvanced['debug.overrideProxyUrl'] = `http://localhost:${gatewayPort}`;\n settings['github.copilot.advanced'] = copilotAdvanced;\n\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Remove VS Code proxy config from `.vscode/settings.json`.\n * Removes `http.proxy`, `http.proxyStrictSSL`, and Copilot proxy override.\n * Returns true if changes were made.\n */\nexport function removeVSCodeProxyConfig(projectPath: string): boolean {\n const settingsPath = join(projectPath, '.vscode', 'settings.json');\n if (!existsSync(settingsPath)) return false;\n\n let settings: Record<string, unknown>;\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { return false; }\n\n let changed = false;\n\n if (settings['http.proxy']) {\n delete settings['http.proxy'];\n delete settings['http.proxyStrictSSL'];\n changed = true;\n }\n\n const copilotAdvanced = settings['github.copilot.advanced'] as Record<string, unknown> | undefined;\n if (copilotAdvanced?.['debug.overrideProxyUrl']) {\n delete copilotAdvanced['debug.overrideProxyUrl'];\n if (Object.keys(copilotAdvanced).length === 0) {\n delete settings['github.copilot.advanced'];\n }\n changed = true;\n }\n\n if (changed) {\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n }\n\n return changed;\n}\n\n/**\n * Remove Copilot Agent hooks by deleting `.github/hooks/rulemetric.json`.\n * Returns true if the file was removed.\n */\nexport function removeCopilotHooks(projectPath: string): boolean {\n const configPath = join(projectPath, '.github', 'hooks', 'rulemetric.json');\n if (!existsSync(configPath)) {\n return false;\n }\n\n unlinkSync(configPath);\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// macOS LaunchAgent for GUI app env vars (HTTPS_PROXY, NODE_EXTRA_CA_CERTS)\n// ---------------------------------------------------------------------------\n\nconst LAUNCH_AGENT_LABEL = 'com.rulemetric.env';\n\nfunction getLaunchAgentPath(): string {\n return join(homedir(), 'Library', 'LaunchAgents', `${LAUNCH_AGENT_LABEL}.plist`);\n}\n\n/**\n * Set HTTPS_PROXY and NODE_EXTRA_CA_CERTS for all GUI apps on macOS.\n *\n * Two layers:\n * 1. `launchctl setenv` \u2014 immediate effect for newly launched apps\n * 2. LaunchAgent plist \u2014 persists across reboots\n *\n * This ensures VS Code / Copilot / Cursor route LLM traffic through the\n * gateway even when launched from Dock or Spotlight (not a terminal).\n *\n * References:\n * - anthropics/claude-code#30318 (same pattern for Claude Desktop)\n * - Snyk IDE docs recommend launchctl setenv for macOS\n * - Apple QA1067 (archived) \u2014 original env var mechanism removed in 10.10\n */\nexport function installMacOSProxyEnv(gatewayPort: number, certPath: string): boolean {\n if (process.platform !== 'darwin') return false;\n\n const proxyUrl = `http://localhost:${gatewayPort}`;\n\n // Layer 1: immediate effect via launchctl setenv\n try {\n execSync(`launchctl setenv HTTPS_PROXY ${proxyUrl}`, { stdio: 'pipe' });\n if (existsSync(certPath)) {\n execSync(`launchctl setenv NODE_EXTRA_CA_CERTS ${certPath}`, { stdio: 'pipe' });\n }\n } catch {\n return false;\n }\n\n // Layer 2: LaunchAgent plist for persistence across reboots\n const plistPath = getLaunchAgentPath();\n const agentsDir = join(homedir(), 'Library', 'LaunchAgents');\n mkdirSync(agentsDir, { recursive: true });\n\n const certLine = existsSync(certPath)\n ? `launchctl setenv NODE_EXTRA_CA_CERTS ${certPath};`\n : '';\n\n const plist = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"\n \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${LAUNCH_AGENT_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>/bin/sh</string>\n <string>-c</string>\n <string>launchctl setenv HTTPS_PROXY ${proxyUrl};${certLine}</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n</dict>\n</plist>\n`;\n\n writeFileSync(plistPath, plist);\n return true;\n}\n\n/**\n * Remove the RuleMetric LaunchAgent and unset env vars.\n */\nexport function uninstallMacOSProxyEnv(): boolean {\n if (process.platform !== 'darwin') return false;\n\n let changed = false;\n\n // Unset env vars for current session\n try {\n execSync('launchctl unsetenv HTTPS_PROXY', { stdio: 'pipe' });\n execSync('launchctl unsetenv NODE_EXTRA_CA_CERTS', { stdio: 'pipe' });\n } catch { /* may not be set */ }\n\n // Remove LaunchAgent plist\n const plistPath = getLaunchAgentPath();\n if (existsSync(plistPath)) {\n unlinkSync(plistPath);\n changed = true;\n }\n\n return changed;\n}\n\n// ---------------------------------------------------------------------------\n// VS Code user-level proxy settings\n// ---------------------------------------------------------------------------\n\nfunction getVSCodeUserSettingsPath(): string {\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Application Support', 'Code', 'User', 'settings.json');\n }\n if (process.platform === 'win32') {\n return join(process.env.APPDATA ?? '', 'Code', 'User', 'settings.json');\n }\n return join(homedir(), '.config', 'Code', 'User', 'settings.json');\n}\n\n/**\n * Set http.proxy in VS Code user settings (not workspace).\n *\n * Workspace-level http.proxy is silently ignored because VS Code restricts\n * it to APPLICATION scope (microsoft/vscode#236932). User-level settings\n * are the only reliable way to configure http.proxy.\n */\nexport function writeVSCodeUserProxyConfig(gatewayPort: number): boolean {\n const settingsPath = getVSCodeUserSettingsPath();\n if (!existsSync(join(settingsPath, '..'))) return false;\n\n let settings: Record<string, unknown> = {};\n if (existsSync(settingsPath)) {\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { /* empty */ }\n }\n\n // Only set if not already configured by the user\n if (settings['http.proxy'] && !(settings['http.proxy'] as string).includes('localhost')) {\n return false; // user has a custom proxy, don't overwrite\n }\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = false;\n\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Remove RuleMetric proxy config from VS Code user settings.\n */\nexport function removeVSCodeUserProxyConfig(): boolean {\n const settingsPath = getVSCodeUserSettingsPath();\n if (!existsSync(settingsPath)) return false;\n\n let settings: Record<string, unknown>;\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { return false; }\n\n const proxy = settings['http.proxy'] as string | undefined;\n if (!proxy?.includes('localhost')) return false;\n\n delete settings['http.proxy'];\n delete settings['http.proxyStrictSSL'];\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Cursor user-level proxy settings\n// ---------------------------------------------------------------------------\n//\n// Cursor is a VS Code fork and uses the same settings.json shape, but reads\n// from `Cursor/User/settings.json` instead of `Code/User/settings.json`. The\n// `.cursor/settings.json` (workspace) path can't reach Cursor's Electron main\n// process for the same reason VS Code's workspace path can't reach VS Code's\n// \u2014 the http.proxy setting is restricted to APPLICATION scope and only the\n// user-level file is honored.\n\nfunction getCursorUserSettingsPath(): string {\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Application Support', 'Cursor', 'User', 'settings.json');\n }\n if (process.platform === 'win32') {\n return join(process.env.APPDATA ?? '', 'Cursor', 'User', 'settings.json');\n }\n return join(homedir(), '.config', 'Cursor', 'User', 'settings.json');\n}\n\n/**\n * Set http.proxy in Cursor user settings (not workspace). Mirrors\n * `writeVSCodeUserProxyConfig` \u2014 workspace-level http.proxy is silently\n * ignored due to APPLICATION-scope restriction (Cursor inherits this from\n * VS Code, see microsoft/vscode#236932).\n *\n * Returns true if config was written, false if Cursor isn't installed\n * (User dir absent) or the user already has a non-localhost proxy set.\n */\nexport function writeCursorUserProxyConfig(gatewayPort: number): boolean {\n const settingsPath = getCursorUserSettingsPath();\n if (!existsSync(join(settingsPath, '..'))) return false;\n\n let settings: Record<string, unknown> = {};\n if (existsSync(settingsPath)) {\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { /* empty */ }\n }\n\n if (settings['http.proxy'] && !(settings['http.proxy'] as string).includes('localhost')) {\n return false;\n }\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = false;\n\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Remove RuleMetric proxy config from Cursor user settings.\n */\nexport function removeCursorUserProxyConfig(): boolean {\n const settingsPath = getCursorUserSettingsPath();\n if (!existsSync(settingsPath)) return false;\n\n let settings: Record<string, unknown>;\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { return false; }\n\n const proxy = settings['http.proxy'] as string | undefined;\n if (!proxy?.includes('localhost')) return false;\n\n delete settings['http.proxy'];\n delete settings['http.proxyStrictSSL'];\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n// \u2500\u2500\u2500 Antigravity (Google's Gemini-based agentic IDE) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Antigravity hooks live in `.agents/hooks.json` (workspace) and\n// `~/.gemini/config/hooks.json` (user-level). Events follow the\n// SessionStart / UserPromptSubmit / PreToolUse / PostToolUse / Stop /\n// SessionEnd vocabulary. Each hook command sets `RULEMETRIC_HOOK_TOOL=\n// antigravity` so `_normalize.sh` routes through the Antigravity branch.\n\ninterface AntigravityHookEntry {\n type: 'command';\n command: string;\n timeout?: number;\n}\n\ninterface AntigravityHookBlock {\n matcher?: string;\n hooks: AntigravityHookEntry[];\n}\n\ninterface AntigravityRuleMetricBlock {\n enabled: boolean;\n SessionStart: AntigravityHookBlock[];\n UserPromptSubmit: AntigravityHookBlock[];\n PreToolUse: AntigravityHookBlock[];\n PostToolUse: AntigravityHookBlock[];\n Stop: AntigravityHookBlock[];\n SessionEnd: AntigravityHookBlock[];\n}\n\nexport type AntigravityHooksConfig = { rulemetric: AntigravityRuleMetricBlock };\n\n/** Resolve the binary string to invoke for a hook command. */\nfunction getRulemetricCommand(): string {\n // Prefer the local Node binary + bin/run.js so the hook works even when\n // `rulemetric` isn't on PATH for the GUI Antigravity process.\n const nodeBin = process.execPath;\n // bin/run.js lives next to dist/ in the installed CLI; resolve from\n // import.meta isn't available in a portable way here, so we use the\n // process argv1 if it's pointing at the CLI entry, else fall back to\n // the bare command name. In practice this function is called inside\n // `rulemetric hooks install`, where process.argv[1] is bin/run.js.\n const cliEntry = process.argv[1];\n if (cliEntry && cliEntry.endsWith('run.js')) {\n return `${nodeBin} ${cliEntry}`;\n }\n return 'rulemetric';\n}\n\nexport function generateAntigravityHooksConfig(): AntigravityHooksConfig {\n const cmd = getRulemetricCommand();\n const mk = (name: string): AntigravityHookEntry => ({\n type: 'command',\n command: `RULEMETRIC_HOOK_TOOL=antigravity ${cmd} hooks run ${name}`,\n timeout: 30,\n });\n return {\n rulemetric: {\n enabled: true,\n SessionStart: [{ hooks: [mk('session-start')] }],\n UserPromptSubmit: [{ hooks: [mk('user-prompt')] }],\n PreToolUse: [{ matcher: '.*', hooks: [mk('post-tool-use')] }],\n PostToolUse: [{ matcher: '.*', hooks: [mk('post-tool-use')] }],\n Stop: [{ hooks: [mk('assistant-response')] }],\n SessionEnd: [{ hooks: [mk('session-end')] }],\n },\n };\n}\n\nfunction writeAntigravityHooksToDir(dir: string): string | null {\n const configPath = join(dir, 'hooks.json');\n let existing: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n try { existing = JSON.parse(readFileSync(configPath, 'utf-8')); } catch { existing = {}; }\n }\n const generated = generateAntigravityHooksConfig();\n // Antigravity keys hook blocks by name; RuleMetric owns its own block\n // and never touches sibling blocks the user may have added.\n const merged = { ...existing, rulemetric: generated.rulemetric };\n mkdirSync(dir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\\n');\n return configPath;\n}\n\nexport function writeAntigravityHooks(projectPath: string): string | null {\n return writeAntigravityHooksToDir(join(projectPath, '.agents'));\n}\n\nexport function writeAntigravityUserHooks(): string | null {\n const configDir = join(homedir(), '.gemini', 'config');\n return writeAntigravityHooksToDir(configDir);\n}\n\nfunction removeAntigravityHooksFromFile(configPath: string): boolean {\n if (!existsSync(configPath)) return false;\n let existing: Record<string, unknown>;\n try { existing = JSON.parse(readFileSync(configPath, 'utf-8')); } catch { return false; }\n if (!('rulemetric' in existing)) return false;\n delete existing.rulemetric;\n if (Object.keys(existing).length === 0) {\n // No other blocks \u2014 remove the file entirely.\n try { unlinkSync(configPath); } catch { /* ignore */ }\n } else {\n writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\\n');\n }\n return true;\n}\n\nexport function removeAntigravityHooks(projectPath: string): boolean {\n return removeAntigravityHooksFromFile(join(projectPath, '.agents', 'hooks.json'));\n}\n\nexport function removeAntigravityUserHooks(): boolean {\n const modern = removeAntigravityHooksFromFile(join(homedir(), '.gemini', 'config', 'hooks.json'));\n const legacy = removeAntigravityHooksFromFile(join(homedir(), '.gemini', 'hooks.json'));\n return modern || legacy;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,47 @@
1
+ // src/dashboard/launcher/api.ts
2
+ function apiUrl() {
3
+ return process.env.RULEMETRIC_API_URL ?? "http://localhost:3000";
4
+ }
5
+ function authToken() {
6
+ const t = process.env.RULEMETRIC_API_KEY ?? process.env.RULEMETRIC_ACCESS_TOKEN;
7
+ if (!t) throw new Error("not signed in \u2014 run `rulemetric auth login`");
8
+ return t;
9
+ }
10
+ async function request(path, init) {
11
+ const resp = await fetch(`${apiUrl()}${path}`, {
12
+ ...init,
13
+ headers: {
14
+ Authorization: `Bearer ${authToken()}`,
15
+ "Content-Type": "application/json",
16
+ ...init?.headers ?? {}
17
+ },
18
+ signal: AbortSignal.timeout(1e4)
19
+ });
20
+ if (!resp.ok) {
21
+ throw new Error(`${resp.status} ${resp.statusText}`);
22
+ }
23
+ return await resp.json();
24
+ }
25
+ function fetchLaunchJobs({ limit }) {
26
+ return request(`/api/launch-jobs?limit=${limit}`);
27
+ }
28
+ function createLaunchJob(payload) {
29
+ return request("/api/launch-jobs", {
30
+ method: "POST",
31
+ body: JSON.stringify(payload)
32
+ });
33
+ }
34
+ function cancelLaunchJob(id) {
35
+ return request(`/api/launch-jobs/${id}/cancel`, { method: "POST" });
36
+ }
37
+ function listLaunchers() {
38
+ return request("/api/launchers");
39
+ }
40
+
41
+ export {
42
+ fetchLaunchJobs,
43
+ createLaunchJob,
44
+ cancelLaunchJob,
45
+ listLaunchers
46
+ };
47
+ //# sourceMappingURL=chunk-N52AHNBH.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/dashboard/launcher/api.ts"],
4
+ "sourcesContent": ["import type { LaunchJob, AvailableLauncher, CreateLaunchPayload } from './types.js';\n\nfunction apiUrl(): string {\n return process.env.RULEMETRIC_API_URL ?? 'http://localhost:3000';\n}\n\nfunction authToken(): string {\n const t = process.env.RULEMETRIC_API_KEY ?? process.env.RULEMETRIC_ACCESS_TOKEN;\n if (!t) throw new Error('not signed in \u2014 run `rulemetric auth login`');\n return t;\n}\n\nasync function request<T>(path: string, init?: RequestInit): Promise<T> {\n const resp = await fetch(`${apiUrl()}${path}`, {\n ...init,\n headers: {\n Authorization: `Bearer ${authToken()}`,\n 'Content-Type': 'application/json',\n ...(init?.headers ?? {}),\n },\n signal: AbortSignal.timeout(10_000),\n });\n if (!resp.ok) {\n throw new Error(`${resp.status} ${resp.statusText}`);\n }\n return (await resp.json()) as T;\n}\n\nexport function fetchLaunchJobs({ limit }: { limit: number }): Promise<LaunchJob[]> {\n return request<LaunchJob[]>(`/api/launch-jobs?limit=${limit}`);\n}\n\nexport function createLaunchJob(payload: CreateLaunchPayload): Promise<LaunchJob> {\n return request<LaunchJob>('/api/launch-jobs', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n}\n\nexport function cancelLaunchJob(id: string): Promise<{ ok: true }> {\n return request<{ ok: true }>(`/api/launch-jobs/${id}/cancel`, { method: 'POST' });\n}\n\nexport function listLaunchers(): Promise<AvailableLauncher[]> {\n return request<AvailableLauncher[]>('/api/launchers');\n}\n"],
5
+ "mappings": ";AAEA,SAAS,SAAiB;AACxB,SAAO,QAAQ,IAAI,sBAAsB;AAC3C;AAEA,SAAS,YAAoB;AAC3B,QAAM,IAAI,QAAQ,IAAI,sBAAsB,QAAQ,IAAI;AACxD,MAAI,CAAC,EAAG,OAAM,IAAI,MAAM,kDAA6C;AACrE,SAAO;AACT;AAEA,eAAe,QAAW,MAAc,MAAgC;AACtE,QAAM,OAAO,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI;AAAA,IAC7C,GAAG;AAAA,IACH,SAAS;AAAA,MACP,eAAe,UAAU,UAAU,CAAC;AAAA,MACpC,gBAAgB;AAAA,MAChB,GAAI,MAAM,WAAW,CAAC;AAAA,IACxB;AAAA,IACA,QAAQ,YAAY,QAAQ,GAAM;AAAA,EACpC,CAAC;AACD,MAAI,CAAC,KAAK,IAAI;AACZ,UAAM,IAAI,MAAM,GAAG,KAAK,MAAM,IAAI,KAAK,UAAU,EAAE;AAAA,EACrD;AACA,SAAQ,MAAM,KAAK,KAAK;AAC1B;AAEO,SAAS,gBAAgB,EAAE,MAAM,GAA4C;AAClF,SAAO,QAAqB,0BAA0B,KAAK,EAAE;AAC/D;AAEO,SAAS,gBAAgB,SAAkD;AAChF,SAAO,QAAmB,oBAAoB;AAAA,IAC5C,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AACH;AAEO,SAAS,gBAAgB,IAAmC;AACjE,SAAO,QAAsB,oBAAoB,EAAE,WAAW,EAAE,QAAQ,OAAO,CAAC;AAClF;AAEO,SAAS,gBAA8C;AAC5D,SAAO,QAA6B,gBAAgB;AACtD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,228 @@
1
+ // ../../packages/email/dist/templates/changelog-announcement.js
2
+ var ACCENT = "#5b6cff";
3
+ var TEXT_PRIMARY = "#1a1a1a";
4
+ var TEXT_MUTED = "#666666";
5
+ var BG_OUTER = "#f5f5f7";
6
+ var BG_CARD = "#ffffff";
7
+ var BORDER = "#e5e5e9";
8
+ var SECTION_ORDER = [
9
+ "Added",
10
+ "Changed",
11
+ "Fixed",
12
+ "Removed",
13
+ "Deprecated",
14
+ "Security"
15
+ ];
16
+ function formatIsoDate(iso) {
17
+ const months = [
18
+ "January",
19
+ "February",
20
+ "March",
21
+ "April",
22
+ "May",
23
+ "June",
24
+ "July",
25
+ "August",
26
+ "September",
27
+ "October",
28
+ "November",
29
+ "December"
30
+ ];
31
+ const [y, m, d] = iso.split("-").map((s) => parseInt(s, 10));
32
+ if (!y || !m || !d || m < 1 || m > 12)
33
+ return iso;
34
+ return `${months[m - 1]} ${d}, ${y}`;
35
+ }
36
+ function escapeHtml(s) {
37
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
38
+ }
39
+ function orderedSections(sections) {
40
+ const out = [];
41
+ for (const name of SECTION_ORDER) {
42
+ const items = sections[name];
43
+ if (items && items.length > 0) {
44
+ out.push({ name, items });
45
+ }
46
+ }
47
+ return out;
48
+ }
49
+ function renderChangelogAnnouncement(input) {
50
+ const { version, date, sections, unsubscribeUrl, productUrl, recipientName } = input;
51
+ const formattedDate = formatIsoDate(date);
52
+ const subject = `What's new in RuleMetric \u2014 ${formattedDate}`;
53
+ const greeting = recipientName ? `Hi ${recipientName},` : "Hi there,";
54
+ const ordered = orderedSections(sections);
55
+ const year = (/* @__PURE__ */ new Date()).getUTCFullYear();
56
+ const sectionsHtml = ordered.map(({ name, items }) => {
57
+ const lis = items.map((it) => ` <li style="margin:0 0 6px 0;font-size:15px;line-height:1.5;color:${TEXT_PRIMARY};">${escapeHtml(it)}</li>`).join("\n");
58
+ return ` <h3 style="margin:24px 0 8px 0;font-size:16px;line-height:1.3;font-weight:600;color:${TEXT_PRIMARY};">${name}</h3>
59
+ <ul style="margin:0 0 8px 0;padding-left:20px;">
60
+ ${lis}
61
+ </ul>`;
62
+ }).join("\n");
63
+ const html = `<!doctype html>
64
+ <html lang="en">
65
+ <head>
66
+ <meta charset="utf-8" />
67
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
68
+ <title>${escapeHtml(subject)}</title>
69
+ </head>
70
+ <body style="margin:0;padding:0;background:${BG_OUTER};font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;color:${TEXT_PRIMARY};">
71
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="background:${BG_OUTER};padding:32px 16px;">
72
+ <tr>
73
+ <td align="center">
74
+ <table role="presentation" width="560" cellspacing="0" cellpadding="0" border="0" style="max-width:560px;background:${BG_CARD};border:1px solid ${BORDER};border-radius:8px;overflow:hidden;">
75
+ <tr>
76
+ <td style="padding:24px 32px 8px 32px;">
77
+ <a href="${escapeHtml(productUrl)}" style="text-decoration:none;color:${ACCENT};font-size:14px;font-weight:600;">RuleMetric</a>
78
+ </td>
79
+ </tr>
80
+ <tr>
81
+ <td style="padding:8px 32px 8px 32px;">
82
+ <h1 style="margin:0 0 8px 0;font-size:22px;line-height:1.3;font-weight:600;color:${TEXT_PRIMARY};">
83
+ What's new \u2014 ${escapeHtml(formattedDate)}
84
+ </h1>
85
+ <p style="margin:0 0 8px 0;font-size:13px;line-height:1.5;color:${TEXT_MUTED};">
86
+ Release ${escapeHtml(version)}
87
+ </p>
88
+ <p style="margin:16px 0 0 0;font-size:15px;line-height:1.5;color:${TEXT_PRIMARY};">
89
+ ${escapeHtml(greeting)}
90
+ </p>
91
+ <p style="margin:8px 0 0 0;font-size:15px;line-height:1.5;color:${TEXT_PRIMARY};">
92
+ Here's what shipped in the latest RuleMetric release.
93
+ </p>
94
+ </td>
95
+ </tr>
96
+ <tr>
97
+ <td style="padding:0 32px 16px 32px;">
98
+ ${sectionsHtml}
99
+ </td>
100
+ </tr>
101
+ <tr>
102
+ <td style="padding:16px 32px 24px 32px;border-top:1px solid ${BORDER};">
103
+ <p style="margin:0 0 8px 0;font-size:12px;line-height:1.5;color:${TEXT_MUTED};">
104
+ You're receiving this because you signed up for RuleMetric product updates. If you'd rather not hear about new releases, you can unsubscribe at any time.
105
+ </p>
106
+ <p style="margin:0 0 4px 0;font-size:12px;line-height:1.5;">
107
+ <a href="${escapeHtml(unsubscribeUrl)}" style="color:${ACCENT};text-decoration:underline;">Unsubscribe</a>
108
+ </p>
109
+ <p style="margin:0 0 12px 0;font-size:12px;line-height:1.5;color:${TEXT_MUTED};word-break:break-all;">
110
+ ${escapeHtml(unsubscribeUrl)}
111
+ </p>
112
+ <p style="margin:0;font-size:11px;line-height:1.5;color:${TEXT_MUTED};">
113
+ RuleMetric \u2022 ${year}
114
+ </p>
115
+ </td>
116
+ </tr>
117
+ </table>
118
+ </td>
119
+ </tr>
120
+ </table>
121
+ </body>
122
+ </html>`;
123
+ const textLines = [
124
+ `What's new in RuleMetric \u2014 ${formattedDate}`,
125
+ `Release ${version}`,
126
+ "",
127
+ greeting,
128
+ "",
129
+ `Here's what shipped in the latest RuleMetric release.`,
130
+ ""
131
+ ];
132
+ for (const { name, items } of ordered) {
133
+ textLines.push(`${name}:`);
134
+ for (const it of items) {
135
+ textLines.push(` - ${it}`);
136
+ }
137
+ textLines.push("");
138
+ }
139
+ textLines.push("--", `You're receiving this because you signed up for RuleMetric product updates.`, `Unsubscribe: ${unsubscribeUrl}`, "", `RuleMetric \u2022 ${year}`);
140
+ const text = textLines.join("\n");
141
+ return { subject, html, text };
142
+ }
143
+
144
+ // ../../packages/email/dist/providers/noop.js
145
+ import { randomBytes } from "node:crypto";
146
+ async function sendNoopEmail(params) {
147
+ const keyNote = params.idempotencyKey ? ` idempotencyKey=${params.idempotencyKey}` : "";
148
+ process.stderr.write(`[email:noop] would send to=${params.to} subject=${JSON.stringify(params.subject)}${keyNote}
149
+ `);
150
+ return {
151
+ id: `noop-${randomBytes(8).toString("hex")}`,
152
+ provider: "noop"
153
+ };
154
+ }
155
+
156
+ // ../../packages/email/dist/providers/resend.js
157
+ var cachedClient = null;
158
+ async function getClient() {
159
+ if (cachedClient)
160
+ return cachedClient;
161
+ const apiKey = process.env.RESEND_API_KEY;
162
+ if (!apiKey) {
163
+ throw new Error("RESEND_API_KEY is not set");
164
+ }
165
+ const { Resend } = await import("resend");
166
+ cachedClient = new Resend(apiKey);
167
+ return cachedClient;
168
+ }
169
+ async function sendResendEmail(params) {
170
+ const fromName = params.fromName ?? "RuleMetric";
171
+ const fromEmail = process.env.RESEND_FROM_EMAIL ?? "onboarding@resend.dev";
172
+ const from = `${fromName} <${fromEmail}>`;
173
+ const client = await getClient();
174
+ const options = params.idempotencyKey ? { idempotencyKey: params.idempotencyKey } : void 0;
175
+ const result = await client.emails.send({
176
+ from,
177
+ to: params.to,
178
+ subject: params.subject,
179
+ html: params.html,
180
+ text: params.text
181
+ }, options);
182
+ if (result.error) {
183
+ throw new Error(`Resend send failed: ${result.error.message}`);
184
+ }
185
+ if (!result.data) {
186
+ throw new Error("Resend send returned no data and no error");
187
+ }
188
+ return { id: result.data.id, provider: "resend" };
189
+ }
190
+
191
+ // ../../packages/email/dist/providers/smtp.js
192
+ async function sendSmtpEmail(_params) {
193
+ throw new Error("SMTP provider not implemented. Set RESEND_API_KEY to use Resend, or unset RULEMETRIC_EMAIL_PROVIDER to fall back to noop.");
194
+ }
195
+
196
+ // ../../packages/email/dist/index.js
197
+ function selectEmailProvider() {
198
+ const explicit = process.env.RULEMETRIC_EMAIL_PROVIDER;
199
+ if (explicit === "resend" || explicit === "smtp" || explicit === "noop") {
200
+ return explicit;
201
+ }
202
+ if (process.env.RESEND_API_KEY)
203
+ return "resend";
204
+ return "noop";
205
+ }
206
+ var providerLogged = false;
207
+ async function sendEmail(params) {
208
+ const provider = selectEmailProvider();
209
+ if (!providerLogged) {
210
+ providerLogged = true;
211
+ process.stderr.write(`[email] active provider: ${provider}
212
+ `);
213
+ }
214
+ switch (provider) {
215
+ case "resend":
216
+ return sendResendEmail(params);
217
+ case "smtp":
218
+ return sendSmtpEmail(params);
219
+ case "noop":
220
+ return sendNoopEmail(params);
221
+ }
222
+ }
223
+
224
+ export {
225
+ renderChangelogAnnouncement,
226
+ sendEmail
227
+ };
228
+ //# sourceMappingURL=chunk-NIDLJO6F.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../packages/email/src/templates/changelog-announcement.ts", "../../../packages/email/src/providers/noop.ts", "../../../packages/email/src/providers/resend.ts", "../../../packages/email/src/providers/smtp.ts", "../../../packages/email/src/index.ts"],
4
+ "sourcesContent": ["// Product-announcement email template. Pure function \u2014 given a parsed\n// CHANGELOG entry, returns subject + html + text. No provider work, no\n// env reads, no IO.\n//\n// Design notes:\n// - Conventions mirror invitation.ts: inline styles only, viewport meta,\n// simple table layout, hand-rolled plain-text body, same colour palette.\n// - Section order is fixed (Added \u2192 Changed \u2192 Fixed \u2192 Removed \u2192\n// Deprecated \u2192 Security) regardless of insertion order in the input,\n// so a single deployment can't produce inconsistent ordering across\n// recipients.\n// - Footer carries the unsubscribe URL twice (styled link + raw text)\n// for CAN-SPAM compliance and because some clients suppress link\n// rendering.\n\nimport type { RenderedEmail } from './invitation.js';\n\nexport type ChangelogSectionName =\n | 'Added'\n | 'Changed'\n | 'Fixed'\n | 'Removed'\n | 'Deprecated'\n | 'Security';\n\nexport interface ChangelogAnnouncementInput {\n /** Verbatim version string from CHANGELOG, e.g. \"2026.06.05\". */\n version: string;\n /** ISO date YYYY-MM-DD. */\n date: string;\n /** Section name \u2192 array of bullet items. Items are plain text (no markdown). */\n sections: Partial<Record<ChangelogSectionName, string[]>>;\n /** Fully-qualified unsubscribe URL embedded in the footer. */\n unsubscribeUrl: string;\n /** Product home URL (e.g. https://rulemetric.com). For the header logo link. */\n productUrl: string;\n /** Optional recipient first name to personalize greeting; falls back to \"Hi there,\". */\n recipientName?: string;\n}\n\nconst ACCENT = '#5b6cff';\nconst TEXT_PRIMARY = '#1a1a1a';\nconst TEXT_MUTED = '#666666';\nconst BG_OUTER = '#f5f5f7';\nconst BG_CARD = '#ffffff';\nconst BORDER = '#e5e5e9';\n\n/** Documented render order for sections \u2014 applied regardless of input key order. */\nconst SECTION_ORDER: ChangelogSectionName[] = [\n 'Added',\n 'Changed',\n 'Fixed',\n 'Removed',\n 'Deprecated',\n 'Security',\n];\n\n/**\n * \"June 5, 2026\" \u2014 locale-independent format identical to invitation.ts.\n * Accepts an ISO YYYY-MM-DD string; parsed as UTC to avoid off-by-one in\n * recipient timezones west of the build server.\n */\nfunction formatIsoDate(iso: string): string {\n const months = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December',\n ];\n const [y, m, d] = iso.split('-').map((s) => parseInt(s, 10));\n // Defensive: if the input is malformed we still want a string. Fall back\n // to the raw ISO so the recipient at least sees something coherent.\n if (!y || !m || !d || m < 1 || m > 12) return iso;\n return `${months[m - 1]} ${d}, ${y}`;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\n/** Returns sections in canonical order, dropping missing/empty ones. */\nfunction orderedSections(\n sections: ChangelogAnnouncementInput['sections'],\n): Array<{ name: ChangelogSectionName; items: string[] }> {\n const out: Array<{ name: ChangelogSectionName; items: string[] }> = [];\n for (const name of SECTION_ORDER) {\n const items = sections[name];\n if (items && items.length > 0) {\n out.push({ name, items });\n }\n }\n return out;\n}\n\nexport function renderChangelogAnnouncement(\n input: ChangelogAnnouncementInput,\n): RenderedEmail {\n const { version, date, sections, unsubscribeUrl, productUrl, recipientName } = input;\n\n const formattedDate = formatIsoDate(date);\n const subject = `What's new in RuleMetric \u2014 ${formattedDate}`;\n const greeting = recipientName ? `Hi ${recipientName},` : 'Hi there,';\n const ordered = orderedSections(sections);\n const year = new Date().getUTCFullYear();\n\n // \u2500\u2500 HTML sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const sectionsHtml = ordered\n .map(({ name, items }) => {\n const lis = items\n .map(\n (it) =>\n ` <li style=\"margin:0 0 6px 0;font-size:15px;line-height:1.5;color:${TEXT_PRIMARY};\">${escapeHtml(it)}</li>`,\n )\n .join('\\n');\n return ` <h3 style=\"margin:24px 0 8px 0;font-size:16px;line-height:1.3;font-weight:600;color:${TEXT_PRIMARY};\">${name}</h3>\n <ul style=\"margin:0 0 8px 0;padding-left:20px;\">\n${lis}\n </ul>`;\n })\n .join('\\n');\n\n // \u2500\u2500 HTML \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const html = `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${escapeHtml(subject)}</title>\n </head>\n <body style=\"margin:0;padding:0;background:${BG_OUTER};font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;color:${TEXT_PRIMARY};\">\n <table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" style=\"background:${BG_OUTER};padding:32px 16px;\">\n <tr>\n <td align=\"center\">\n <table role=\"presentation\" width=\"560\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" style=\"max-width:560px;background:${BG_CARD};border:1px solid ${BORDER};border-radius:8px;overflow:hidden;\">\n <tr>\n <td style=\"padding:24px 32px 8px 32px;\">\n <a href=\"${escapeHtml(productUrl)}\" style=\"text-decoration:none;color:${ACCENT};font-size:14px;font-weight:600;\">RuleMetric</a>\n </td>\n </tr>\n <tr>\n <td style=\"padding:8px 32px 8px 32px;\">\n <h1 style=\"margin:0 0 8px 0;font-size:22px;line-height:1.3;font-weight:600;color:${TEXT_PRIMARY};\">\n What's new \u2014 ${escapeHtml(formattedDate)}\n </h1>\n <p style=\"margin:0 0 8px 0;font-size:13px;line-height:1.5;color:${TEXT_MUTED};\">\n Release ${escapeHtml(version)}\n </p>\n <p style=\"margin:16px 0 0 0;font-size:15px;line-height:1.5;color:${TEXT_PRIMARY};\">\n ${escapeHtml(greeting)}\n </p>\n <p style=\"margin:8px 0 0 0;font-size:15px;line-height:1.5;color:${TEXT_PRIMARY};\">\n Here's what shipped in the latest RuleMetric release.\n </p>\n </td>\n </tr>\n <tr>\n <td style=\"padding:0 32px 16px 32px;\">\n${sectionsHtml}\n </td>\n </tr>\n <tr>\n <td style=\"padding:16px 32px 24px 32px;border-top:1px solid ${BORDER};\">\n <p style=\"margin:0 0 8px 0;font-size:12px;line-height:1.5;color:${TEXT_MUTED};\">\n You're receiving this because you signed up for RuleMetric product updates. If you'd rather not hear about new releases, you can unsubscribe at any time.\n </p>\n <p style=\"margin:0 0 4px 0;font-size:12px;line-height:1.5;\">\n <a href=\"${escapeHtml(unsubscribeUrl)}\" style=\"color:${ACCENT};text-decoration:underline;\">Unsubscribe</a>\n </p>\n <p style=\"margin:0 0 12px 0;font-size:12px;line-height:1.5;color:${TEXT_MUTED};word-break:break-all;\">\n ${escapeHtml(unsubscribeUrl)}\n </p>\n <p style=\"margin:0;font-size:11px;line-height:1.5;color:${TEXT_MUTED};\">\n RuleMetric \u2022 ${year}\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n</html>`;\n\n // \u2500\u2500 Plain text \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const textLines: string[] = [\n `What's new in RuleMetric \u2014 ${formattedDate}`,\n `Release ${version}`,\n '',\n greeting,\n '',\n `Here's what shipped in the latest RuleMetric release.`,\n '',\n ];\n for (const { name, items } of ordered) {\n textLines.push(`${name}:`);\n for (const it of items) {\n textLines.push(` - ${it}`);\n }\n textLines.push('');\n }\n textLines.push(\n '--',\n `You're receiving this because you signed up for RuleMetric product updates.`,\n `Unsubscribe: ${unsubscribeUrl}`,\n '',\n `RuleMetric \u2022 ${year}`,\n );\n const text = textLines.join('\\n');\n\n return { subject, html, text };\n}\n", "// No-op email provider. Used in dev/test when no real email infrastructure\n// is configured. Logs the destination + subject to stderr so operators can\n// see that a send was requested, then returns a synthetic id. Never throws.\n//\n// This is intentionally the default \u2014 it lets the test suite run without\n// any email environment variables and lets local development work without\n// an email account. Switch to `resend` by setting RESEND_API_KEY, or force\n// noop explicitly with RULEMETRIC_EMAIL_PROVIDER=noop.\n\nimport { randomBytes } from 'node:crypto';\nimport type { SendEmailParams, SendEmailResult } from '../index.js';\n\nexport async function sendNoopEmail(params: SendEmailParams): Promise<SendEmailResult> {\n // Use stderr (same convention as the dev-mode invite log) so it doesn't\n // pollute stdout if a caller is parsing JSON from there.\n const keyNote = params.idempotencyKey ? ` idempotencyKey=${params.idempotencyKey}` : '';\n process.stderr.write(\n `[email:noop] would send to=${params.to} subject=${JSON.stringify(params.subject)}${keyNote}\\n`,\n );\n return {\n id: `noop-${randomBytes(8).toString('hex')}`,\n provider: 'noop',\n };\n}\n", "// Resend provider. Activated when RESEND_API_KEY is set. The Resend SDK is\n// imported lazily so that environments without `resend` installed (or where\n// the dependency hasn't been hoisted yet) don't crash at module-load time \u2014\n// only when a send is actually attempted via this provider.\n//\n// `from` is computed from RESEND_FROM_EMAIL (default: onboarding@resend.dev,\n// which works out of the box with a fresh Resend account for testing).\n\nimport type { SendEmailParams, SendEmailResult } from '../index.js';\n\nlet cachedClient: {\n emails: {\n send: (input: ResendSendInput, options?: ResendSendOptions) => Promise<ResendSendResult>;\n };\n} | null = null;\n\ninterface ResendSendInput {\n from: string;\n to: string | string[];\n subject: string;\n html: string;\n text: string;\n}\n\ninterface ResendSendOptions {\n idempotencyKey?: string;\n}\n\ninterface ResendSendResult {\n data: { id: string } | null;\n error: { message: string; name?: string } | null;\n}\n\nasync function getClient() {\n if (cachedClient) return cachedClient;\n const apiKey = process.env.RESEND_API_KEY;\n if (!apiKey) {\n throw new Error('RESEND_API_KEY is not set');\n }\n // Lazy ESM import. Resend ships ESM-compatible types in its modern releases.\n const { Resend } = (await import('resend')) as {\n Resend: new (key: string) => {\n emails: {\n send: (input: ResendSendInput, options?: ResendSendOptions) => Promise<ResendSendResult>;\n };\n };\n };\n cachedClient = new Resend(apiKey);\n return cachedClient;\n}\n\nexport async function sendResendEmail(\n params: SendEmailParams,\n): Promise<SendEmailResult> {\n const fromName = params.fromName ?? 'RuleMetric';\n const fromEmail = process.env.RESEND_FROM_EMAIL ?? 'onboarding@resend.dev';\n const from = `${fromName} <${fromEmail}>`;\n\n const client = await getClient();\n // Idempotency-Key is a request option in the Resend SDK (not a body field).\n // Resend caches responses keyed on (api_key, idempotency_key) for 24 hours \u2014\n // a duplicate send with the same key returns the original response.\n const options: ResendSendOptions | undefined = params.idempotencyKey\n ? { idempotencyKey: params.idempotencyKey }\n : undefined;\n const result = await client.emails.send(\n {\n from,\n to: params.to,\n subject: params.subject,\n html: params.html,\n text: params.text,\n },\n options,\n );\n\n if (result.error) {\n throw new Error(`Resend send failed: ${result.error.message}`);\n }\n if (!result.data) {\n throw new Error('Resend send returned no data and no error');\n }\n\n return { id: result.data.id, provider: 'resend' };\n}\n\n// For tests: reset the cached client so a fresh API key is picked up.\nexport function _resetResendClient() {\n cachedClient = null;\n}\n", "// SMTP provider \u2014 stub for now.\n//\n// We don't ship `nodemailer` yet. If you want SMTP-based delivery (e.g.\n// to use Supabase's project-level SMTP config), this is where it goes:\n// add `nodemailer` to package.json, parse SMTP_* env vars (or\n// SUPABASE_SMTP_*), build a transport, and call `transport.sendMail(...)`.\n//\n// Until that's wired, this stub throws \u2014 so selectEmailProvider() never\n// chooses 'smtp' unless a future env-var (`RULEMETRIC_EMAIL_PROVIDER=smtp`)\n// is explicitly set, in which case the caller will get a clear error\n// rather than silent failure.\n\nimport type { SendEmailParams, SendEmailResult } from '../index.js';\n\nexport async function sendSmtpEmail(\n _params: SendEmailParams,\n): Promise<SendEmailResult> {\n throw new Error(\n 'SMTP provider not implemented. Set RESEND_API_KEY to use Resend, or unset RULEMETRIC_EMAIL_PROVIDER to fall back to noop.',\n );\n}\n", "// @rulemetric/email \u2014 small abstraction over a transactional-email provider.\n//\n// At module load we DON'T pick a provider \u2014 we resolve it on the first call\n// to `sendEmail`. This is so tests can flip env vars (RESEND_API_KEY,\n// RULEMETRIC_EMAIL_PROVIDER) between cases and observe different behaviour\n// without juggling module imports.\n//\n// Provider selection (highest to lowest precedence):\n// 1. RULEMETRIC_EMAIL_PROVIDER env var ('resend' | 'smtp' | 'noop') \u2014 explicit.\n// 2. If RESEND_API_KEY is set \u2192 'resend'.\n// 3. Otherwise \u2192 'noop' (logs to stderr, returns synthetic id).\n//\n// `noop` is the default to keep the test suite from needing real email\n// infrastructure. Failures from real providers bubble up \u2014 the caller (e.g.\n// the invitation route) decides whether a delivery failure should fail the\n// request or just be logged.\n\nimport { sendNoopEmail } from './providers/noop.js';\nimport { sendResendEmail } from './providers/resend.js';\nimport { sendSmtpEmail } from './providers/smtp.js';\n\nexport interface SendEmailParams {\n to: string;\n subject: string;\n html: string;\n text: string;\n /** Display name for the From header. Defaults to 'RuleMetric'. */\n fromName?: string;\n /**\n * Provider-side idempotency key. When set, the provider deduplicates\n * concurrent / retried sends with the same key for a provider-defined\n * window (Resend: 24h). Required for safe-retry email pipelines \u2014\n * callers should derive this from a stable per-recipient row id\n * (e.g. `announcement_deliveries.id`), NOT a per-attempt nonce.\n */\n idempotencyKey?: string;\n}\n\nexport type EmailProvider = 'resend' | 'noop' | 'smtp';\n\nexport interface SendEmailResult {\n id: string;\n provider: EmailProvider;\n}\n\n/** Pure function \u2014 exported for testing. Reads `process.env` each call. */\nexport function selectEmailProvider(): EmailProvider {\n const explicit = process.env.RULEMETRIC_EMAIL_PROVIDER;\n if (explicit === 'resend' || explicit === 'smtp' || explicit === 'noop') {\n return explicit;\n }\n if (process.env.RESEND_API_KEY) return 'resend';\n return 'noop';\n}\n\n// Track whether we've logged the active provider yet \u2014 log-once so dev/test\n// stderr doesn't get spammed.\nlet providerLogged = false;\n\nexport async function sendEmail(params: SendEmailParams): Promise<SendEmailResult> {\n const provider = selectEmailProvider();\n if (!providerLogged) {\n providerLogged = true;\n process.stderr.write(`[email] active provider: ${provider}\\n`);\n }\n switch (provider) {\n case 'resend':\n return sendResendEmail(params);\n case 'smtp':\n return sendSmtpEmail(params);\n case 'noop':\n return sendNoopEmail(params);\n }\n}\n\n/** Test helper: reset the provider-logged flag. */\nexport function _resetEmailLogState() {\n providerLogged = false;\n}\n\nexport { renderInvitation } from './templates/invitation.js';\nexport type { InvitationTemplateInput, RenderedEmail } from './templates/invitation.js';\nexport { renderChangelogAnnouncement } from './templates/changelog-announcement.js';\nexport type {\n ChangelogAnnouncementInput,\n ChangelogSectionName,\n} from './templates/changelog-announcement.js';\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+
13
+ export {
14
+ __require,
15
+ __export
16
+ };
17
+ //# sourceMappingURL=chunk-NSBPE2FW.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,70 @@
1
+ // src/lib/version-check.ts
2
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ var CONFIG_DIR = join(homedir(), ".config", "rulemetric");
6
+ var CACHE_FILE = join(CONFIG_DIR, "version-check.json");
7
+ var TTL_MS = 60 * 60 * 1e3;
8
+ function readCache() {
9
+ try {
10
+ const data = JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
11
+ if (typeof data.latest === "string" && typeof data.fetchedAtMs === "number") {
12
+ return data;
13
+ }
14
+ return null;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ function writeCache(entry) {
20
+ try {
21
+ mkdirSync(CONFIG_DIR, { recursive: true });
22
+ writeFileSync(CACHE_FILE, JSON.stringify(entry));
23
+ } catch {
24
+ }
25
+ }
26
+ function compareVersions(a, b) {
27
+ const parse = (v) => v.split(".").map((n) => Number.parseInt(n, 10) || 0);
28
+ const pa = parse(a);
29
+ const pb = parse(b);
30
+ const len = Math.max(pa.length, pb.length);
31
+ for (let i = 0; i < len; i++) {
32
+ const ai = pa[i] ?? 0;
33
+ const bi = pb[i] ?? 0;
34
+ if (ai < bi) return -1;
35
+ if (ai > bi) return 1;
36
+ }
37
+ return 0;
38
+ }
39
+ function getApiUrl() {
40
+ const env = process.env.RULEMETRIC_API_URL;
41
+ if (env) return env.replace(/\/$/, "");
42
+ return "https://rulemetric.com";
43
+ }
44
+ function refreshVersionCacheInBackground() {
45
+ const cached = readCache();
46
+ if (cached && Date.now() - cached.fetchedAtMs < TTL_MS) return;
47
+ const controller = new AbortController();
48
+ const timer = setTimeout(() => controller.abort(), 3e3);
49
+ globalThis.fetch(`${getApiUrl()}/api/cli/latest-version`, { signal: controller.signal }).then(async (res) => {
50
+ clearTimeout(timer);
51
+ if (!res.ok) return;
52
+ const data = await res.json();
53
+ if (typeof data.latest !== "string") return;
54
+ writeCache({ latest: data.latest, fetchedAtMs: Date.now() });
55
+ }).catch(() => {
56
+ clearTimeout(timer);
57
+ });
58
+ }
59
+ function getUpgradeBanner(currentVersion) {
60
+ const cached = readCache();
61
+ if (!cached) return null;
62
+ if (compareVersions(cached.latest, currentVersion) <= 0) return null;
63
+ return `RuleMetric ${cached.latest} available \u2014 you're on ${currentVersion}.`;
64
+ }
65
+
66
+ export {
67
+ refreshVersionCacheInBackground,
68
+ getUpgradeBanner
69
+ };
70
+ //# sourceMappingURL=chunk-OGVORIFM.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/lib/version-check.ts"],
4
+ "sourcesContent": ["// CLI version-check banner. Every command kicks off an async fetch to\n// /api/cli/latest-version (cached for an hour) and prints a one-line\n// notice on the next invocation if the cached version is newer than the\n// currently-running CLI.\n//\n// Design notes:\n// - Fire-and-forget: we never block command execution on the network.\n// - Cache: ~/.config/rulemetric/version-check.json, TTL 1h. Stored on disk\n// so the check survives between CLI invocations (each invocation is a\n// fresh process \u2014 in-memory cache wouldn't help).\n// - \"Newer\" uses semver-naive numeric comparison split on dots \u2014 fine for\n// our 0.x line; tightening this is a follow-up if/when we adopt semver\n// pre-releases.\n// - We DO NOT have an `upgrade` command yet; the banner just says \"version\n// X.Y.Z available\" and trusts the user to know how they installed.\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst CACHE_FILE = join(CONFIG_DIR, 'version-check.json');\nconst TTL_MS = 60 * 60 * 1000; // 1h\n\ninterface CacheEntry {\n latest: string;\n fetchedAtMs: number;\n}\n\nfunction readCache(): CacheEntry | null {\n try {\n const data = JSON.parse(readFileSync(CACHE_FILE, 'utf-8')) as CacheEntry;\n if (typeof data.latest === 'string' && typeof data.fetchedAtMs === 'number') {\n return data;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(entry: CacheEntry): void {\n try {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CACHE_FILE, JSON.stringify(entry));\n } catch {\n // Best-effort: a write failure just means we'll re-fetch next time.\n }\n}\n\nfunction compareVersions(a: string, b: string): number {\n const parse = (v: string) => v.split('.').map((n) => Number.parseInt(n, 10) || 0);\n const pa = parse(a);\n const pb = parse(b);\n const len = Math.max(pa.length, pb.length);\n for (let i = 0; i < len; i++) {\n const ai = pa[i] ?? 0;\n const bi = pb[i] ?? 0;\n if (ai < bi) return -1;\n if (ai > bi) return 1;\n }\n return 0;\n}\n\nfunction getApiUrl(): string {\n const env = process.env.RULEMETRIC_API_URL;\n if (env) return env.replace(/\\/$/, '');\n return 'https://rulemetric.com';\n}\n\n/**\n * Fetches latest version from the API in the background and refreshes the\n * cache if the entry is missing or older than TTL_MS. Never throws.\n */\nexport function refreshVersionCacheInBackground(): void {\n const cached = readCache();\n if (cached && Date.now() - cached.fetchedAtMs < TTL_MS) return;\n\n // Fire-and-forget \u2014 explicitly catch every failure mode so an unhandled\n // rejection can never reach the user. AbortController guards against\n // hanging connections (3s budget).\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 3000);\n globalThis\n .fetch(`${getApiUrl()}/api/cli/latest-version`, { signal: controller.signal })\n .then(async (res) => {\n clearTimeout(timer);\n if (!res.ok) return;\n const data = (await res.json()) as { latest?: unknown };\n if (typeof data.latest !== 'string') return;\n writeCache({ latest: data.latest, fetchedAtMs: Date.now() });\n })\n .catch(() => {\n clearTimeout(timer);\n // Network error, timeout, malformed JSON \u2014 silently ignore. Banner\n // is purely a nicety; we never want it to surface failures.\n });\n}\n\n/**\n * Returns a one-line upgrade banner if a newer version is cached, else null.\n * Designed to be printed to stderr by the CLI's BaseCommand on launch.\n */\nexport function getUpgradeBanner(currentVersion: string): string | null {\n const cached = readCache();\n if (!cached) return null;\n if (compareVersions(cached.latest, currentVersion) <= 0) return null;\n return `RuleMetric ${cached.latest} available \u2014 you're on ${currentVersion}.`;\n}\n"],
5
+ "mappings": ";AAeA,SAAS,WAAW,cAAc,qBAAqB;AACvD,SAAS,eAAe;AACxB,SAAS,YAAY;AAErB,IAAM,aAAa,KAAK,QAAQ,GAAG,WAAW,YAAY;AAC1D,IAAM,aAAa,KAAK,YAAY,oBAAoB;AACxD,IAAM,SAAS,KAAK,KAAK;AAOzB,SAAS,YAA+B;AACtC,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AACzD,QAAI,OAAO,KAAK,WAAW,YAAY,OAAO,KAAK,gBAAgB,UAAU;AAC3E,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,OAAyB;AAC3C,MAAI;AACF,cAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,kBAAc,YAAY,KAAK,UAAU,KAAK,CAAC;AAAA,EACjD,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,gBAAgB,GAAW,GAAmB;AACrD,QAAM,QAAQ,CAAC,MAAc,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,OAAO,SAAS,GAAG,EAAE,KAAK,CAAC;AAChF,QAAM,KAAK,MAAM,CAAC;AAClB,QAAM,KAAK,MAAM,CAAC;AAClB,QAAM,MAAM,KAAK,IAAI,GAAG,QAAQ,GAAG,MAAM;AACzC,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,QAAI,KAAK,GAAI,QAAO;AACpB,QAAI,KAAK,GAAI,QAAO;AAAA,EACtB;AACA,SAAO;AACT;AAEA,SAAS,YAAoB;AAC3B,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,IAAK,QAAO,IAAI,QAAQ,OAAO,EAAE;AACrC,SAAO;AACT;AAMO,SAAS,kCAAwC;AACtD,QAAM,SAAS,UAAU;AACzB,MAAI,UAAU,KAAK,IAAI,IAAI,OAAO,cAAc,OAAQ;AAKxD,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AACvD,aACG,MAAM,GAAG,UAAU,CAAC,2BAA2B,EAAE,QAAQ,WAAW,OAAO,CAAC,EAC5E,KAAK,OAAO,QAAQ;AACnB,iBAAa,KAAK;AAClB,QAAI,CAAC,IAAI,GAAI;AACb,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,QAAI,OAAO,KAAK,WAAW,SAAU;AACrC,eAAW,EAAE,QAAQ,KAAK,QAAQ,aAAa,KAAK,IAAI,EAAE,CAAC;AAAA,EAC7D,CAAC,EACA,MAAM,MAAM;AACX,iBAAa,KAAK;AAAA,EAGpB,CAAC;AACL;AAMO,SAAS,iBAAiB,gBAAuC;AACtE,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,gBAAgB,OAAO,QAAQ,cAAc,KAAK,EAAG,QAAO;AAChE,SAAO,cAAc,OAAO,MAAM,+BAA0B,cAAc;AAC5E;",
6
+ "names": []
7
+ }
@@ -0,0 +1,77 @@
1
+ // src/lib/detect-languages.ts
2
+ import { existsSync, statSync, readdirSync } from "node:fs";
3
+ import path from "node:path";
4
+ var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
5
+ "node_modules",
6
+ ".git",
7
+ "dist",
8
+ "build",
9
+ ".next",
10
+ ".turbo",
11
+ ".worktrees",
12
+ "target",
13
+ "venv",
14
+ "__pycache__",
15
+ ".cache"
16
+ ]);
17
+ var MAX_DEPTH = 3;
18
+ function detectLanguages(projectPath) {
19
+ if (!existsSync(projectPath)) return [];
20
+ const signals = /* @__PURE__ */ new Set();
21
+ const walk = (dir, depth) => {
22
+ if (depth > MAX_DEPTH) return;
23
+ let entries;
24
+ try {
25
+ entries = readdirSync(dir);
26
+ } catch {
27
+ return;
28
+ }
29
+ for (const name of entries) {
30
+ if (name === "package.json") signals.add("JavaScript/TypeScript");
31
+ if (name === "tsconfig.json") signals.add("TypeScript-config");
32
+ if (name === "pyproject.toml") signals.add("Python-pyproject");
33
+ if (name === "setup.py") signals.add("Python-setup");
34
+ if (name === "requirements.txt") signals.add("Python-requirements");
35
+ if (name === "Pipfile") signals.add("Python-pipfile");
36
+ if (name === "Cargo.toml") signals.add("Rust-cargo");
37
+ if (name === "go.mod") signals.add("Go-mod");
38
+ if (name === "pom.xml") signals.add("Java-pom");
39
+ if (name === "build.gradle" || name === "build.gradle.kts") signals.add("Java-gradle");
40
+ if (name === "Gemfile") signals.add("Ruby-gemfile");
41
+ if (name === "composer.json") signals.add("PHP-composer");
42
+ if (name.endsWith(".ts") || name.endsWith(".tsx")) signals.add("TypeScript-source");
43
+ if (name.endsWith(".py")) signals.add("Python-source");
44
+ if (name.endsWith(".rs")) signals.add("Rust-source");
45
+ if (name.endsWith(".go")) signals.add("Go-source");
46
+ }
47
+ if (depth >= MAX_DEPTH) return;
48
+ for (const name of entries) {
49
+ if (EXCLUDE_DIRS.has(name)) continue;
50
+ const full = path.join(dir, name);
51
+ try {
52
+ if (statSync(full).isDirectory()) walk(full, depth + 1);
53
+ } catch {
54
+ }
55
+ }
56
+ };
57
+ walk(projectPath, 0);
58
+ const result = /* @__PURE__ */ new Set();
59
+ if (signals.has("TypeScript-source") || signals.has("TypeScript-config")) {
60
+ result.add("TypeScript");
61
+ } else if (signals.has("JavaScript/TypeScript")) {
62
+ result.add("JavaScript");
63
+ }
64
+ if (signals.has("Python-pyproject") || signals.has("Python-setup") || signals.has("Python-requirements") || signals.has("Python-pipfile") || signals.has("Python-source")) result.add("Python");
65
+ if (signals.has("Rust-cargo") || signals.has("Rust-source")) result.add("Rust");
66
+ if (signals.has("Go-mod") || signals.has("Go-source")) result.add("Go");
67
+ if (signals.has("Java-pom") || signals.has("Java-gradle")) result.add("Java");
68
+ if (signals.has("Ruby-gemfile")) result.add("Ruby");
69
+ if (signals.has("PHP-composer")) result.add("PHP");
70
+ if (signals.size < 2) return [];
71
+ return [...result];
72
+ }
73
+
74
+ export {
75
+ detectLanguages
76
+ };
77
+ //# sourceMappingURL=chunk-OQSQC7VB.js.map