@rulemetric/cli 0.7.2 → 0.7.4

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 (547) hide show
  1. package/dist/base-command.js +1 -14
  2. package/dist/chunk-2TC6WCUT.js +34 -0
  3. package/dist/chunk-2UC3ULIG.js +1 -0
  4. package/dist/chunk-3AV3GTMP.js +1 -0
  5. package/dist/chunk-4Z5ECCJE.js +1 -0
  6. package/dist/chunk-5RBLIVBF.js +1 -0
  7. package/dist/chunk-67QCYUJU.js +1 -0
  8. package/dist/chunk-6QKI756T.js +2 -0
  9. package/dist/chunk-6V4WM73L.js +1 -0
  10. package/dist/chunk-6XEC6474.js +1 -0
  11. package/dist/chunk-72XLQE3X.js +2 -0
  12. package/dist/chunk-7DFNBRLY.js +61 -0
  13. package/dist/chunk-7XQ4VPLC.js +2 -0
  14. package/dist/chunk-AHRHCERJ.js +1 -0
  15. package/dist/chunk-ARNZQBMX.js +1 -0
  16. package/dist/chunk-CADKBP3D.js +58 -0
  17. package/dist/chunk-CDI5CCHU.js +1 -0
  18. package/dist/chunk-CNQ5DTNC.js +1 -0
  19. package/dist/chunk-CRAKDQ4H.js +1 -0
  20. package/dist/chunk-DNF4HDI6.js +14 -0
  21. package/dist/chunk-DSO2U4Y6.js +56 -0
  22. package/dist/chunk-DT4GKEP5.js +5 -0
  23. package/dist/chunk-DVN7GFJG.js +1 -0
  24. package/dist/chunk-E4SFUPYR.js +15 -0
  25. package/dist/chunk-EUHNCVJQ.js +33 -0
  26. package/dist/chunk-F2VP4B4J.js +1 -0
  27. package/dist/chunk-FEHM5OKW.js +1 -0
  28. package/dist/chunk-FHVBTDBM.js +69 -0
  29. package/dist/chunk-GBMF3TP6.js +1 -0
  30. package/dist/chunk-GY5IJ4RS.js +1 -0
  31. package/dist/chunk-HOHD5HY2.js +5 -0
  32. package/dist/chunk-HP2BUPGS.js +24 -0
  33. package/dist/{chunk-OQBBVTDG.js → chunk-I2DZGJRR.js} +6 -71
  34. package/dist/chunk-I4YJ7NTX.js +1 -0
  35. package/dist/chunk-IY5NXR3N.js +1 -0
  36. package/dist/chunk-IZTIYR5Q.js +2 -0
  37. package/dist/chunk-KKDHD4XA.js +2 -0
  38. package/dist/chunk-LQRYQE6Q.js +4 -0
  39. package/dist/chunk-M6AJDVCL.js +5 -0
  40. package/dist/chunk-MGHFDHHM.js +1 -0
  41. package/dist/chunk-ML36XQW7.js +1 -0
  42. package/dist/chunk-MODXEGCU.js +1 -0
  43. package/dist/chunk-MVM6OGAF.js +4 -0
  44. package/dist/chunk-N7ODX6PO.js +1 -0
  45. package/dist/chunk-NBTC5FNV.js +1 -0
  46. package/dist/chunk-NJ5UED3H.js +1 -0
  47. package/dist/chunk-NVKX36YN.js +3 -0
  48. package/dist/chunk-NVOTOQBA.js +1 -0
  49. package/dist/chunk-O7ZMHCMG.js +31 -0
  50. package/dist/chunk-OMXUK4M6.js +1 -0
  51. package/dist/chunk-PZS2KOU7.js +1 -0
  52. package/dist/chunk-RSKQRVPJ.js +1 -0
  53. package/dist/chunk-RTEATXTP.js +1 -0
  54. package/dist/chunk-RTWRHIKY.js +7 -0
  55. package/dist/chunk-RVO4HV3M.js +1 -0
  56. package/dist/chunk-SBILN45P.js +1 -0
  57. package/dist/chunk-SZ62CP55.js +1 -0
  58. package/dist/chunk-T3W5N3BP.js +2 -0
  59. package/dist/chunk-TDD7IOV2.js +1 -0
  60. package/dist/chunk-TIQ7DQ3M.js +1 -0
  61. package/dist/chunk-TU2AR6XO.js +1 -0
  62. package/dist/chunk-UF6US7VU.js +1 -0
  63. package/dist/chunk-V5QFOF4F.js +9 -0
  64. package/dist/chunk-V5U3E4BZ.js +1 -0
  65. package/dist/chunk-VAFAH6QL.js +1 -0
  66. package/dist/chunk-VMWY7KHH.js +1 -0
  67. package/dist/chunk-VUGRXM7R.js +1 -0
  68. package/dist/{chunk-XZXS2W24.js → chunk-VWEXKDWG.js} +10 -56
  69. package/dist/chunk-W2MV25SB.js +1 -0
  70. package/dist/chunk-WJ3H73G6.js +1 -0
  71. package/dist/chunk-WJUQBMTF.js +9 -0
  72. package/dist/chunk-WLVQJH4E.js +1 -0
  73. package/dist/chunk-WPJ2BND4.js +1 -0
  74. package/dist/chunk-WSCK4WNK.js +1 -0
  75. package/dist/chunk-Y65CSJFF.js +3 -0
  76. package/dist/chunk-ZL4MZMUK.js +34 -0
  77. package/dist/chunk-ZLLER3HP.js +1 -0
  78. package/dist/chunk-ZXF5NE54.js +1 -0
  79. package/dist/commands/antigravity/backfill.js +2 -136
  80. package/dist/commands/auth/create-key.js +1 -52
  81. package/dist/commands/auth/login.js +1 -85
  82. package/dist/commands/auth/logout.js +1 -29
  83. package/dist/commands/auth/revoke-key.js +1 -33
  84. package/dist/commands/auth/signup.js +1 -89
  85. package/dist/commands/auth/status.js +1 -42
  86. package/dist/commands/catalog/index.js +2 -52
  87. package/dist/commands/catalog/recommend.js +3 -43
  88. package/dist/commands/convert.js +1 -75
  89. package/dist/commands/converters.js +1 -54
  90. package/dist/commands/crons/list.js +1 -41
  91. package/dist/commands/crons/run.js +2 -76
  92. package/dist/commands/dashboard.js +1 -46
  93. package/dist/commands/diagnostics.js +1 -117
  94. package/dist/commands/eval-targets/create.js +1 -53
  95. package/dist/commands/eval-targets/list.js +1 -54
  96. package/dist/commands/evals/agent.js +3 -309
  97. package/dist/commands/evals/benchmark.js +6 -73
  98. package/dist/commands/evals/compare.js +13 -96
  99. package/dist/commands/evals/create.js +1 -67
  100. package/dist/commands/evals/optimize-description.js +25 -239
  101. package/dist/commands/evals/optimize.js +5 -211
  102. package/dist/commands/evals/run.js +3 -183
  103. package/dist/commands/gateway/ensure.js +1 -104
  104. package/dist/commands/hooks/emit-instructions.js +1 -25
  105. package/dist/commands/hooks/install.js +1 -442
  106. package/dist/commands/hooks/run.js +3 -81
  107. package/dist/commands/hooks/uninstall.js +2 -156
  108. package/dist/commands/import.js +1 -66
  109. package/dist/commands/instructions/create.js +1 -74
  110. package/dist/commands/instructions/delete.js +1 -55
  111. package/dist/commands/instructions/fork.js +1 -34
  112. package/dist/commands/instructions/get.js +1 -68
  113. package/dist/commands/instructions/list.js +1 -65
  114. package/dist/commands/instructions/promote.js +1 -42
  115. package/dist/commands/instructions/pull.js +1 -39
  116. package/dist/commands/instructions/upstream.js +1 -38
  117. package/dist/commands/instructions/versions.js +1 -53
  118. package/dist/commands/launcher.js +1 -40
  119. package/dist/commands/org/current.js +1 -77
  120. package/dist/commands/org/list.js +1 -52
  121. package/dist/commands/org/switch.js +1 -71
  122. package/dist/commands/packs/add-instruction.js +1 -37
  123. package/dist/commands/packs/apply.js +1 -39
  124. package/dist/commands/packs/create.js +1 -50
  125. package/dist/commands/packs/fork.js +1 -34
  126. package/dist/commands/packs/get.js +3 -56
  127. package/dist/commands/packs/list.js +1 -66
  128. package/dist/commands/packs/remove-instruction.js +1 -35
  129. package/dist/commands/proxy/env.js +3 -131
  130. package/dist/commands/proxy/logs.js +3 -85
  131. package/dist/commands/proxy/restart.js +1 -35
  132. package/dist/commands/proxy/setup.js +15 -454
  133. package/dist/commands/proxy/start.js +10 -333
  134. package/dist/commands/proxy/status.js +1 -78
  135. package/dist/commands/proxy/stop.js +1 -94
  136. package/dist/commands/research/backfill.js +1 -59
  137. package/dist/commands/research/tail-transcript.js +1 -70
  138. package/dist/commands/service/install.js +57 -781
  139. package/dist/commands/service/status.js +1 -180
  140. package/dist/commands/service/uninstall.js +1 -119
  141. package/dist/commands/sessions/analyze.js +3 -48
  142. package/dist/commands/sessions/end.js +2 -85
  143. package/dist/commands/sessions/import.js +1 -46
  144. package/dist/commands/sessions/list.js +1 -48
  145. package/dist/commands/sessions/start.js +3 -90
  146. package/dist/commands/setup.js +3 -150
  147. package/dist/commands/skills/export-approved.js +1 -46
  148. package/dist/commands/skills/install.js +4 -107
  149. package/dist/commands/skills/list.js +4 -65
  150. package/dist/commands/skills/publish.js +2 -98
  151. package/dist/commands/skills/search.js +3 -72
  152. package/dist/commands/skills/update.js +3 -55
  153. package/dist/commands/suggestions/accept.js +8 -84
  154. package/dist/commands/suggestions/dismiss.js +1 -45
  155. package/dist/commands/suggestions/list.js +1 -61
  156. package/dist/commands/suggestions/refresh.js +1 -27
  157. package/dist/cursor-T7AMCMKS.js +13 -0
  158. package/dist/dashboard/Dashboard.js +1 -243
  159. package/dist/dashboard/data.js +1 -15
  160. package/dist/dashboard/launcher/ActiveJobsList.js +1 -10
  161. package/dist/dashboard/launcher/LauncherOverlay.js +1 -16
  162. package/dist/dashboard/launcher/NewLaunchForm.js +1 -10
  163. package/dist/dashboard/launcher/api.js +1 -16
  164. package/dist/dashboard/launcher/tool-labels.js +1 -10
  165. package/dist/dashboard/launcher/types.js +0 -1
  166. package/dist/dashboard/launcher/useLaunchJobs.js +1 -11
  167. package/dist/dashboard/panels/friction.js +1 -10
  168. package/dist/dashboard/panels/insights.js +1 -10
  169. package/dist/dashboard/panels/instructions.js +1 -10
  170. package/dist/dashboard/panels/outcomes.js +1 -10
  171. package/dist/dashboard/panels/overview.js +1 -10
  172. package/dist/dashboard/panels/shared.js +1 -19
  173. package/dist/dashboard/types.js +1 -24
  174. package/dist/dist-FAVALJ5C.js +1 -0
  175. package/dist/index.js +1 -8
  176. package/dist/lib/active-org-refresh.js +1 -15
  177. package/dist/lib/active-org.js +1 -16
  178. package/dist/lib/agent-loop.js +1 -46
  179. package/dist/lib/antigravity-transcript.js +1 -22
  180. package/dist/lib/api-client.js +1 -23
  181. package/dist/lib/auth.js +1 -30
  182. package/dist/lib/capture-hosts.js +1 -8
  183. package/dist/lib/detect-languages.js +1 -8
  184. package/dist/lib/detect-tmux.js +1 -9
  185. package/dist/lib/diagnostics.js +1 -12
  186. package/dist/lib/editor-proxy-pins.js +1 -14
  187. package/dist/lib/ensure-api-key.js +1 -11
  188. package/dist/lib/eval-analyzer.js +1 -9
  189. package/dist/lib/eval-benchmark.js +1 -12
  190. package/dist/lib/eval-conversation-handler.js +1 -13
  191. package/dist/lib/eval-executor.js +1 -8
  192. package/dist/lib/eval-grader.js +1 -9
  193. package/dist/lib/eval-meta-judge.js +1 -9
  194. package/dist/lib/eval-trigger-tester.js +1 -11
  195. package/dist/lib/eval-worktree.js +1 -8
  196. package/dist/lib/gateway-entry.js +1 -61
  197. package/dist/lib/gateway-identity.js +1 -16
  198. package/dist/lib/gateway-lifecycle.js +1 -32
  199. package/dist/lib/gateway.js +1 -14
  200. package/dist/lib/handlers/cron-refresh-pricing.js +1 -0
  201. package/dist/lib/handlers/cron-refresh-skills.js +1 -8
  202. package/dist/lib/handlers/cron-suggest-instructions.js +1 -15
  203. package/dist/lib/handlers/process-announcement.js +1 -11
  204. package/dist/lib/handlers/process-changelog.js +1 -11
  205. package/dist/lib/handlers/process-conversation.js +1 -14
  206. package/dist/lib/handlers/process-eval.js +1 -15
  207. package/dist/lib/handlers/process-insights.js +1 -14
  208. package/dist/lib/handlers/process-launch.js +1 -16
  209. package/dist/lib/handlers/process-run-cleanup.js +1 -13
  210. package/dist/lib/handlers/process-send-message.js +1 -10
  211. package/dist/lib/handlers/process-session-goal.js +1 -11
  212. package/dist/lib/hooks-config.js +1 -81
  213. package/dist/lib/insights-prompts.js +1 -12
  214. package/dist/lib/instruction-snapshot.js +1 -8
  215. package/dist/lib/job-helpers.js +0 -1
  216. package/dist/lib/llm-client.js +1 -17
  217. package/dist/lib/manual-tasks-meta.js +1 -8
  218. package/dist/lib/manual-tasks.js +1 -79
  219. package/dist/lib/output.js +1 -12
  220. package/dist/lib/permanent-job-error.js +1 -10
  221. package/dist/lib/pid-identity.js +1 -14
  222. package/dist/lib/proxy-respawn.js +1 -12
  223. package/dist/lib/research-client.js +1 -12
  224. package/dist/lib/setup-steps.js +1 -33
  225. package/dist/lib/skills-loader.js +1 -8
  226. package/dist/lib/statusline-shim.js +1 -20
  227. package/dist/lib/telemetry.js +1 -16
  228. package/dist/lib/terminal-target-heartbeat.js +1 -15
  229. package/dist/lib/tmux.js +1 -16
  230. package/dist/lib/transcript-rate-limit-watcher.js +1 -22
  231. package/dist/lib/types.js +1 -8
  232. package/dist/lib/version-check.js +1 -12
  233. package/dist/lib/which.js +1 -8
  234. package/dist/lib/worktree.js +1 -17
  235. package/dist/opencode-QRJ3BH23.js +1 -0
  236. package/oclif.manifest.json +135 -135
  237. package/package.json +8 -7
  238. package/dist/base-command.js.map +0 -7
  239. package/dist/chunk-2HK7RGZB.js +0 -82
  240. package/dist/chunk-2HK7RGZB.js.map +0 -7
  241. package/dist/chunk-2ORJWTNZ.js +0 -307
  242. package/dist/chunk-2ORJWTNZ.js.map +0 -7
  243. package/dist/chunk-37LN5O7M.js +0 -59
  244. package/dist/chunk-37LN5O7M.js.map +0 -7
  245. package/dist/chunk-3S7223UR.js +0 -81
  246. package/dist/chunk-3S7223UR.js.map +0 -7
  247. package/dist/chunk-3TIMQ3O6.js +0 -96
  248. package/dist/chunk-3TIMQ3O6.js.map +0 -7
  249. package/dist/chunk-42GFSAJP.js +0 -32
  250. package/dist/chunk-42GFSAJP.js.map +0 -7
  251. package/dist/chunk-4BHDHHKL.js +0 -48
  252. package/dist/chunk-4BHDHHKL.js.map +0 -7
  253. package/dist/chunk-4D537GXE.js +0 -99
  254. package/dist/chunk-4D537GXE.js.map +0 -7
  255. package/dist/chunk-4LYCDS2N.js +0 -139
  256. package/dist/chunk-4LYCDS2N.js.map +0 -7
  257. package/dist/chunk-4SCZK7AL.js +0 -129
  258. package/dist/chunk-4SCZK7AL.js.map +0 -7
  259. package/dist/chunk-4XAWK6S2.js +0 -161
  260. package/dist/chunk-4XAWK6S2.js.map +0 -7
  261. package/dist/chunk-52WIYRZH.js +0 -73
  262. package/dist/chunk-52WIYRZH.js.map +0 -7
  263. package/dist/chunk-5BAOGNUH.js +0 -79
  264. package/dist/chunk-5BAOGNUH.js.map +0 -7
  265. package/dist/chunk-5EDMGK3W.js +0 -39
  266. package/dist/chunk-5EDMGK3W.js.map +0 -7
  267. package/dist/chunk-6NBS5XFS.js +0 -99
  268. package/dist/chunk-6NBS5XFS.js.map +0 -7
  269. package/dist/chunk-7DULPSFU.js +0 -299
  270. package/dist/chunk-7DULPSFU.js.map +0 -7
  271. package/dist/chunk-7LVVKQMZ.js +0 -98
  272. package/dist/chunk-7LVVKQMZ.js.map +0 -7
  273. package/dist/chunk-7NNFYWKK.js +0 -243
  274. package/dist/chunk-7NNFYWKK.js.map +0 -7
  275. package/dist/chunk-7NYKWN7U.js +0 -12
  276. package/dist/chunk-7NYKWN7U.js.map +0 -7
  277. package/dist/chunk-BO76WKJR.js +0 -42
  278. package/dist/chunk-BO76WKJR.js.map +0 -7
  279. package/dist/chunk-BRD5RUGM.js +0 -53
  280. package/dist/chunk-BRD5RUGM.js.map +0 -7
  281. package/dist/chunk-BT6Z6545.js +0 -43
  282. package/dist/chunk-BT6Z6545.js.map +0 -7
  283. package/dist/chunk-BZDKEQKU.js +0 -39
  284. package/dist/chunk-BZDKEQKU.js.map +0 -7
  285. package/dist/chunk-DGHWRQXL.js +0 -17
  286. package/dist/chunk-DGHWRQXL.js.map +0 -7
  287. package/dist/chunk-DNKSVWMD.js +0 -108
  288. package/dist/chunk-DNKSVWMD.js.map +0 -7
  289. package/dist/chunk-DQ3KELXD.js +0 -74
  290. package/dist/chunk-DQ3KELXD.js.map +0 -7
  291. package/dist/chunk-DUJSRBLP.js +0 -122
  292. package/dist/chunk-DUJSRBLP.js.map +0 -7
  293. package/dist/chunk-E3BIT53W.js +0 -154
  294. package/dist/chunk-E3BIT53W.js.map +0 -7
  295. package/dist/chunk-EARWG4EV.js +0 -22
  296. package/dist/chunk-EARWG4EV.js.map +0 -7
  297. package/dist/chunk-EI5BHWXA.js +0 -1662
  298. package/dist/chunk-EI5BHWXA.js.map +0 -7
  299. package/dist/chunk-EJ3YAFDP.js +0 -37
  300. package/dist/chunk-EJ3YAFDP.js.map +0 -7
  301. package/dist/chunk-EKJ2CABV.js +0 -76
  302. package/dist/chunk-EKJ2CABV.js.map +0 -7
  303. package/dist/chunk-EKP32DLN.js +0 -16
  304. package/dist/chunk-EKP32DLN.js.map +0 -7
  305. package/dist/chunk-EYPAAGN5.js +0 -51
  306. package/dist/chunk-EYPAAGN5.js.map +0 -7
  307. package/dist/chunk-F5N6CLJJ.js +0 -1995
  308. package/dist/chunk-F5N6CLJJ.js.map +0 -7
  309. package/dist/chunk-FZKLLNDS.js +0 -228
  310. package/dist/chunk-FZKLLNDS.js.map +0 -7
  311. package/dist/chunk-GIUBARWS.js +0 -99
  312. package/dist/chunk-GIUBARWS.js.map +0 -7
  313. package/dist/chunk-GQNJO2P2.js +0 -102
  314. package/dist/chunk-GQNJO2P2.js.map +0 -7
  315. package/dist/chunk-IJGF2ETG.js +0 -68
  316. package/dist/chunk-IJGF2ETG.js.map +0 -7
  317. package/dist/chunk-ILYDELUE.js +0 -46
  318. package/dist/chunk-ILYDELUE.js.map +0 -7
  319. package/dist/chunk-J6QFW4LD.js +0 -55
  320. package/dist/chunk-J6QFW4LD.js.map +0 -7
  321. package/dist/chunk-J7N3DLH6.js +0 -117
  322. package/dist/chunk-J7N3DLH6.js.map +0 -7
  323. package/dist/chunk-JFDWKLQC.js +0 -23
  324. package/dist/chunk-JFDWKLQC.js.map +0 -7
  325. package/dist/chunk-JULOLTZS.js +0 -61
  326. package/dist/chunk-JULOLTZS.js.map +0 -7
  327. package/dist/chunk-KJKBDQ4D.js +0 -220
  328. package/dist/chunk-KJKBDQ4D.js.map +0 -7
  329. package/dist/chunk-KRBQLMOP.js +0 -41
  330. package/dist/chunk-KRBQLMOP.js.map +0 -7
  331. package/dist/chunk-LXKPNATC.js +0 -624
  332. package/dist/chunk-LXKPNATC.js.map +0 -7
  333. package/dist/chunk-NSBPE2FW.js +0 -17
  334. package/dist/chunk-NSBPE2FW.js.map +0 -7
  335. package/dist/chunk-OK3I555A.js +0 -243
  336. package/dist/chunk-OK3I555A.js.map +0 -7
  337. package/dist/chunk-OKWCKCPE.js +0 -414
  338. package/dist/chunk-OKWCKCPE.js.map +0 -7
  339. package/dist/chunk-OO7JDFS4.js +0 -157
  340. package/dist/chunk-OO7JDFS4.js.map +0 -7
  341. package/dist/chunk-OQBBVTDG.js.map +0 -7
  342. package/dist/chunk-OQSQC7VB.js +0 -77
  343. package/dist/chunk-OQSQC7VB.js.map +0 -7
  344. package/dist/chunk-PED7L5GX.js +0 -92
  345. package/dist/chunk-PED7L5GX.js.map +0 -7
  346. package/dist/chunk-PMI56ED5.js +0 -167
  347. package/dist/chunk-PMI56ED5.js.map +0 -7
  348. package/dist/chunk-QJQS6TUN.js +0 -44
  349. package/dist/chunk-QJQS6TUN.js.map +0 -7
  350. package/dist/chunk-QN34TGD3.js +0 -83
  351. package/dist/chunk-QN34TGD3.js.map +0 -7
  352. package/dist/chunk-QSN77T7C.js +0 -250
  353. package/dist/chunk-QSN77T7C.js.map +0 -7
  354. package/dist/chunk-R56PH7YE.js +0 -78
  355. package/dist/chunk-R56PH7YE.js.map +0 -7
  356. package/dist/chunk-RH7NHVSK.js +0 -16
  357. package/dist/chunk-RH7NHVSK.js.map +0 -7
  358. package/dist/chunk-RMTT4KDY.js +0 -191
  359. package/dist/chunk-RMTT4KDY.js.map +0 -7
  360. package/dist/chunk-RQ2TMLKG.js +0 -142
  361. package/dist/chunk-RQ2TMLKG.js.map +0 -7
  362. package/dist/chunk-SO3T35U7.js +0 -80
  363. package/dist/chunk-SO3T35U7.js.map +0 -7
  364. package/dist/chunk-UKMLICWS.js +0 -51
  365. package/dist/chunk-UKMLICWS.js.map +0 -7
  366. package/dist/chunk-W2YERO7E.js +0 -170
  367. package/dist/chunk-W2YERO7E.js.map +0 -7
  368. package/dist/chunk-W53GKIZQ.js +0 -50
  369. package/dist/chunk-W53GKIZQ.js.map +0 -7
  370. package/dist/chunk-WA4MWYRW.js +0 -254
  371. package/dist/chunk-WA4MWYRW.js.map +0 -7
  372. package/dist/chunk-XC6M4CSW.js +0 -44
  373. package/dist/chunk-XC6M4CSW.js.map +0 -7
  374. package/dist/chunk-XK42ZBDE.js +0 -23
  375. package/dist/chunk-XK42ZBDE.js.map +0 -7
  376. package/dist/chunk-XUV6DDBF.js +0 -124
  377. package/dist/chunk-XUV6DDBF.js.map +0 -7
  378. package/dist/chunk-XZXS2W24.js.map +0 -7
  379. package/dist/chunk-Y3WD5CSW.js +0 -49
  380. package/dist/chunk-Y3WD5CSW.js.map +0 -7
  381. package/dist/chunk-Y4BJXXYV.js +0 -148
  382. package/dist/chunk-Y4BJXXYV.js.map +0 -7
  383. package/dist/chunk-YNIH3KMU.js +0 -121
  384. package/dist/chunk-YNIH3KMU.js.map +0 -7
  385. package/dist/chunk-YOBA3NAM.js +0 -55
  386. package/dist/chunk-YOBA3NAM.js.map +0 -7
  387. package/dist/chunk-ZUJBM6HE.js +0 -125
  388. package/dist/chunk-ZUJBM6HE.js.map +0 -7
  389. package/dist/commands/antigravity/backfill.js.map +0 -7
  390. package/dist/commands/auth/create-key.js.map +0 -7
  391. package/dist/commands/auth/login.js.map +0 -7
  392. package/dist/commands/auth/logout.js.map +0 -7
  393. package/dist/commands/auth/revoke-key.js.map +0 -7
  394. package/dist/commands/auth/signup.js.map +0 -7
  395. package/dist/commands/auth/status.js.map +0 -7
  396. package/dist/commands/catalog/index.js.map +0 -7
  397. package/dist/commands/catalog/recommend.js.map +0 -7
  398. package/dist/commands/convert.js.map +0 -7
  399. package/dist/commands/converters.js.map +0 -7
  400. package/dist/commands/crons/list.js.map +0 -7
  401. package/dist/commands/crons/run.js.map +0 -7
  402. package/dist/commands/dashboard.js.map +0 -7
  403. package/dist/commands/diagnostics.js.map +0 -7
  404. package/dist/commands/eval-targets/create.js.map +0 -7
  405. package/dist/commands/eval-targets/list.js.map +0 -7
  406. package/dist/commands/evals/agent.js.map +0 -7
  407. package/dist/commands/evals/benchmark.js.map +0 -7
  408. package/dist/commands/evals/compare.js.map +0 -7
  409. package/dist/commands/evals/create.js.map +0 -7
  410. package/dist/commands/evals/optimize-description.js.map +0 -7
  411. package/dist/commands/evals/optimize.js.map +0 -7
  412. package/dist/commands/evals/run.js.map +0 -7
  413. package/dist/commands/gateway/ensure.js.map +0 -7
  414. package/dist/commands/hooks/emit-instructions.js.map +0 -7
  415. package/dist/commands/hooks/install.js.map +0 -7
  416. package/dist/commands/hooks/run.js.map +0 -7
  417. package/dist/commands/hooks/uninstall.js.map +0 -7
  418. package/dist/commands/import.js.map +0 -7
  419. package/dist/commands/instructions/create.js.map +0 -7
  420. package/dist/commands/instructions/delete.js.map +0 -7
  421. package/dist/commands/instructions/fork.js.map +0 -7
  422. package/dist/commands/instructions/get.js.map +0 -7
  423. package/dist/commands/instructions/list.js.map +0 -7
  424. package/dist/commands/instructions/promote.js.map +0 -7
  425. package/dist/commands/instructions/pull.js.map +0 -7
  426. package/dist/commands/instructions/upstream.js.map +0 -7
  427. package/dist/commands/instructions/versions.js.map +0 -7
  428. package/dist/commands/launcher.js.map +0 -7
  429. package/dist/commands/org/current.js.map +0 -7
  430. package/dist/commands/org/list.js.map +0 -7
  431. package/dist/commands/org/switch.js.map +0 -7
  432. package/dist/commands/packs/add-instruction.js.map +0 -7
  433. package/dist/commands/packs/apply.js.map +0 -7
  434. package/dist/commands/packs/create.js.map +0 -7
  435. package/dist/commands/packs/fork.js.map +0 -7
  436. package/dist/commands/packs/get.js.map +0 -7
  437. package/dist/commands/packs/list.js.map +0 -7
  438. package/dist/commands/packs/remove-instruction.js.map +0 -7
  439. package/dist/commands/proxy/env.js.map +0 -7
  440. package/dist/commands/proxy/logs.js.map +0 -7
  441. package/dist/commands/proxy/restart.js.map +0 -7
  442. package/dist/commands/proxy/setup.js.map +0 -7
  443. package/dist/commands/proxy/start.js.map +0 -7
  444. package/dist/commands/proxy/status.js.map +0 -7
  445. package/dist/commands/proxy/stop.js.map +0 -7
  446. package/dist/commands/research/backfill.js.map +0 -7
  447. package/dist/commands/research/tail-transcript.js.map +0 -7
  448. package/dist/commands/service/install.js.map +0 -7
  449. package/dist/commands/service/status.js.map +0 -7
  450. package/dist/commands/service/uninstall.js.map +0 -7
  451. package/dist/commands/sessions/analyze.js.map +0 -7
  452. package/dist/commands/sessions/end.js.map +0 -7
  453. package/dist/commands/sessions/import.js.map +0 -7
  454. package/dist/commands/sessions/list.js.map +0 -7
  455. package/dist/commands/sessions/start.js.map +0 -7
  456. package/dist/commands/setup.js.map +0 -7
  457. package/dist/commands/skills/export-approved.js.map +0 -7
  458. package/dist/commands/skills/install.js.map +0 -7
  459. package/dist/commands/skills/list.js.map +0 -7
  460. package/dist/commands/skills/publish.js.map +0 -7
  461. package/dist/commands/skills/search.js.map +0 -7
  462. package/dist/commands/skills/update.js.map +0 -7
  463. package/dist/commands/suggestions/accept.js.map +0 -7
  464. package/dist/commands/suggestions/dismiss.js.map +0 -7
  465. package/dist/commands/suggestions/list.js.map +0 -7
  466. package/dist/commands/suggestions/refresh.js.map +0 -7
  467. package/dist/cursor-BGQJ4CWI.js +0 -134
  468. package/dist/cursor-BGQJ4CWI.js.map +0 -7
  469. package/dist/dashboard/Dashboard.js.map +0 -7
  470. package/dist/dashboard/data.js.map +0 -7
  471. package/dist/dashboard/launcher/ActiveJobsList.js.map +0 -7
  472. package/dist/dashboard/launcher/LauncherOverlay.js.map +0 -7
  473. package/dist/dashboard/launcher/NewLaunchForm.js.map +0 -7
  474. package/dist/dashboard/launcher/api.js.map +0 -7
  475. package/dist/dashboard/launcher/tool-labels.js.map +0 -7
  476. package/dist/dashboard/launcher/types.js.map +0 -7
  477. package/dist/dashboard/launcher/useLaunchJobs.js.map +0 -7
  478. package/dist/dashboard/panels/friction.js.map +0 -7
  479. package/dist/dashboard/panels/insights.js.map +0 -7
  480. package/dist/dashboard/panels/instructions.js.map +0 -7
  481. package/dist/dashboard/panels/outcomes.js.map +0 -7
  482. package/dist/dashboard/panels/overview.js.map +0 -7
  483. package/dist/dashboard/panels/shared.js.map +0 -7
  484. package/dist/dashboard/types.js.map +0 -7
  485. package/dist/dist-UNYP5PJR.js +0 -56
  486. package/dist/dist-UNYP5PJR.js.map +0 -7
  487. package/dist/index.js.map +0 -7
  488. package/dist/lib/active-org-refresh.js.map +0 -7
  489. package/dist/lib/active-org.js.map +0 -7
  490. package/dist/lib/agent-loop.js.map +0 -7
  491. package/dist/lib/antigravity-transcript.js.map +0 -7
  492. package/dist/lib/api-client.js.map +0 -7
  493. package/dist/lib/auth.js.map +0 -7
  494. package/dist/lib/capture-hosts.js.map +0 -7
  495. package/dist/lib/detect-languages.js.map +0 -7
  496. package/dist/lib/detect-tmux.js.map +0 -7
  497. package/dist/lib/diagnostics.js.map +0 -7
  498. package/dist/lib/editor-proxy-pins.js.map +0 -7
  499. package/dist/lib/ensure-api-key.js.map +0 -7
  500. package/dist/lib/eval-analyzer.js.map +0 -7
  501. package/dist/lib/eval-benchmark.js.map +0 -7
  502. package/dist/lib/eval-conversation-handler.js.map +0 -7
  503. package/dist/lib/eval-executor.js.map +0 -7
  504. package/dist/lib/eval-grader.js.map +0 -7
  505. package/dist/lib/eval-meta-judge.js.map +0 -7
  506. package/dist/lib/eval-trigger-tester.js.map +0 -7
  507. package/dist/lib/eval-worktree.js.map +0 -7
  508. package/dist/lib/gateway-entry.js.map +0 -7
  509. package/dist/lib/gateway-identity.js.map +0 -7
  510. package/dist/lib/gateway-lifecycle.js.map +0 -7
  511. package/dist/lib/gateway.js.map +0 -7
  512. package/dist/lib/handlers/cron-refresh-skills.js.map +0 -7
  513. package/dist/lib/handlers/cron-suggest-instructions.js.map +0 -7
  514. package/dist/lib/handlers/process-announcement.js.map +0 -7
  515. package/dist/lib/handlers/process-changelog.js.map +0 -7
  516. package/dist/lib/handlers/process-conversation.js.map +0 -7
  517. package/dist/lib/handlers/process-eval.js.map +0 -7
  518. package/dist/lib/handlers/process-insights.js.map +0 -7
  519. package/dist/lib/handlers/process-launch.js.map +0 -7
  520. package/dist/lib/handlers/process-run-cleanup.js.map +0 -7
  521. package/dist/lib/handlers/process-send-message.js.map +0 -7
  522. package/dist/lib/handlers/process-session-goal.js.map +0 -7
  523. package/dist/lib/hooks-config.js.map +0 -7
  524. package/dist/lib/insights-prompts.js.map +0 -7
  525. package/dist/lib/instruction-snapshot.js.map +0 -7
  526. package/dist/lib/job-helpers.js.map +0 -7
  527. package/dist/lib/llm-client.js.map +0 -7
  528. package/dist/lib/manual-tasks-meta.js.map +0 -7
  529. package/dist/lib/manual-tasks.js.map +0 -7
  530. package/dist/lib/output.js.map +0 -7
  531. package/dist/lib/permanent-job-error.js.map +0 -7
  532. package/dist/lib/pid-identity.js.map +0 -7
  533. package/dist/lib/proxy-respawn.js.map +0 -7
  534. package/dist/lib/research-client.js.map +0 -7
  535. package/dist/lib/setup-steps.js.map +0 -7
  536. package/dist/lib/skills-loader.js.map +0 -7
  537. package/dist/lib/statusline-shim.js.map +0 -7
  538. package/dist/lib/telemetry.js.map +0 -7
  539. package/dist/lib/terminal-target-heartbeat.js.map +0 -7
  540. package/dist/lib/tmux.js.map +0 -7
  541. package/dist/lib/transcript-rate-limit-watcher.js.map +0 -7
  542. package/dist/lib/types.js.map +0 -7
  543. package/dist/lib/version-check.js.map +0 -7
  544. package/dist/lib/which.js.map +0 -7
  545. package/dist/lib/worktree.js.map +0 -7
  546. package/dist/opencode-IQ7X5YMJ.js +0 -190
  547. package/dist/opencode-IQ7X5YMJ.js.map +0 -7
@@ -1,688 +1,48 @@
1
- import {
2
- detectTmux
3
- } from "../../chunk-BO76WKJR.js";
4
- import "../../chunk-KRBQLMOP.js";
5
- import {
6
- BaseCommand
7
- } from "../../chunk-2HK7RGZB.js";
8
- import "../../chunk-R56PH7YE.js";
9
- import {
10
- emitSetupEvent
11
- } from "../../chunk-GQNJO2P2.js";
12
- import {
13
- bootstrapActiveOrg
14
- } from "../../chunk-37LN5O7M.js";
15
- import "../../chunk-EKJ2CABV.js";
16
- import "../../chunk-ZUJBM6HE.js";
17
- import "../../chunk-W2YERO7E.js";
18
- import "../../chunk-NSBPE2FW.js";
19
-
20
- // src/commands/service/install.ts
21
- import { Flags } from "@oclif/core";
22
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
23
- import { execSync, execFileSync, spawnSync } from "node:child_process";
24
- import { homedir, userInfo } from "node:os";
25
- import { dirname, join } from "node:path";
26
- var ALLOWED_ENV_VARS = /* @__PURE__ */ new Set([
27
- "SUPABASE_URL",
28
- "SUPABASE_ANON_KEY",
29
- "SUPABASE_SERVICE_ROLE_KEY",
30
- // Enables local HS256 JWT verification in the API's authMiddleware —
31
- // without it every authed request pays a /auth/v1/user network round-trip
32
- // (measured p50 ~244ms) to Supabase.
33
- "SUPABASE_JWT_SECRET",
34
- "DATABASE_URL",
35
- "RULEMETRIC_API_URL",
36
- "RULEMETRIC_API_KEY",
37
- "RULEMETRIC_ACCESS_TOKEN",
38
- // Recipient for the weekly cron_data_integrity_audit notification.
39
- // Without one of these, the audit cron runs but nobody is notified —
40
- // see cron-data-integrity-audit.ts (defaults: NOTIFY_USER_ID then USER_ID).
41
- "RULEMETRIC_AUDIT_NOTIFY_USER_ID",
42
- "RULEMETRIC_USER_ID",
43
- // cron_refresh_skills needs an authenticated GitHub API budget (5000
44
- // req/hr) — without it the handler skips and the skills registry goes
45
- // stale, which makes cron_suggest_instructions mark every suggestion
46
- // stale on each nightly run.
47
- "GITHUB_TOKEN",
48
- // Pool-tuning overrides so the plist generators (buildPlist / buildWorkerPlist)
49
- // actually honor a user-set value instead of always falling back to the pinned
50
- // default — without these in the allow-list the `envVars.PG_* ?? '<default>'`
51
- // escape hatch was silently dead. Pool-exhaustion RCA 2026-06-21.
52
- "PG_POOL_MAX",
53
- "PG_IDLE_TIMEOUT",
54
- "PG_STATEMENT_TIMEOUT_MS",
55
- // Heavy-read bulkhead size + client-side query deadline — prod sets both
56
- // (fly.toml); without them here a local launchd install can't match prod
57
- // pool math. See packages/db/src/client.ts (getHeavyDb / raceWithDeadline).
58
- "PG_HEAVY_POOL_MAX",
59
- "PG_QUERY_DEADLINE_MS",
60
- // Resend transactional email. The worker (`evals agent`) sends changelog
61
- // announcements via `@rulemetric/email` → `sendEmail()`, which picks the
62
- // provider from `process.env.RESEND_API_KEY`. Without these in the allow-list
63
- // the installer stripped them out of the worker plist, the CLI never loads
64
- // `.env.local`, so the worker fell back to the `noop` provider and SILENTLY
65
- // dropped every announcement email. RESEND_FROM_EMAIL must be the verified
66
- // sender (noreply@rulemetric.com) — otherwise the provider defaults to
67
- // Resend's shared sandbox `onboarding@resend.dev`, which Gmail spam-filters.
68
- "RESEND_API_KEY",
69
- "RESEND_FROM_EMAIL",
70
- // Sentry error capture for the worker process. The worker (`evals agent`)
71
- // calls initSentry(), which now keys off DSN presence alone. Without this in
72
- // the allow-list the installer stripped SENTRY_DSN from the worker plist, so
73
- // worker crashes went unreported even when the DSN was set in .env.local /
74
- // ~/.config/rulemetric/env. The DSN is ingest-only (not a secret).
75
- "SENTRY_DSN"
76
- ]);
77
- var PLIST_LABEL = "com.rulemetric.api";
78
- var PLIST_PATH = join(homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
79
- var WORKER_PLIST_LABEL = "com.rulemetric.worker";
80
- var WORKER_PLIST_PATH = join(homedir(), "Library", "LaunchAgents", `${WORKER_PLIST_LABEL}.plist`);
81
- var GATEWAY_PLIST_LABEL = "com.rulemetric.gateway";
82
- var GATEWAY_PLIST_PATH = join(homedir(), "Library", "LaunchAgents", `${GATEWAY_PLIST_LABEL}.plist`);
83
- var PROXY_PLIST_LABEL = "com.rulemetric.proxy";
84
- var PROXY_PLIST_PATH = join(homedir(), "Library", "LaunchAgents", `${PROXY_PLIST_LABEL}.plist`);
85
- var WORKER_RESTART_PLIST_LABEL = "com.rulemetric.worker.restart";
86
- var WORKER_RESTART_PLIST_PATH = join(homedir(), "Library", "LaunchAgents", `${WORKER_RESTART_PLIST_LABEL}.plist`);
87
- var CONFIG_DIR = join(homedir(), ".config", "rulemetric");
88
- var LOG_DIR = join(CONFIG_DIR, "logs");
89
- var GATEWAY_PORT = 8787;
90
- var PROXY_PORT = 8788;
91
- var WORKER_SYSTEMD_DIR = join(homedir(), ".config", "systemd", "user");
92
- var WORKER_SYSTEMD_UNIT = "rulemetric-worker.service";
93
- var WORKER_SYSTEMD_PATH = join(WORKER_SYSTEMD_DIR, WORKER_SYSTEMD_UNIT);
94
- var ServiceInstall = class _ServiceInstall extends BaseCommand {
95
- static description = "Install RuleMetric services. Default (in a repo checkout): API + worker + gateway + capture proxy as launchd agents. With --worker-only: just the job worker, targeting the globally-installed CLI \u2014 no repo, no build (works from `npm i -g @rulemetric/cli`, macOS launchd or Linux systemd).";
96
- static examples = [
97
- "<%= config.bin %> service install",
98
- "<%= config.bin %> service install --port 3000",
99
- "<%= config.bin %> service install --skip-build",
100
- "<%= config.bin %> service install --no-proxy",
101
- "<%= config.bin %> service install --worker-only"
102
- ];
103
- static flags = {
104
- port: Flags.integer({
105
- char: "p",
106
- default: 3e3,
107
- description: "API server port"
108
- }),
109
- force: Flags.boolean({
110
- char: "f",
111
- default: false,
112
- description: "Overwrite existing service configuration and reclaim conflicting ports"
113
- }),
114
- "skip-build": Flags.boolean({
115
- default: false,
116
- description: "Skip the pre-install workspace build (API/web/cli dist must already exist)"
117
- }),
118
- "no-proxy": Flags.boolean({
119
- default: false,
120
- description: "Skip gateway + mitmproxy plists (just install API + worker)"
121
- }),
122
- "worker-only": Flags.boolean({
123
- default: false,
124
- description: "Install ONLY the job worker as a persistent service, targeting the globally-installed CLI (no repo checkout, no build, no API/gateway/proxy). Sources auth from ~/.config/rulemetric/env. macOS (launchd) + Linux (systemd --user)."
125
- })
126
- };
127
- async run() {
128
- const { flags } = await this.parse(_ServiceInstall);
129
- const port = flags.port;
130
- const skipBuild = flags["skip-build"];
131
- const noProxy = flags["no-proxy"];
132
- if (flags["worker-only"]) {
133
- await this.runWorkerOnly(flags.force);
134
- return;
135
- }
136
- if (process.platform !== "darwin") {
137
- this.error(
138
- "The full service install is macOS-only (launchd). For just the job worker on Linux (or a clean npm install), use: rulemetric service install --worker-only"
139
- );
140
- }
141
- if (existsSync(PLIST_PATH) && !flags.force) {
142
- this.log(`Service already installed at ${PLIST_PATH}`);
143
- this.log("Use --force to overwrite, or run: rulemetric service status");
144
- return;
145
- }
146
- try {
147
- const res = await fetch(`http://localhost:${port}/health`);
148
- if (res.ok && !flags.force) {
149
- this.warn(`Port ${port} is already in use (API may be running via start.sh or in another terminal).`);
150
- this.warn("Stop it first with scripts/stop.sh, or use --force to take over the port.");
151
- return;
152
- }
153
- } catch {
154
- }
155
- const projectRoot = this.findProjectRoot();
156
- if (!projectRoot) {
157
- this.error(
158
- "Could not find RuleMetric project root. Run this command from within the momento-mori repo, or set RULEMETRIC_PROJECT_ROOT."
159
- );
160
- }
161
- const envLocal = join(projectRoot, ".env.local");
162
- if (!existsSync(envLocal)) {
163
- this.error(`.env.local not found at ${envLocal}. The API needs Supabase credentials to start.`);
164
- }
165
- const envVars = this.guardAlwaysOnDatabaseUrl(this.loadEnvVars(projectRoot));
166
- const nodePath = this.findBinary("node");
167
- const pnpmPath = this.findBinary("pnpm");
168
- if (!nodePath || !pnpmPath) {
169
- this.error("Could not find node or pnpm. Ensure they are in your PATH.");
170
- }
171
- let mitmdumpPath = null;
172
- if (!noProxy) {
173
- mitmdumpPath = this.findBinary("mitmdump");
174
- if (!mitmdumpPath) {
175
- this.error(
176
- "mitmdump not found in PATH. Install with: pipx install mitmproxy (or brew install mitmproxy), then re-run.\nOr skip the capture proxy with --no-proxy."
177
- );
178
- }
179
- }
180
- if (!skipBuild) {
181
- this.log("[..] Building workspace artifacts (api, web, cli) via turbo...");
182
- const buildFilters = [
183
- "--filter",
184
- "@rulemetric/api...",
185
- "--filter",
186
- "@rulemetric/web...",
187
- "--filter",
188
- "@rulemetric/cli"
189
- ];
190
- const build = spawnSync(pnpmPath, ["exec", "turbo", "run", "build", ...buildFilters], {
191
- cwd: projectRoot,
192
- stdio: "inherit"
193
- });
194
- if (build.status !== 0) {
195
- this.error(
196
- `Workspace build failed (exit ${build.status}). Fix the build first, or use --skip-build if dist/ already exists.`
197
- );
198
- }
199
- this.log("[OK] Build complete");
200
- } else {
201
- this.log("[..] Skipping pre-install build (--skip-build)");
202
- }
203
- const apiEntry = join(projectRoot, "apps", "api", "dist", "index.js");
204
- if (!existsSync(apiEntry)) {
205
- this.error(`API entry not found at ${apiEntry}. Re-run without --skip-build, or: pnpm --filter @rulemetric/api... build`);
206
- }
207
- const webIndex = join(projectRoot, "apps", "web", "dist", "index.html");
208
- if (!existsSync(webIndex)) {
209
- this.warn(`Web bundle not found at ${webIndex}. Dashboard at :${port} will 404 until you build apps/web.`);
210
- }
211
- if (!noProxy) {
212
- const gatewayEntry = join(projectRoot, "apps", "cli", "dist", "lib", "gateway-entry.js");
213
- if (!existsSync(gatewayEntry)) {
214
- this.error(`Gateway entry not found at ${gatewayEntry}. Re-run without --skip-build, or: pnpm --filter @rulemetric/cli build`);
215
- }
216
- }
217
- if (flags.force) {
218
- this.killStaleProcess(port, null, "API on :" + port);
219
- }
220
- if (!noProxy) {
221
- this.killStaleProcess(GATEWAY_PORT, join(CONFIG_DIR, "gateway.pid"), "gateway");
222
- this.killStaleProcess(PROXY_PORT, join(CONFIG_DIR, "proxy.pid"), "mitmproxy");
223
- }
224
- mkdirSync(join(homedir(), "Library", "LaunchAgents"), { recursive: true });
225
- mkdirSync(LOG_DIR, { recursive: true });
226
- const uid = execSync("id -u", { encoding: "utf-8" }).trim();
227
- const apiPlist = this.buildPlist({ port, projectRoot, nodePath, pnpmPath, envVars });
228
- this.bootoutAndWrite(uid, PLIST_PATH, apiPlist, "API");
229
- this.bootstrapPlist(uid, PLIST_PATH, "API");
230
- this.log(`[..] Waiting for API on :${port}...`);
231
- const apiStarted = await this.waitForApi(port, 15);
232
- if (apiStarted) {
233
- this.log(`[OK] RuleMetric API running on :${port}`);
234
- if (existsSync(webIndex)) {
235
- this.log(`[OK] Dashboard available at http://localhost:${port}`);
236
- }
237
- } else {
238
- this.warn("API did not respond within 15s. Check logs:");
239
- this.log(` tail -f ${LOG_DIR}/api-stdout.log`);
240
- this.log(` tail -f ${LOG_DIR}/api-stderr.log`);
241
- }
242
- this.log("");
243
- this.log("Installing worker service...");
244
- this.killStaleAgents();
245
- const workerPlist = this.buildWorkerPlist({
246
- cliBin: join(projectRoot, "apps", "cli", "bin", "run.js"),
247
- cliDist: join(projectRoot, "apps", "cli", "dist"),
248
- workingDir: projectRoot,
249
- nodePath,
250
- pnpmPath,
251
- envVars
252
- });
253
- this.bootoutAndWrite(uid, WORKER_PLIST_PATH, workerPlist, "Worker");
254
- this.bootstrapPlist(uid, WORKER_PLIST_PATH, "Worker");
255
- if (!noProxy) {
256
- this.log("");
257
- this.log("Installing gateway + capture proxy services...");
258
- const gatewayPlist = this.buildGatewayPlist({ projectRoot, nodePath });
259
- this.bootoutAndWrite(uid, GATEWAY_PLIST_PATH, gatewayPlist, "Gateway");
260
- this.bootstrapPlist(uid, GATEWAY_PLIST_PATH, "Gateway");
261
- const proxyPlist = this.buildProxyPlist({
262
- projectRoot,
263
- mitmdumpPath,
264
- envVars
265
- });
266
- this.bootoutAndWrite(uid, PROXY_PLIST_PATH, proxyPlist, "Proxy");
267
- this.bootstrapPlist(uid, PROXY_PLIST_PATH, "Proxy");
268
- }
269
- if (existsSync(WORKER_RESTART_PLIST_PATH)) {
270
- try {
271
- execFileSync("launchctl", ["bootout", `gui/${uid}`, WORKER_RESTART_PLIST_PATH], { encoding: "utf-8" });
272
- } catch {
273
- }
274
- try {
275
- execFileSync("rm", ["-f", WORKER_RESTART_PLIST_PATH]);
276
- this.log("[OK] Removed stale daily worker-restart agent (no longer needed on agent path)");
277
- } catch {
278
- }
279
- }
280
- this.log("");
281
- if (noProxy) {
282
- this.log("Installed: API + worker. Gateway/proxy skipped (--no-proxy).");
283
- } else {
284
- this.log("Installed: API + worker + gateway + capture proxy.");
285
- }
286
- this.log("All services start at login, restart on crash, and pick up rebuilds via WatchPaths.");
287
- this.log("");
288
- this.log("NOTE: Env vars are baked in at install time. If you change");
289
- this.log(".env.local or credentials, re-run: rulemetric service install --force");
290
- this.log("");
291
- this.log("Manage with:");
292
- this.log(" rulemetric service status \u2014 check if running");
293
- this.log(" rulemetric service uninstall \u2014 remove all services");
294
- await bootstrapActiveOrg();
295
- const tmux = await detectTmux();
296
- this.log("");
297
- if (tmux.available) {
298
- this.log(`[OK] tmux found${tmux.version ? ` (v${tmux.version})` : ""} \u2014 live send enabled`);
299
- } else {
300
- this.log("[!!] tmux not found \u2014 live send will fall back to opening Terminal. Install with: brew install tmux");
301
- }
302
- }
303
- /**
304
- * Worker-only install: a persistent job worker for end users on the
305
- * globally-installed CLI, with NO repo checkout, NO build, and NO
306
- * API/gateway/proxy. macOS → launchd; Linux → systemd --user. Auth is
307
- * sourced from ~/.config/rulemetric/env (written by `rulemetric auth
308
- * login`); the thin-agent worker is HTTP-only (long-polls /api/work/next),
309
- * so it needs only the API URL + a key/token, never DB credentials.
310
- */
311
- async runWorkerOnly(force) {
312
- const platform = process.platform;
313
- if (platform !== "darwin" && platform !== "linux") {
314
- this.error(`--worker-only supports macOS (launchd) and Linux (systemd) only; detected '${platform}'.`);
315
- }
316
- const nodePath = this.findBinary("node");
317
- if (!nodePath) {
318
- this.error("Could not find `node` in PATH.");
319
- }
320
- const cliBin = join(this.config.root, "bin", "run.js");
321
- if (!existsSync(cliBin)) {
322
- this.error(
323
- `Could not locate the installed CLI entry at ${cliBin}. Reinstall the CLI (e.g. npm i -g @rulemetric/cli) and re-run.`
324
- );
325
- }
326
- const cliDist = join(this.config.root, "dist");
327
- const envVars = this.loadGlobalWorkerEnv();
328
- if (!envVars.RULEMETRIC_API_KEY && !envVars.RULEMETRIC_ACCESS_TOKEN) {
329
- this.error(
330
- "Not authenticated \u2014 no RULEMETRIC_API_KEY/RULEMETRIC_ACCESS_TOKEN in ~/.config/rulemetric/env.\nRun `rulemetric auth login` first, then re-run `rulemetric service install --worker-only`."
331
- );
332
- }
333
- if (!envVars.RULEMETRIC_API_URL) {
334
- envVars.RULEMETRIC_API_URL = "https://rulemetric.com";
335
- }
336
- mkdirSync(LOG_DIR, { recursive: true });
337
- this.killStaleAgents();
338
- if (platform === "darwin") {
339
- if (existsSync(WORKER_PLIST_PATH) && !force) {
340
- this.log(`Worker already installed at ${WORKER_PLIST_PATH}.`);
341
- this.log("Use --force to overwrite, or run: rulemetric service status");
342
- return;
343
- }
344
- mkdirSync(join(homedir(), "Library", "LaunchAgents"), { recursive: true });
345
- const uid = execSync("id -u", { encoding: "utf-8" }).trim();
346
- const plist = this.buildWorkerPlist({
347
- cliBin,
348
- cliDist,
349
- workingDir: homedir(),
350
- nodePath,
351
- nodeEnv: "production",
352
- envVars
353
- });
354
- this.bootoutAndWrite(uid, WORKER_PLIST_PATH, plist, "Worker");
355
- this.bootstrapPlist(uid, WORKER_PLIST_PATH, "Worker");
356
- this.log("");
357
- this.log("[OK] Worker installed (launchd). Starts at login, restarts on crash.");
358
- this.log(` Logs: tail -f ${join(LOG_DIR, "worker-stdout.log")}`);
359
- } else {
360
- if (existsSync(WORKER_SYSTEMD_PATH) && !force) {
361
- this.log(`Worker already installed at ${WORKER_SYSTEMD_PATH}.`);
362
- this.log(`Use --force to overwrite, or: systemctl --user status ${WORKER_SYSTEMD_UNIT}`);
363
- return;
364
- }
365
- mkdirSync(WORKER_SYSTEMD_DIR, { recursive: true });
366
- const unit = this.buildWorkerSystemdUnit({ cliBin, nodePath, envVars });
367
- writeFileSync(WORKER_SYSTEMD_PATH, unit, { mode: 384 });
368
- this.log(`[OK] Wrote ${WORKER_SYSTEMD_PATH}`);
369
- try {
370
- execFileSync("systemctl", ["--user", "daemon-reload"]);
371
- execFileSync("systemctl", ["--user", "enable", "--now", WORKER_SYSTEMD_UNIT]);
372
- this.log("[OK] Worker enabled + started (systemctl --user).");
373
- try {
374
- execFileSync("loginctl", ["enable-linger", userInfo().username]);
375
- this.log("[OK] Enabled linger \u2014 worker survives logout/reboot.");
376
- } catch {
377
- this.log("[!!] Could not enable linger (worker will stop on logout).");
378
- this.log(' Run: sudo loginctl enable-linger "$USER"');
379
- }
380
- this.log(` Logs: journalctl --user -u ${WORKER_SYSTEMD_UNIT} -f`);
381
- } catch (err) {
382
- this.warn(
383
- `Wrote the unit but \`systemctl --user\` failed: ${err instanceof Error ? err.message : String(err)}`
384
- );
385
- this.log(
386
- `Enable it manually: systemctl --user daemon-reload && systemctl --user enable --now ${WORKER_SYSTEMD_UNIT}`
387
- );
388
- }
389
- }
390
- this.log("");
391
- this.log("Manage with:");
392
- this.log(" rulemetric service status \u2014 check if running");
393
- this.log(" rulemetric service uninstall \u2014 remove the worker");
394
- await bootstrapActiveOrg();
395
- void emitSetupEvent("worker_started", { mode: "worker-only" }, this.config.version);
396
- }
397
- /**
398
- * Load worker env from ~/.config/rulemetric/env only (no repo .env.local).
399
- * Filtered by ALLOWED_ENV_VARS, same as the full install's loader.
400
- */
401
- loadGlobalWorkerEnv() {
402
- const vars = {};
403
- const globalEnv = join(CONFIG_DIR, "env");
404
- if (existsSync(globalEnv)) {
405
- for (const line of readFileSync(globalEnv, "utf-8").split("\n")) {
406
- const trimmed = line.trim();
407
- if (!trimmed || trimmed.startsWith("#")) continue;
408
- const eqIdx = trimmed.indexOf("=");
409
- if (eqIdx > 0) {
410
- vars[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
411
- }
412
- }
413
- }
414
- return Object.fromEntries(Object.entries(vars).filter(([k]) => ALLOWED_ENV_VARS.has(k)));
415
- }
416
- /** systemd --user unit for the Linux worker-only path. */
417
- buildWorkerSystemdUnit(opts) {
418
- const { cliBin, nodePath, envVars } = opts;
419
- const env = {
420
- ...envVars,
421
- NODE_ENV: "production",
422
- // Mirror the launchd worker's pooler bound (RCA 2026-06-21).
423
- PG_POOL_MAX: envVars.PG_POOL_MAX ?? "3",
424
- PG_IDLE_TIMEOUT: envVars.PG_IDLE_TIMEOUT ?? "10"
425
- };
426
- const envLines = Object.entries(env).map(([k, v]) => `Environment="${k}=${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`).join("\n");
427
- return `[Unit]
1
+ import{a as N}from"../../chunk-6XEC6474.js";import"../../chunk-N7ODX6PO.js";import{a as W}from"../../chunk-LQRYQE6Q.js";import"../../chunk-IZTIYR5Q.js";import{c as M}from"../../chunk-CRAKDQ4H.js";import{b as D}from"../../chunk-WPJ2BND4.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-TIQ7DQ3M.js";import"../../chunk-M6AJDVCL.js";import{a as $}from"../../chunk-ZLLER3HP.js";import{Flags as v}from"@oclif/core";import{existsSync as g,mkdirSync as T,readFileSync as R,writeFileSync as j}from"node:fs";import{execSync as B,execFileSync as h,spawnSync as x}from"node:child_process";import{homedir as y,userInfo as Z}from"node:os";import{dirname as E,join as o}from"node:path";var K=new Set(["SUPABASE_URL","SUPABASE_ANON_KEY","SUPABASE_SERVICE_ROLE_KEY","SUPABASE_JWT_SECRET","DATABASE_URL","RULEMETRIC_API_URL","RULEMETRIC_API_KEY","RULEMETRIC_ACCESS_TOKEN","RULEMETRIC_AUDIT_NOTIFY_USER_ID","RULEMETRIC_USER_ID","GITHUB_TOKEN","PG_POOL_MAX","PG_IDLE_TIMEOUT","PG_STATEMENT_TIMEOUT_MS","PG_HEAVY_POOL_MAX","PG_QUERY_DEADLINE_MS","RESEND_API_KEY","RESEND_FROM_EMAIL","SENTRY_DSN"]),H="com.rulemetric.api",I=o(y(),"Library","LaunchAgents",`${H}.plist`),F="com.rulemetric.worker",b=o(y(),"Library","LaunchAgents",`${F}.plist`),X="com.rulemetric.gateway",G=o(y(),"Library","LaunchAgents",`${X}.plist`),J="com.rulemetric.proxy",Y=o(y(),"Library","LaunchAgents",`${J}.plist`),tt="com.rulemetric.worker.restart",U=o(y(),"Library","LaunchAgents",`${tt}.plist`),w=o(y(),".config","rulemetric"),p=o(w,"logs"),et=8787,V=8788,q=o(y(),".config","systemd","user"),_="rulemetric-worker.service",S=o(q,_),C=class L extends W{static{$(this,"ServiceInstall")}static description="Install RuleMetric services. Default (in a repo checkout): API + worker + gateway + capture proxy as launchd agents. With --worker-only: just the job worker, targeting the globally-installed CLI \u2014 no repo, no build (works from `npm i -g @rulemetric/cli`, macOS launchd or Linux systemd).";static examples=["<%= config.bin %> service install","<%= config.bin %> service install --port 3000","<%= config.bin %> service install --skip-build","<%= config.bin %> service install --no-proxy","<%= config.bin %> service install --worker-only"];static flags={port:v.integer({char:"p",default:3e3,description:"API server port"}),force:v.boolean({char:"f",default:!1,description:"Overwrite existing service configuration and reclaim conflicting ports"}),"skip-build":v.boolean({default:!1,description:"Skip the pre-install workspace build (API/web/cli dist must already exist)"}),"no-proxy":v.boolean({default:!1,description:"Skip gateway + mitmproxy plists (just install API + worker)"}),"worker-only":v.boolean({default:!1,description:"Install ONLY the job worker as a persistent service, targeting the globally-installed CLI (no repo checkout, no build, no API/gateway/proxy). Sources auth from ~/.config/rulemetric/env. macOS (launchd) + Linux (systemd --user)."})};async run(){let{flags:r}=await this.parse(L),t=r.port,e=r["skip-build"],s=r["no-proxy"];if(r["worker-only"]){await this.runWorkerOnly(r.force);return}if(process.platform!=="darwin"&&this.error("The full service install is macOS-only (launchd). For just the job worker on Linux (or a clean npm install), use: rulemetric service install --worker-only"),g(I)&&!r.force){this.log(`Service already installed at ${I}`),this.log("Use --force to overwrite, or run: rulemetric service status");return}try{if((await fetch(`http://localhost:${t}/health`)).ok&&!r.force){this.warn(`Port ${t} is already in use (API may be running via start.sh or in another terminal).`),this.warn("Stop it first with scripts/stop.sh, or use --force to take over the port.");return}}catch{}let i=this.findProjectRoot();i||this.error("Could not find RuleMetric project root. Run this command from within the momento-mori repo, or set RULEMETRIC_PROJECT_ROOT.");let n=o(i,".env.local");g(n)||this.error(`.env.local not found at ${n}. The API needs Supabase credentials to start.`);let a=this.guardAlwaysOnDatabaseUrl(this.loadEnvVars(i)),c=this.findBinary("node"),d=this.findBinary("pnpm");(!c||!d)&&this.error("Could not find node or pnpm. Ensure they are in your PATH.");let u=null;if(s||(u=this.findBinary("mitmdump"),u||this.error(`mitmdump not found in PATH. Install with: pipx install mitmproxy (or brew install mitmproxy), then re-run.
2
+ Or skip the capture proxy with --no-proxy.`)),e)this.log("[..] Skipping pre-install build (--skip-build)");else{this.log("[..] Building workspace artifacts (api, web, cli) via turbo...");let A=x(d,["exec","turbo","run","build",...["--filter","@rulemetric/api...","--filter","@rulemetric/web...","--filter","@rulemetric/cli"]],{cwd:i,stdio:"inherit"});A.status!==0&&this.error(`Workspace build failed (exit ${A.status}). Fix the build first, or use --skip-build if dist/ already exists.`),this.log("[OK] Build complete")}let f=o(i,"apps","api","dist","index.js");g(f)||this.error(`API entry not found at ${f}. Re-run without --skip-build, or: pnpm --filter @rulemetric/api... build`);let k=o(i,"apps","web","dist","index.html");if(g(k)||this.warn(`Web bundle not found at ${k}. Dashboard at :${t} will 404 until you build apps/web.`),!s){let P=o(i,"apps","cli","dist","lib","gateway-entry.js");g(P)||this.error(`Gateway entry not found at ${P}. Re-run without --skip-build, or: pnpm --filter @rulemetric/cli build`)}r.force&&this.killStaleProcess(t,null,"API on :"+t),s||(this.killStaleProcess(et,o(w,"gateway.pid"),"gateway"),this.killStaleProcess(V,o(w,"proxy.pid"),"mitmproxy")),T(o(y(),"Library","LaunchAgents"),{recursive:!0}),T(p,{recursive:!0});let m=B("id -u",{encoding:"utf-8"}).trim(),z=this.buildPlist({port:t,projectRoot:i,nodePath:c,pnpmPath:d,envVars:a});this.bootoutAndWrite(m,I,z,"API"),this.bootstrapPlist(m,I,"API"),this.log(`[..] Waiting for API on :${t}...`),await this.waitForApi(t,15)?(this.log(`[OK] RuleMetric API running on :${t}`),g(k)&&this.log(`[OK] Dashboard available at http://localhost:${t}`)):(this.warn("API did not respond within 15s. Check logs:"),this.log(` tail -f ${p}/api-stdout.log`),this.log(` tail -f ${p}/api-stderr.log`)),this.log(""),this.log("Installing worker service..."),this.killStaleAgents();let Q=this.buildWorkerPlist({cliBin:o(i,"apps","cli","bin","run.js"),cliDist:o(i,"apps","cli","dist"),workingDir:i,nodePath:c,pnpmPath:d,envVars:a});if(this.bootoutAndWrite(m,b,Q,"Worker"),this.bootstrapPlist(m,b,"Worker"),!s){this.log(""),this.log("Installing gateway + capture proxy services...");let P=this.buildGatewayPlist({projectRoot:i,nodePath:c});this.bootoutAndWrite(m,G,P,"Gateway"),this.bootstrapPlist(m,G,"Gateway");let A=this.buildProxyPlist({projectRoot:i,mitmdumpPath:u,envVars:a});this.bootoutAndWrite(m,Y,A,"Proxy"),this.bootstrapPlist(m,Y,"Proxy")}if(g(U)){try{h("launchctl",["bootout",`gui/${m}`,U],{encoding:"utf-8"})}catch{}try{h("rm",["-f",U]),this.log("[OK] Removed stale daily worker-restart agent (no longer needed on agent path)")}catch{}}this.log(""),s?this.log("Installed: API + worker. Gateway/proxy skipped (--no-proxy)."):this.log("Installed: API + worker + gateway + capture proxy."),this.log("All services start at login, restart on crash, and pick up rebuilds via WatchPaths."),this.log(""),this.log("NOTE: Env vars are baked in at install time. If you change"),this.log(".env.local or credentials, re-run: rulemetric service install --force"),this.log(""),this.log("Manage with:"),this.log(" rulemetric service status \u2014 check if running"),this.log(" rulemetric service uninstall \u2014 remove all services"),await D();let O=await N();this.log(""),O.available?this.log(`[OK] tmux found${O.version?` (v${O.version})`:""} \u2014 live send enabled`):this.log("[!!] tmux not found \u2014 live send will fall back to opening Terminal. Install with: brew install tmux")}async runWorkerOnly(r){let t=process.platform;t!=="darwin"&&t!=="linux"&&this.error(`--worker-only supports macOS (launchd) and Linux (systemd) only; detected '${t}'.`);let e=this.findBinary("node");e||this.error("Could not find `node` in PATH.");let s=o(this.config.root,"bin","run.js");g(s)||this.error(`Could not locate the installed CLI entry at ${s}. Reinstall the CLI (e.g. npm i -g @rulemetric/cli) and re-run.`);let i=o(this.config.root,"dist"),n=this.loadGlobalWorkerEnv();if(!n.RULEMETRIC_API_KEY&&!n.RULEMETRIC_ACCESS_TOKEN&&this.error("Not authenticated \u2014 no RULEMETRIC_API_KEY/RULEMETRIC_ACCESS_TOKEN in ~/.config/rulemetric/env.\nRun `rulemetric auth login` first, then re-run `rulemetric service install --worker-only`."),n.RULEMETRIC_API_URL||(n.RULEMETRIC_API_URL="https://rulemetric.com"),T(p,{recursive:!0}),this.killStaleAgents(),t==="darwin"){if(g(b)&&!r){this.log(`Worker already installed at ${b}.`),this.log("Use --force to overwrite, or run: rulemetric service status");return}T(o(y(),"Library","LaunchAgents"),{recursive:!0});let a=B("id -u",{encoding:"utf-8"}).trim(),c=this.buildWorkerPlist({cliBin:s,cliDist:i,workingDir:y(),nodePath:e,nodeEnv:"production",envVars:n});this.bootoutAndWrite(a,b,c,"Worker"),this.bootstrapPlist(a,b,"Worker"),this.log(""),this.log("[OK] Worker installed (launchd). Starts at login, restarts on crash."),this.log(` Logs: tail -f ${o(p,"worker-stdout.log")}`)}else{if(g(S)&&!r){this.log(`Worker already installed at ${S}.`),this.log(`Use --force to overwrite, or: systemctl --user status ${_}`);return}T(q,{recursive:!0});let a=this.buildWorkerSystemdUnit({cliBin:s,nodePath:e,envVars:n});j(S,a,{mode:384}),this.log(`[OK] Wrote ${S}`);try{h("systemctl",["--user","daemon-reload"]),h("systemctl",["--user","enable","--now",_]),this.log("[OK] Worker enabled + started (systemctl --user).");try{h("loginctl",["enable-linger",Z().username]),this.log("[OK] Enabled linger \u2014 worker survives logout/reboot.")}catch{this.log("[!!] Could not enable linger (worker will stop on logout)."),this.log(' Run: sudo loginctl enable-linger "$USER"')}this.log(` Logs: journalctl --user -u ${_} -f`)}catch(c){this.warn(`Wrote the unit but \`systemctl --user\` failed: ${c instanceof Error?c.message:String(c)}`),this.log(`Enable it manually: systemctl --user daemon-reload && systemctl --user enable --now ${_}`)}}this.log(""),this.log("Manage with:"),this.log(" rulemetric service status \u2014 check if running"),this.log(" rulemetric service uninstall \u2014 remove the worker"),await D(),M("worker_started",{mode:"worker-only"},this.config.version)}loadGlobalWorkerEnv(){let r={},t=o(w,"env");if(g(t))for(let e of R(t,"utf-8").split(`
3
+ `)){let s=e.trim();if(!s||s.startsWith("#"))continue;let i=s.indexOf("=");i>0&&(r[s.slice(0,i)]=s.slice(i+1))}return Object.fromEntries(Object.entries(r).filter(([e])=>K.has(e)))}buildWorkerSystemdUnit(r){let{cliBin:t,nodePath:e,envVars:s}=r,i={...s,NODE_ENV:"production",PATH:[...new Set([E(e),o(y(),".local","bin"),"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"])].join(":"),PG_POOL_MAX:s.PG_POOL_MAX??"3",PG_IDLE_TIMEOUT:s.PG_IDLE_TIMEOUT??"10"},n=Object.entries(i).map(([a,c])=>`Environment="${a}=${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`).join(`
4
+ `);return`[Unit]
428
5
  Description=RuleMetric job worker (evals agent)
429
6
  After=network-online.target
430
7
  Wants=network-online.target
431
8
 
432
9
  [Service]
433
10
  Type=simple
434
- ExecStart=${nodePath} ${cliBin} evals agent
11
+ ExecStart=${e} ${t} evals agent
435
12
  Restart=on-failure
436
13
  RestartSec=15
437
- ${envLines}
14
+ ${n}
438
15
 
439
16
  [Install]
440
17
  WantedBy=default.target
441
- `;
442
- }
443
- findProjectRoot() {
444
- if (process.env.RULEMETRIC_PROJECT_ROOT) {
445
- return process.env.RULEMETRIC_PROJECT_ROOT;
446
- }
447
- let dir = process.cwd();
448
- for (let i = 0; i < 10; i++) {
449
- if (existsSync(join(dir, "apps", "api", "package.json"))) {
450
- return dir;
451
- }
452
- const parent = join(dir, "..");
453
- if (parent === dir) break;
454
- dir = parent;
455
- }
456
- return null;
457
- }
458
- findBinary(name) {
459
- try {
460
- return execFileSync("which", [name], { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).trim() || null;
461
- } catch {
462
- return null;
463
- }
464
- }
465
- loadEnvVars(projectRoot) {
466
- const vars = {};
467
- const envLocal = join(projectRoot, ".env.local");
468
- if (existsSync(envLocal)) {
469
- for (const line of readFileSync(envLocal, "utf-8").split("\n")) {
470
- const trimmed = line.trim();
471
- if (!trimmed || trimmed.startsWith("#")) continue;
472
- const eqIdx = trimmed.indexOf("=");
473
- if (eqIdx > 0) {
474
- vars[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
475
- }
476
- }
477
- }
478
- const globalEnv = join(CONFIG_DIR, "env");
479
- if (existsSync(globalEnv)) {
480
- for (const line of readFileSync(globalEnv, "utf-8").split("\n")) {
481
- const trimmed = line.trim();
482
- if (!trimmed || trimmed.startsWith("#")) continue;
483
- const eqIdx = trimmed.indexOf("=");
484
- if (eqIdx > 0) {
485
- vars[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
486
- }
487
- }
488
- }
489
- return Object.fromEntries(
490
- Object.entries(vars).filter(([k]) => ALLOWED_ENV_VARS.has(k))
491
- );
492
- }
493
- // Guard: the always-on API + worker MUST use the TRANSACTION-mode pooler
494
- // (port 6543). A SESSION-mode URL (:5432, 15-slot cap) baked into these
495
- // services was the trigger of the recurring pool saturation — a pool-cascade
496
- // debugging override leaked into the plists through this very installer. Auto-
497
- // correct the obvious session→transaction port and warn loudly; warn (but do
498
- // not block) on a direct, non-pooler URL. Pool-exhaustion RCA 2026-06-21.
499
- guardAlwaysOnDatabaseUrl(envVars) {
500
- const url = envVars.DATABASE_URL;
501
- if (!url) return envVars;
502
- if (url.includes("pooler.supabase.com:5432")) {
503
- this.warn(
504
- "DATABASE_URL points at the SESSION-mode pooler (:5432, 15-slot cap). The always-on API/worker must use TRANSACTION mode (:6543) \u2014 auto-correcting for the installed services. Fix .env.local to silence this warning."
505
- );
506
- return { ...envVars, DATABASE_URL: url.replace("pooler.supabase.com:5432", "pooler.supabase.com:6543") };
507
- }
508
- if (/@db\.[a-z0-9]+\.supabase\.co[:/]/.test(url)) {
509
- this.warn(
510
- "DATABASE_URL is a DIRECT database connection (db.<ref>.supabase.co), not the pooler. Always-on services should use the transaction pooler (aws-*.pooler.supabase.com:6543) to avoid exhausting Postgres connections."
511
- );
512
- }
513
- return envVars;
514
- }
515
- // Reap orphaned, unsupervised `evals agent` worker processes before
516
- // (re)bootstrapping the launchd worker. The worker holds no listening port,
517
- // so killStaleProcess (port/pidfile based) cannot find detached agents — a
518
- // fleet of 4 ran 3+ days and helped saturate the pool (RCA 2026-06-21). pgrep
519
- // the command line and SIGTERM every match except ourselves; the agent's own
520
- // single-instance lock then keeps a fresh fleet from forming.
521
- killStaleAgents() {
522
- try {
523
- const out = execFileSync("pgrep", ["-f", "bin/run.js evals agent"], {
524
- encoding: "utf-8",
525
- stdio: ["ignore", "pipe", "ignore"]
526
- });
527
- const pids = out.trim().split("\n").filter(Boolean).map((s) => parseInt(s, 10)).filter((p) => !isNaN(p) && p !== process.pid);
528
- for (const pid of pids) {
529
- try {
530
- process.kill(pid, "SIGTERM");
531
- this.log(`[OK] Reaped orphan evals agent (PID ${pid})`);
532
- } catch {
533
- }
534
- }
535
- if (pids.length) spawnSync("sleep", ["1"], { stdio: "ignore" });
536
- } catch {
537
- }
538
- }
539
- // Best-effort cleanup of a process that would conflict with an
540
- // about-to-bootstrap launchd plist. Tries two routes:
541
- // (a) the PID file written by the legacy spawn path
542
- // (gateway-lifecycle / proxy start), if pidFile is non-null
543
- // (b) anything actively listening on the expected port
544
- // Either way: SIGTERM + small grace + SIGKILL fallback. Stale PID file
545
- // gets unlinked.
546
- killStaleProcess(port, pidFile, name) {
547
- let killedAny = false;
548
- if (pidFile && existsSync(pidFile)) {
549
- try {
550
- const pidStr = readFileSync(pidFile, "utf-8").trim();
551
- const pid = parseInt(pidStr, 10);
552
- if (!isNaN(pid)) {
553
- try {
554
- process.kill(pid, "SIGTERM");
555
- killedAny = true;
556
- this.log(`[OK] Stopped existing ${name} (PID ${pid} from ${pidFile})`);
557
- } catch {
558
- }
559
- }
560
- } catch {
561
- }
562
- try {
563
- execFileSync("rm", ["-f", pidFile]);
564
- } catch {
565
- }
566
- }
567
- try {
568
- const result = execFileSync("lsof", ["-ti", `:${port}`, "-sTCP:LISTEN"], {
569
- encoding: "utf-8",
570
- stdio: ["ignore", "pipe", "ignore"]
571
- });
572
- const pids = result.trim().split("\n").filter(Boolean);
573
- for (const pidStr of pids) {
574
- const pid = parseInt(pidStr, 10);
575
- if (!isNaN(pid)) {
576
- try {
577
- process.kill(pid, "SIGTERM");
578
- killedAny = true;
579
- this.log(`[OK] Stopped orphan on :${port} (PID ${pid})`);
580
- } catch {
581
- }
582
- }
583
- }
584
- } catch {
585
- }
586
- if (killedAny) {
587
- spawnSync("sleep", ["1"], { stdio: "ignore" });
588
- }
589
- }
590
- bootoutAndWrite(uid, plistPath, content, name) {
591
- const benignBootoutPatterns = [
592
- "Could not find specified service",
593
- "No such process",
594
- "3: No such process",
595
- "5: Input/output error"
596
- ];
597
- try {
598
- execFileSync("launchctl", ["bootout", `gui/${uid}`, plistPath], {
599
- encoding: "utf-8",
600
- // Capture stderr instead of letting it print to the user's terminal.
601
- // The plist was either already-loaded (we unload it cleanly) or not
602
- // loaded (we want to swallow the error) — the user shouldn't see
603
- // launchctl's raw output either way.
604
- stdio: ["ignore", "pipe", "pipe"]
605
- });
606
- this.log(`[OK] Unloaded existing ${name} service`);
607
- } catch (err) {
608
- const msg = err.message || "";
609
- const stderr = (err.stderr ?? "").toString();
610
- const combined = `${msg}
611
- ${stderr}`;
612
- if (!benignBootoutPatterns.some((p) => combined.includes(p))) {
613
- this.warn(`Could not unload existing ${name} service: ${msg.trim()}`);
614
- }
615
- }
616
- writeFileSync(plistPath, content, { mode: 384 });
617
- this.log(`[OK] ${name} plist written to ${plistPath}`);
618
- }
619
- bootstrapPlist(uid, plistPath, name) {
620
- try {
621
- execFileSync("launchctl", ["bootstrap", `gui/${uid}`, plistPath]);
622
- this.log(`[OK] ${name} service loaded into launchd`);
623
- } catch (bootstrapErr) {
624
- try {
625
- execFileSync("launchctl", ["load", plistPath]);
626
- this.log(`[OK] ${name} service loaded into launchd (legacy)`);
627
- } catch (loadErr) {
628
- this.warn(
629
- `Could not load ${name} service.
630
- bootstrap: ${bootstrapErr.message.trim()}
631
- load: ${loadErr.message.trim()}`
632
- );
633
- }
634
- }
635
- }
636
- buildPlist(opts) {
637
- const { port, projectRoot, nodePath, pnpmPath, envVars } = opts;
638
- const pathDirs = [.../* @__PURE__ */ new Set([dirname(nodePath), dirname(pnpmPath), "/usr/local/bin", "/usr/bin", "/bin"])];
639
- const envEntries = Object.entries({
640
- ...envVars,
641
- PORT: String(port),
642
- NODE_ENV: "production",
643
- PATH: pathDirs.join(":"),
644
- // Pool resilience for the always-on API (NOT the worker, which runs
645
- // legitimately long analytics queries). A wedged Supavisor socket with
646
- // the default max=3 pool and no query timeout hangs every authenticated
647
- // request — the 2026-06-09 login-hang. statement_timeout lets Postgres
648
- // cancel a stuck query so the connection returns to the pool (verified
649
- // honored through the transaction pooler); the larger pool adds headroom.
650
- // Both env-overridable. See packages/db/src/client.ts.
651
- PG_POOL_MAX: envVars.PG_POOL_MAX ?? "10",
652
- PG_STATEMENT_TIMEOUT_MS: envVars.PG_STATEMENT_TIMEOUT_MS ?? "10000",
653
- // Keep the pool warm so the API stops reconnecting (and re-resolving the
654
- // rotating pooler ELB) on nearly every request — the churn that exposed
655
- // it to intermittent CONNECT_TIMEOUT/ENOTFOUND. Worker/tests keep the
656
- // conservative 5s default. See packages/db/src/client.ts (2026-06-09).
657
- PG_IDLE_TIMEOUT: envVars.PG_IDLE_TIMEOUT ?? "30",
658
- // Silence per-span stdout dumps on the local API — it has no OTLP
659
- // endpoint and a fixed (now rotated) log file; the ConsoleSpanExporter
660
- // grew api-stdout to 370MB / ~400k spans. Fly leaves this unset so its
661
- // console spans stay grep-able in the managed log stream.
662
- OTEL_SPAN_EXPORT: envVars.OTEL_SPAN_EXPORT ?? "none"
663
- }).map(([k, v]) => ` <key>${escapeXml(k)}</key>
664
- <string>${escapeXml(v)}</string>`).join("\n");
665
- const apiEntry = join(projectRoot, "apps", "api", "dist", "index.js");
666
- const apiDist = join(projectRoot, "apps", "api", "dist");
667
- return `<?xml version="1.0" encoding="UTF-8"?>
18
+ `}findProjectRoot(){if(process.env.RULEMETRIC_PROJECT_ROOT)return process.env.RULEMETRIC_PROJECT_ROOT;let r=process.cwd();for(let t=0;t<10;t++){if(g(o(r,"apps","api","package.json")))return r;let e=o(r,"..");if(e===r)break;r=e}return null}findBinary(r){try{return h("which",[r],{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim()||null}catch{return null}}loadEnvVars(r){let t={},e=o(r,".env.local");if(g(e))for(let i of R(e,"utf-8").split(`
19
+ `)){let n=i.trim();if(!n||n.startsWith("#"))continue;let a=n.indexOf("=");a>0&&(t[n.slice(0,a)]=n.slice(a+1))}let s=o(w,"env");if(g(s))for(let i of R(s,"utf-8").split(`
20
+ `)){let n=i.trim();if(!n||n.startsWith("#"))continue;let a=n.indexOf("=");a>0&&(t[n.slice(0,a)]=n.slice(a+1))}return Object.fromEntries(Object.entries(t).filter(([i])=>K.has(i)))}guardAlwaysOnDatabaseUrl(r){let t=r.DATABASE_URL;return t?t.includes("pooler.supabase.com:5432")?(this.warn("DATABASE_URL points at the SESSION-mode pooler (:5432, 15-slot cap). The always-on API/worker must use TRANSACTION mode (:6543) \u2014 auto-correcting for the installed services. Fix .env.local to silence this warning."),{...r,DATABASE_URL:t.replace("pooler.supabase.com:5432","pooler.supabase.com:6543")}):(/@db\.[a-z0-9]+\.supabase\.co[:/]/.test(t)&&this.warn("DATABASE_URL is a DIRECT database connection (db.<ref>.supabase.co), not the pooler. Always-on services should use the transaction pooler (aws-*.pooler.supabase.com:6543) to avoid exhausting Postgres connections."),r):r}killStaleAgents(){try{let t=h("pgrep",["-f","bin/run.js evals agent"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim().split(`
21
+ `).filter(Boolean).map(e=>parseInt(e,10)).filter(e=>!isNaN(e)&&e!==process.pid);for(let e of t)try{process.kill(e,"SIGTERM"),this.log(`[OK] Reaped orphan evals agent (PID ${e})`)}catch{}t.length&&x("sleep",["1"],{stdio:"ignore"})}catch{}}killStaleProcess(r,t,e){let s=!1;if(t&&g(t)){try{let i=R(t,"utf-8").trim(),n=parseInt(i,10);if(!isNaN(n))try{process.kill(n,"SIGTERM"),s=!0,this.log(`[OK] Stopped existing ${e} (PID ${n} from ${t})`)}catch{}}catch{}try{h("rm",["-f",t])}catch{}}try{let n=h("lsof",["-ti",`:${r}`,"-sTCP:LISTEN"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim().split(`
22
+ `).filter(Boolean);for(let a of n){let c=parseInt(a,10);if(!isNaN(c))try{process.kill(c,"SIGTERM"),s=!0,this.log(`[OK] Stopped orphan on :${r} (PID ${c})`)}catch{}}}catch{}s&&x("sleep",["1"],{stdio:"ignore"})}bootoutAndWrite(r,t,e,s){let i=["Could not find specified service","No such process","3: No such process","5: Input/output error"];try{h("launchctl",["bootout",`gui/${r}`,t],{encoding:"utf-8",stdio:["ignore","pipe","pipe"]}),this.log(`[OK] Unloaded existing ${s} service`)}catch(n){let a=n.message||"",c=(n.stderr??"").toString(),d=`${a}
23
+ ${c}`;i.some(u=>d.includes(u))||this.warn(`Could not unload existing ${s} service: ${a.trim()}`)}j(t,e,{mode:384}),this.log(`[OK] ${s} plist written to ${t}`)}bootstrapPlist(r,t,e){try{h("launchctl",["bootstrap",`gui/${r}`,t]),this.log(`[OK] ${e} service loaded into launchd`)}catch(s){try{h("launchctl",["load",t]),this.log(`[OK] ${e} service loaded into launchd (legacy)`)}catch(i){this.warn(`Could not load ${e} service.
24
+ bootstrap: ${s.message.trim()}
25
+ load: ${i.message.trim()}`)}}}buildPlist(r){let{port:t,projectRoot:e,nodePath:s,pnpmPath:i,envVars:n}=r,a=[...new Set([E(s),E(i),"/usr/local/bin","/usr/bin","/bin"])],c=Object.entries({...n,PORT:String(t),NODE_ENV:"production",PATH:a.join(":"),PG_POOL_MAX:n.PG_POOL_MAX??"10",PG_STATEMENT_TIMEOUT_MS:n.PG_STATEMENT_TIMEOUT_MS??"10000",PG_IDLE_TIMEOUT:n.PG_IDLE_TIMEOUT??"30",OTEL_SPAN_EXPORT:n.OTEL_SPAN_EXPORT??"none"}).map(([f,k])=>` <key>${l(f)}</key>
26
+ <string>${l(k)}</string>`).join(`
27
+ `),d=o(e,"apps","api","dist","index.js"),u=o(e,"apps","api","dist");return`<?xml version="1.0" encoding="UTF-8"?>
668
28
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
669
29
  <plist version="1.0">
670
30
  <dict>
671
31
  <key>Label</key>
672
- <string>${PLIST_LABEL}</string>
32
+ <string>${H}</string>
673
33
 
674
34
  <key>ProgramArguments</key>
675
35
  <array>
676
- <string>${escapeXml(nodePath)}</string>
677
- <string>${escapeXml(apiEntry)}</string>
36
+ <string>${l(s)}</string>
37
+ <string>${l(d)}</string>
678
38
  </array>
679
39
 
680
40
  <key>WorkingDirectory</key>
681
- <string>${escapeXml(projectRoot)}</string>
41
+ <string>${l(e)}</string>
682
42
 
683
43
  <key>EnvironmentVariables</key>
684
44
  <dict>
685
- ${envEntries}
45
+ ${c}
686
46
  </dict>
687
47
 
688
48
  <key>RunAtLoad</key>
@@ -699,65 +59,42 @@ ${envEntries}
699
59
 
700
60
  <key>WatchPaths</key>
701
61
  <array>
702
- <string>${escapeXml(apiDist)}</string>
62
+ <string>${l(u)}</string>
703
63
  </array>
704
64
 
705
65
  <key>StandardOutPath</key>
706
- <string>${escapeXml(join(LOG_DIR, "api-stdout.log"))}</string>
66
+ <string>${l(o(p,"api-stdout.log"))}</string>
707
67
 
708
68
  <key>StandardErrorPath</key>
709
- <string>${escapeXml(join(LOG_DIR, "api-stderr.log"))}</string>
69
+ <string>${l(o(p,"api-stderr.log"))}</string>
710
70
 
711
71
  <key>ProcessType</key>
712
72
  <string>Background</string>
713
73
  </dict>
714
74
  </plist>
715
- `;
716
- }
717
- buildWorkerPlist(opts) {
718
- const { cliBin, cliDist, workingDir, nodePath, pnpmPath, envVars } = opts;
719
- const nodeEnv = opts.nodeEnv ?? "development";
720
- const pathDirs = [
721
- ...new Set(
722
- [dirname(nodePath), pnpmPath ? dirname(pnpmPath) : null, "/usr/local/bin", "/usr/bin", "/bin"].filter(
723
- (d) => Boolean(d)
724
- )
725
- )
726
- ];
727
- const envEntries = Object.entries({
728
- ...envVars,
729
- NODE_ENV: nodeEnv,
730
- PATH: pathDirs.join(":"),
731
- // Bound the worker's pooler footprint. The worker is mostly idle (HTTP
732
- // long-poll); an UNPINNED pool plus the previously-missing single-instance
733
- // guard let an orphaned fleet of agents each hold a pool and saturate
734
- // Supavisor's 200-client cap. A small pool + short idle timeout releases
735
- // sessions promptly. Pool-exhaustion RCA 2026-06-21.
736
- PG_POOL_MAX: envVars.PG_POOL_MAX ?? "3",
737
- PG_IDLE_TIMEOUT: envVars.PG_IDLE_TIMEOUT ?? "10"
738
- }).map(([k, v]) => ` <key>${escapeXml(k)}</key>
739
- <string>${escapeXml(v)}</string>`).join("\n");
740
- return `<?xml version="1.0" encoding="UTF-8"?>
75
+ `}buildWorkerPlist(r){let{cliBin:t,cliDist:e,workingDir:s,nodePath:i,pnpmPath:n,envVars:a}=r,c=r.nodeEnv??"development",d=[...new Set([E(i),n?E(n):null,o(y(),".local","bin"),"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"].filter(f=>!!f))],u=Object.entries({...a,NODE_ENV:c,PATH:d.join(":"),PG_POOL_MAX:a.PG_POOL_MAX??"3",PG_IDLE_TIMEOUT:a.PG_IDLE_TIMEOUT??"10"}).map(([f,k])=>` <key>${l(f)}</key>
76
+ <string>${l(k)}</string>`).join(`
77
+ `);return`<?xml version="1.0" encoding="UTF-8"?>
741
78
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
742
79
  <plist version="1.0">
743
80
  <dict>
744
81
  <key>Label</key>
745
- <string>${WORKER_PLIST_LABEL}</string>
82
+ <string>${F}</string>
746
83
 
747
84
  <key>ProgramArguments</key>
748
85
  <array>
749
- <string>${escapeXml(nodePath)}</string>
750
- <string>${escapeXml(cliBin)}</string>
86
+ <string>${l(i)}</string>
87
+ <string>${l(t)}</string>
751
88
  <string>evals</string>
752
89
  <string>agent</string>
753
90
  </array>
754
91
 
755
92
  <key>WorkingDirectory</key>
756
- <string>${escapeXml(workingDir)}</string>
93
+ <string>${l(s)}</string>
757
94
 
758
95
  <key>EnvironmentVariables</key>
759
96
  <dict>
760
- ${envEntries}
97
+ ${u}
761
98
  </dict>
762
99
 
763
100
  <key>RunAtLoad</key>
@@ -774,58 +111,40 @@ ${envEntries}
774
111
 
775
112
  <key>WatchPaths</key>
776
113
  <array>
777
- <string>${escapeXml(cliDist)}</string>
114
+ <string>${l(e)}</string>
778
115
  </array>
779
116
 
780
117
  <key>StandardOutPath</key>
781
- <string>${escapeXml(join(LOG_DIR, "worker-stdout.log"))}</string>
118
+ <string>${l(o(p,"worker-stdout.log"))}</string>
782
119
 
783
120
  <key>StandardErrorPath</key>
784
- <string>${escapeXml(join(LOG_DIR, "worker-stderr.log"))}</string>
121
+ <string>${l(o(p,"worker-stderr.log"))}</string>
785
122
 
786
123
  <key>ProcessType</key>
787
124
  <string>Background</string>
788
125
  </dict>
789
126
  </plist>
790
- `;
791
- }
792
- // CONNECT-proxy router that fronts mitmproxy on :8787. Always-on so
793
- // .claude/settings.json's HTTPS_PROXY pointer never resolves to a dead
794
- // socket (which would break Claude Code entirely — see CLAUDE.md).
795
- // NOT watched on rebuild: bouncing the gateway mid-request would drop
796
- // in-flight streaming responses. Gateway code changes rarely; on
797
- // upgrade, the user can `launchctl kickstart gui/<uid>/com.rulemetric.gateway`.
798
- buildGatewayPlist(opts) {
799
- const { projectRoot, nodePath } = opts;
800
- const gatewayEntry = join(projectRoot, "apps", "cli", "dist", "lib", "gateway-entry.js");
801
- const cliBin = join(projectRoot, "apps", "cli", "bin", "run.js");
802
- const pathDirs = [.../* @__PURE__ */ new Set([dirname(nodePath), "/usr/local/bin", "/usr/bin", "/bin"])];
803
- const env = {
804
- RULEMETRIC_CLI_VERSION: this.config.version,
805
- RULEMETRIC_CLI_ENTRY: cliBin,
806
- PATH: pathDirs.join(":")
807
- };
808
- const envEntries = Object.entries(env).map(([k, v]) => ` <key>${escapeXml(k)}</key>
809
- <string>${escapeXml(v)}</string>`).join("\n");
810
- return `<?xml version="1.0" encoding="UTF-8"?>
127
+ `}buildGatewayPlist(r){let{projectRoot:t,nodePath:e}=r,s=o(t,"apps","cli","dist","lib","gateway-entry.js"),i=o(t,"apps","cli","bin","run.js"),n=[...new Set([E(e),"/usr/local/bin","/usr/bin","/bin"])],a={RULEMETRIC_CLI_VERSION:this.config.version,RULEMETRIC_CLI_ENTRY:i,PATH:n.join(":")},c=Object.entries(a).map(([d,u])=>` <key>${l(d)}</key>
128
+ <string>${l(u)}</string>`).join(`
129
+ `);return`<?xml version="1.0" encoding="UTF-8"?>
811
130
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
812
131
  <plist version="1.0">
813
132
  <dict>
814
133
  <key>Label</key>
815
- <string>${GATEWAY_PLIST_LABEL}</string>
134
+ <string>${X}</string>
816
135
 
817
136
  <key>ProgramArguments</key>
818
137
  <array>
819
- <string>${escapeXml(nodePath)}</string>
820
- <string>${escapeXml(gatewayEntry)}</string>
138
+ <string>${l(e)}</string>
139
+ <string>${l(s)}</string>
821
140
  </array>
822
141
 
823
142
  <key>WorkingDirectory</key>
824
- <string>${escapeXml(projectRoot)}</string>
143
+ <string>${l(t)}</string>
825
144
 
826
145
  <key>EnvironmentVariables</key>
827
146
  <dict>
828
- ${envEntries}
147
+ ${c}
829
148
  </dict>
830
149
 
831
150
  <key>RunAtLoad</key>
@@ -841,58 +160,41 @@ ${envEntries}
841
160
  <integer>10</integer>
842
161
 
843
162
  <key>StandardOutPath</key>
844
- <string>${escapeXml(join(LOG_DIR, "gateway-stdout.log"))}</string>
163
+ <string>${l(o(p,"gateway-stdout.log"))}</string>
845
164
 
846
165
  <key>StandardErrorPath</key>
847
- <string>${escapeXml(join(LOG_DIR, "gateway-stderr.log"))}</string>
166
+ <string>${l(o(p,"gateway-stderr.log"))}</string>
848
167
 
849
168
  <key>ProcessType</key>
850
169
  <string>Background</string>
851
170
  </dict>
852
171
  </plist>
853
- `;
854
- }
855
- // mitmproxy with the RuleMetric capture addon. Same invocation as
856
- // `rulemetric proxy start` (see commands/proxy/start.ts:308) so the
857
- // launchd path and the CLI path are interchangeable. We don't WatchPath
858
- // the Python addon — mitmdump has its own addon reload that handles
859
- // edits without a full process restart.
860
- buildProxyPlist(opts) {
861
- const { projectRoot, mitmdumpPath, envVars } = opts;
862
- const addonPath = join(projectRoot, "packages", "proxy", "addon", "rulemetric_addon.py");
863
- const pathDirs = [.../* @__PURE__ */ new Set([dirname(mitmdumpPath), "/usr/local/bin", "/usr/bin", "/bin"])];
864
- const env = {
865
- ...envVars,
866
- RULEMETRIC_PROJECT_PATH: projectRoot,
867
- RULEMETRIC_CLI_VERSION: this.config.version,
868
- PATH: pathDirs.join(":")
869
- };
870
- const envEntries = Object.entries(env).map(([k, v]) => ` <key>${escapeXml(k)}</key>
871
- <string>${escapeXml(v)}</string>`).join("\n");
872
- return `<?xml version="1.0" encoding="UTF-8"?>
172
+ `}buildProxyPlist(r){let{projectRoot:t,mitmdumpPath:e,envVars:s}=r,i=o(t,"packages","proxy","addon","rulemetric_addon.py"),n=[...new Set([E(e),"/usr/local/bin","/usr/bin","/bin"])],a={...s,RULEMETRIC_PROJECT_PATH:t,RULEMETRIC_CLI_VERSION:this.config.version,PATH:n.join(":")},c=Object.entries(a).map(([d,u])=>` <key>${l(d)}</key>
173
+ <string>${l(u)}</string>`).join(`
174
+ `);return`<?xml version="1.0" encoding="UTF-8"?>
873
175
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
874
176
  <plist version="1.0">
875
177
  <dict>
876
178
  <key>Label</key>
877
- <string>${PROXY_PLIST_LABEL}</string>
179
+ <string>${J}</string>
878
180
 
879
181
  <key>ProgramArguments</key>
880
182
  <array>
881
- <string>${escapeXml(mitmdumpPath)}</string>
183
+ <string>${l(e)}</string>
882
184
  <string>--listen-port</string>
883
- <string>${PROXY_PORT}</string>
185
+ <string>${V}</string>
884
186
  <string>-s</string>
885
- <string>${escapeXml(addonPath)}</string>
187
+ <string>${l(i)}</string>
886
188
  <string>--set</string>
887
189
  <string>console_eventlog_verbosity=info</string>
888
190
  </array>
889
191
 
890
192
  <key>WorkingDirectory</key>
891
- <string>${escapeXml(projectRoot)}</string>
193
+ <string>${l(t)}</string>
892
194
 
893
195
  <key>EnvironmentVariables</key>
894
196
  <dict>
895
- ${envEntries}
197
+ ${c}
896
198
  </dict>
897
199
 
898
200
  <key>RunAtLoad</key>
@@ -908,39 +210,13 @@ ${envEntries}
908
210
  <integer>15</integer>
909
211
 
910
212
  <key>StandardOutPath</key>
911
- <string>${escapeXml(join(LOG_DIR, "proxy-stdout.log"))}</string>
213
+ <string>${l(o(p,"proxy-stdout.log"))}</string>
912
214
 
913
215
  <key>StandardErrorPath</key>
914
- <string>${escapeXml(join(LOG_DIR, "proxy-stderr.log"))}</string>
216
+ <string>${l(o(p,"proxy-stderr.log"))}</string>
915
217
 
916
218
  <key>ProcessType</key>
917
219
  <string>Background</string>
918
220
  </dict>
919
221
  </plist>
920
- `;
921
- }
922
- async waitForApi(port, timeoutSecs) {
923
- let lastError = null;
924
- for (let i = 0; i < timeoutSecs; i++) {
925
- try {
926
- const res = await fetch(`http://localhost:${port}/health`);
927
- if (res.ok) return true;
928
- lastError = `health check returned ${res.status}`;
929
- } catch (err) {
930
- lastError = err.message;
931
- }
932
- await new Promise((r) => setTimeout(r, 1e3));
933
- }
934
- if (lastError) {
935
- this.warn(`Last health check error: ${lastError}`);
936
- }
937
- return false;
938
- }
939
- };
940
- function escapeXml(s) {
941
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
942
- }
943
- export {
944
- ServiceInstall as default
945
- };
946
- //# sourceMappingURL=install.js.map
222
+ `}async waitForApi(r,t){let e=null;for(let s=0;s<t;s++){try{let i=await fetch(`http://localhost:${r}/health`);if(i.ok)return!0;e=`health check returned ${i.status}`}catch(i){e=i.message}await new Promise(i=>setTimeout(i,1e3))}return e&&this.warn(`Last health check error: ${e}`),!1}};function l(L){return L.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}$(l,"escapeXml");export{C as default};