@rulemetric/cli 0.7.3 → 0.7.5

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 (550) hide show
  1. package/README.md +10 -8
  2. package/dist/base-command.js +1 -14
  3. package/dist/chunk-2JRDG4LJ.js +31 -0
  4. package/dist/chunk-2TC6WCUT.js +34 -0
  5. package/dist/chunk-2WLVDSAP.js +2 -0
  6. package/dist/chunk-32EEBARV.js +1 -0
  7. package/dist/chunk-3AV3GTMP.js +1 -0
  8. package/dist/chunk-43YBXX7R.js +1 -0
  9. package/dist/chunk-4Z5ECCJE.js +1 -0
  10. package/dist/chunk-5RBLIVBF.js +1 -0
  11. package/dist/chunk-67QCYUJU.js +1 -0
  12. package/dist/chunk-6QKI756T.js +2 -0
  13. package/dist/chunk-6V4WM73L.js +1 -0
  14. package/dist/chunk-6XEC6474.js +1 -0
  15. package/dist/chunk-7DFNBRLY.js +61 -0
  16. package/dist/chunk-ARNZQBMX.js +1 -0
  17. package/dist/chunk-AYUJY37O.js +5 -0
  18. package/dist/chunk-CADKBP3D.js +58 -0
  19. package/dist/chunk-CDI5CCHU.js +1 -0
  20. package/dist/chunk-CNQ5DTNC.js +1 -0
  21. package/dist/chunk-DCLWFGEA.js +1 -0
  22. package/dist/chunk-DNF4HDI6.js +14 -0
  23. package/dist/chunk-DPFNJZUO.js +1 -0
  24. package/dist/chunk-DSO2U4Y6.js +56 -0
  25. package/dist/chunk-DVN7GFJG.js +1 -0
  26. package/dist/chunk-G63KMH6U.js +1 -0
  27. package/dist/chunk-G6XGDHGC.js +2 -0
  28. package/dist/chunk-GBMF3TP6.js +1 -0
  29. package/dist/chunk-GY5IJ4RS.js +1 -0
  30. package/dist/chunk-H2ORWIEY.js +1 -0
  31. package/dist/chunk-H4SV7FN4.js +1 -0
  32. package/dist/chunk-HS7X43XE.js +24 -0
  33. package/dist/{chunk-OQBBVTDG.js → chunk-I2DZGJRR.js} +6 -71
  34. package/dist/chunk-IZTIYR5Q.js +2 -0
  35. package/dist/chunk-JAPCCEKF.js +3 -0
  36. package/dist/chunk-JQTGQXUX.js +1 -0
  37. package/dist/chunk-KAF3CYRW.js +9 -0
  38. package/dist/chunk-KKDHD4XA.js +2 -0
  39. package/dist/chunk-KV325CXF.js +33 -0
  40. package/dist/chunk-MGHFDHHM.js +1 -0
  41. package/dist/chunk-MODXEGCU.js +1 -0
  42. package/dist/chunk-MVM6OGAF.js +4 -0
  43. package/dist/chunk-N7ODX6PO.js +1 -0
  44. package/dist/chunk-N7TGRFVZ.js +70 -0
  45. package/dist/chunk-NBTC5FNV.js +1 -0
  46. package/dist/chunk-NEACEHQD.js +1 -0
  47. package/dist/chunk-NJ5UED3H.js +1 -0
  48. package/dist/chunk-NVKX36YN.js +3 -0
  49. package/dist/chunk-O2SDD2WW.js +1 -0
  50. package/dist/chunk-O6C2UGBY.js +7 -0
  51. package/dist/chunk-OMXUK4M6.js +1 -0
  52. package/dist/chunk-PPKPCXJD.js +4 -0
  53. package/dist/{chunk-XZXS2W24.js → chunk-QFVGUZDO.js} +11 -57
  54. package/dist/chunk-RDET7CKR.js +1 -0
  55. package/dist/chunk-RQ424GI6.js +5 -0
  56. package/dist/chunk-RSKQRVPJ.js +1 -0
  57. package/dist/chunk-RTWRHIKY.js +7 -0
  58. package/dist/chunk-SZ62CP55.js +1 -0
  59. package/dist/chunk-TDD7IOV2.js +1 -0
  60. package/dist/chunk-TIOKY2IA.js +1 -0
  61. package/dist/chunk-TQMG647B.js +15 -0
  62. package/dist/chunk-TU2AR6XO.js +1 -0
  63. package/dist/chunk-U6ABMRT3.js +9 -0
  64. package/dist/chunk-U6XEU573.js +1 -0
  65. package/dist/chunk-UF6US7VU.js +1 -0
  66. package/dist/chunk-V44SRRYR.js +1 -0
  67. package/dist/chunk-V5U3E4BZ.js +1 -0
  68. package/dist/chunk-VAXRCSSH.js +2 -0
  69. package/dist/chunk-VLOX6KOM.js +1 -0
  70. package/dist/chunk-VUGRXM7R.js +1 -0
  71. package/dist/chunk-W2MOTOQE.js +1 -0
  72. package/dist/chunk-W2MV25SB.js +1 -0
  73. package/dist/chunk-WLVQJH4E.js +1 -0
  74. package/dist/chunk-WSCK4WNK.js +1 -0
  75. package/dist/chunk-XICLXXRH.js +1 -0
  76. package/dist/chunk-XXDZJ6YI.js +1 -0
  77. package/dist/chunk-ZL4MZMUK.js +34 -0
  78. package/dist/chunk-ZLLER3HP.js +1 -0
  79. package/dist/chunk-ZR3MUNLS.js +1 -0
  80. package/dist/chunk-ZXF5NE54.js +1 -0
  81. package/dist/commands/antigravity/backfill.js +2 -136
  82. package/dist/commands/auth/create-key.js +1 -52
  83. package/dist/commands/auth/login.js +1 -85
  84. package/dist/commands/auth/logout.js +1 -29
  85. package/dist/commands/auth/revoke-key.js +4 -33
  86. package/dist/commands/auth/signup.js +1 -89
  87. package/dist/commands/auth/status.js +1 -42
  88. package/dist/commands/catalog/index.js +2 -52
  89. package/dist/commands/catalog/recommend.js +3 -43
  90. package/dist/commands/convert.js +1 -75
  91. package/dist/commands/converters.js +1 -54
  92. package/dist/commands/crons/list.js +1 -41
  93. package/dist/commands/crons/run.js +2 -76
  94. package/dist/commands/dashboard.js +1 -46
  95. package/dist/commands/diagnostics.js +1 -117
  96. package/dist/commands/eval-targets/create.js +1 -53
  97. package/dist/commands/eval-targets/list.js +1 -54
  98. package/dist/commands/evals/agent.js +3 -310
  99. package/dist/commands/evals/benchmark.js +6 -73
  100. package/dist/commands/evals/compare.js +13 -96
  101. package/dist/commands/evals/create.js +1 -67
  102. package/dist/commands/evals/optimize-description.js +25 -239
  103. package/dist/commands/evals/optimize.js +5 -211
  104. package/dist/commands/evals/run.js +3 -183
  105. package/dist/commands/gateway/ensure.js +1 -104
  106. package/dist/commands/hooks/emit-instructions.js +1 -25
  107. package/dist/commands/hooks/install.js +1 -442
  108. package/dist/commands/hooks/run.js +3 -81
  109. package/dist/commands/hooks/uninstall.js +2 -156
  110. package/dist/commands/import.js +1 -66
  111. package/dist/commands/instructions/create.js +1 -74
  112. package/dist/commands/instructions/delete.js +1 -55
  113. package/dist/commands/instructions/fork.js +1 -34
  114. package/dist/commands/instructions/get.js +1 -68
  115. package/dist/commands/instructions/list.js +1 -65
  116. package/dist/commands/instructions/promote.js +1 -42
  117. package/dist/commands/instructions/pull.js +1 -39
  118. package/dist/commands/instructions/upstream.js +1 -38
  119. package/dist/commands/instructions/versions.js +1 -53
  120. package/dist/commands/launcher.js +1 -40
  121. package/dist/commands/org/current.js +1 -77
  122. package/dist/commands/org/list.js +1 -52
  123. package/dist/commands/org/switch.js +1 -71
  124. package/dist/commands/packs/add-instruction.js +1 -37
  125. package/dist/commands/packs/apply.js +1 -39
  126. package/dist/commands/packs/create.js +1 -50
  127. package/dist/commands/packs/fork.js +1 -34
  128. package/dist/commands/packs/get.js +3 -56
  129. package/dist/commands/packs/list.js +1 -66
  130. package/dist/commands/packs/remove-instruction.js +1 -35
  131. package/dist/commands/proxy/env.js +3 -131
  132. package/dist/commands/proxy/logs.js +3 -85
  133. package/dist/commands/proxy/restart.js +1 -35
  134. package/dist/commands/proxy/setup.js +17 -454
  135. package/dist/commands/proxy/start.js +10 -333
  136. package/dist/commands/proxy/status.js +1 -78
  137. package/dist/commands/proxy/stop.js +1 -94
  138. package/dist/commands/research/backfill.js +1 -59
  139. package/dist/commands/research/tail-transcript.js +1 -70
  140. package/dist/commands/service/install.js +57 -796
  141. package/dist/commands/service/status.js +1 -180
  142. package/dist/commands/service/uninstall.js +1 -119
  143. package/dist/commands/sessions/analyze.js +1 -48
  144. package/dist/commands/sessions/end.js +2 -85
  145. package/dist/commands/sessions/import.js +1 -46
  146. package/dist/commands/sessions/list.js +1 -48
  147. package/dist/commands/sessions/start.js +3 -90
  148. package/dist/commands/setup.js +3 -150
  149. package/dist/commands/skills/export-approved.js +1 -46
  150. package/dist/commands/skills/install.js +4 -107
  151. package/dist/commands/skills/list.js +4 -65
  152. package/dist/commands/skills/publish.js +2 -98
  153. package/dist/commands/skills/search.js +3 -72
  154. package/dist/commands/skills/update.js +3 -55
  155. package/dist/commands/suggestions/accept.js +8 -84
  156. package/dist/commands/suggestions/dismiss.js +1 -45
  157. package/dist/commands/suggestions/list.js +2 -61
  158. package/dist/commands/suggestions/refresh.js +1 -27
  159. package/dist/cursor-T7AMCMKS.js +13 -0
  160. package/dist/dashboard/Dashboard.js +1 -243
  161. package/dist/dashboard/data.js +1 -15
  162. package/dist/dashboard/launcher/ActiveJobsList.js +1 -10
  163. package/dist/dashboard/launcher/LauncherOverlay.js +1 -16
  164. package/dist/dashboard/launcher/NewLaunchForm.js +1 -10
  165. package/dist/dashboard/launcher/api.js +1 -16
  166. package/dist/dashboard/launcher/tool-labels.js +1 -10
  167. package/dist/dashboard/launcher/types.js +0 -1
  168. package/dist/dashboard/launcher/useLaunchJobs.js +1 -11
  169. package/dist/dashboard/panels/friction.js +1 -10
  170. package/dist/dashboard/panels/insights.js +1 -10
  171. package/dist/dashboard/panels/instructions.js +1 -10
  172. package/dist/dashboard/panels/outcomes.js +1 -10
  173. package/dist/dashboard/panels/overview.js +1 -10
  174. package/dist/dashboard/panels/shared.js +1 -19
  175. package/dist/dashboard/types.js +1 -24
  176. package/dist/dist-FAVALJ5C.js +1 -0
  177. package/dist/index.js +1 -8
  178. package/dist/lib/active-org-refresh.js +1 -15
  179. package/dist/lib/active-org.js +1 -16
  180. package/dist/lib/agent-loop.js +1 -47
  181. package/dist/lib/antigravity-transcript.js +1 -22
  182. package/dist/lib/api-client.js +1 -23
  183. package/dist/lib/auth.js +1 -30
  184. package/dist/lib/capture-hosts.js +1 -8
  185. package/dist/lib/detect-languages.js +1 -8
  186. package/dist/lib/detect-tmux.js +1 -9
  187. package/dist/lib/diagnostics.js +1 -12
  188. package/dist/lib/editor-proxy-pins.js +1 -14
  189. package/dist/lib/ensure-api-key.js +1 -11
  190. package/dist/lib/ensure-fresh-token.js +1 -0
  191. package/dist/lib/eval-analyzer.js +1 -9
  192. package/dist/lib/eval-benchmark.js +1 -12
  193. package/dist/lib/eval-conversation-handler.js +1 -13
  194. package/dist/lib/eval-executor.js +1 -8
  195. package/dist/lib/eval-grader.js +1 -9
  196. package/dist/lib/eval-meta-judge.js +1 -9
  197. package/dist/lib/eval-trigger-tester.js +1 -11
  198. package/dist/lib/eval-worktree.js +1 -8
  199. package/dist/lib/gateway-entry.js +1 -61
  200. package/dist/lib/gateway-identity.js +1 -16
  201. package/dist/lib/gateway-lifecycle.js +1 -32
  202. package/dist/lib/gateway.js +1 -14
  203. package/dist/lib/handlers/cron-refresh-pricing.js +1 -0
  204. package/dist/lib/handlers/cron-refresh-skills.js +1 -8
  205. package/dist/lib/handlers/cron-suggest-instructions.js +1 -16
  206. package/dist/lib/handlers/process-announcement.js +1 -11
  207. package/dist/lib/handlers/process-changelog.js +1 -11
  208. package/dist/lib/handlers/process-conversation.js +1 -14
  209. package/dist/lib/handlers/process-eval.js +1 -15
  210. package/dist/lib/handlers/process-insights.js +1 -15
  211. package/dist/lib/handlers/process-launch.js +1 -16
  212. package/dist/lib/handlers/process-run-cleanup.js +1 -13
  213. package/dist/lib/handlers/process-send-message.js +1 -10
  214. package/dist/lib/handlers/process-session-goal.js +1 -12
  215. package/dist/lib/hooks-config.js +1 -81
  216. package/dist/lib/insights-prompts.js +1 -12
  217. package/dist/lib/instruction-snapshot.js +1 -8
  218. package/dist/lib/job-helpers.js +0 -1
  219. package/dist/lib/llm-client.js +1 -20
  220. package/dist/lib/manual-tasks-meta.js +1 -8
  221. package/dist/lib/manual-tasks.js +1 -80
  222. package/dist/lib/output.js +1 -12
  223. package/dist/lib/permanent-job-error.js +1 -10
  224. package/dist/lib/pid-identity.js +1 -14
  225. package/dist/lib/proxy-respawn.js +1 -12
  226. package/dist/lib/research-client.js +1 -12
  227. package/dist/lib/setup-steps.js +1 -33
  228. package/dist/lib/skills-loader.js +1 -8
  229. package/dist/lib/statusline-shim.js +1 -20
  230. package/dist/lib/telemetry.js +1 -16
  231. package/dist/lib/terminal-target-heartbeat.js +1 -15
  232. package/dist/lib/tmux.js +1 -16
  233. package/dist/lib/transcript-rate-limit-watcher.js +1 -22
  234. package/dist/lib/types.js +1 -8
  235. package/dist/lib/version-check.js +1 -12
  236. package/dist/lib/which.js +1 -8
  237. package/dist/lib/worktree.js +1 -17
  238. package/dist/opencode-QRJ3BH23.js +1 -0
  239. package/oclif.manifest.json +12 -34
  240. package/package.json +9 -8
  241. package/dist/base-command.js.map +0 -7
  242. package/dist/chunk-2HK7RGZB.js +0 -82
  243. package/dist/chunk-2HK7RGZB.js.map +0 -7
  244. package/dist/chunk-2ORJWTNZ.js +0 -307
  245. package/dist/chunk-2ORJWTNZ.js.map +0 -7
  246. package/dist/chunk-37LN5O7M.js +0 -59
  247. package/dist/chunk-37LN5O7M.js.map +0 -7
  248. package/dist/chunk-3S7223UR.js +0 -81
  249. package/dist/chunk-3S7223UR.js.map +0 -7
  250. package/dist/chunk-3TIMQ3O6.js +0 -96
  251. package/dist/chunk-3TIMQ3O6.js.map +0 -7
  252. package/dist/chunk-42GFSAJP.js +0 -32
  253. package/dist/chunk-42GFSAJP.js.map +0 -7
  254. package/dist/chunk-4BHDHHKL.js +0 -48
  255. package/dist/chunk-4BHDHHKL.js.map +0 -7
  256. package/dist/chunk-4D537GXE.js +0 -99
  257. package/dist/chunk-4D537GXE.js.map +0 -7
  258. package/dist/chunk-4LYCDS2N.js +0 -139
  259. package/dist/chunk-4LYCDS2N.js.map +0 -7
  260. package/dist/chunk-4SCZK7AL.js +0 -129
  261. package/dist/chunk-4SCZK7AL.js.map +0 -7
  262. package/dist/chunk-4XAWK6S2.js +0 -161
  263. package/dist/chunk-4XAWK6S2.js.map +0 -7
  264. package/dist/chunk-52WIYRZH.js +0 -73
  265. package/dist/chunk-52WIYRZH.js.map +0 -7
  266. package/dist/chunk-5BAOGNUH.js +0 -79
  267. package/dist/chunk-5BAOGNUH.js.map +0 -7
  268. package/dist/chunk-5EDMGK3W.js +0 -39
  269. package/dist/chunk-5EDMGK3W.js.map +0 -7
  270. package/dist/chunk-6NBS5XFS.js +0 -99
  271. package/dist/chunk-6NBS5XFS.js.map +0 -7
  272. package/dist/chunk-7LVVKQMZ.js +0 -98
  273. package/dist/chunk-7LVVKQMZ.js.map +0 -7
  274. package/dist/chunk-7NNFYWKK.js +0 -243
  275. package/dist/chunk-7NNFYWKK.js.map +0 -7
  276. package/dist/chunk-7NYKWN7U.js +0 -12
  277. package/dist/chunk-7NYKWN7U.js.map +0 -7
  278. package/dist/chunk-BO76WKJR.js +0 -42
  279. package/dist/chunk-BO76WKJR.js.map +0 -7
  280. package/dist/chunk-BRD5RUGM.js +0 -53
  281. package/dist/chunk-BRD5RUGM.js.map +0 -7
  282. package/dist/chunk-BT6Z6545.js +0 -43
  283. package/dist/chunk-BT6Z6545.js.map +0 -7
  284. package/dist/chunk-BZDKEQKU.js +0 -39
  285. package/dist/chunk-BZDKEQKU.js.map +0 -7
  286. package/dist/chunk-DGHWRQXL.js +0 -17
  287. package/dist/chunk-DGHWRQXL.js.map +0 -7
  288. package/dist/chunk-DIQUV5FR.js +0 -257
  289. package/dist/chunk-DIQUV5FR.js.map +0 -7
  290. package/dist/chunk-DMX5YOTM.js +0 -167
  291. package/dist/chunk-DMX5YOTM.js.map +0 -7
  292. package/dist/chunk-DNKSVWMD.js +0 -108
  293. package/dist/chunk-DNKSVWMD.js.map +0 -7
  294. package/dist/chunk-DQ3KELXD.js +0 -74
  295. package/dist/chunk-DQ3KELXD.js.map +0 -7
  296. package/dist/chunk-DUJSRBLP.js +0 -122
  297. package/dist/chunk-DUJSRBLP.js.map +0 -7
  298. package/dist/chunk-E3BIT53W.js +0 -154
  299. package/dist/chunk-E3BIT53W.js.map +0 -7
  300. package/dist/chunk-EARWG4EV.js +0 -22
  301. package/dist/chunk-EARWG4EV.js.map +0 -7
  302. package/dist/chunk-EI5BHWXA.js +0 -1662
  303. package/dist/chunk-EI5BHWXA.js.map +0 -7
  304. package/dist/chunk-EJ3YAFDP.js +0 -37
  305. package/dist/chunk-EJ3YAFDP.js.map +0 -7
  306. package/dist/chunk-EKJ2CABV.js +0 -76
  307. package/dist/chunk-EKJ2CABV.js.map +0 -7
  308. package/dist/chunk-EKP32DLN.js +0 -16
  309. package/dist/chunk-EKP32DLN.js.map +0 -7
  310. package/dist/chunk-EYPAAGN5.js +0 -51
  311. package/dist/chunk-EYPAAGN5.js.map +0 -7
  312. package/dist/chunk-F5N6CLJJ.js +0 -1995
  313. package/dist/chunk-F5N6CLJJ.js.map +0 -7
  314. package/dist/chunk-GIUBARWS.js +0 -99
  315. package/dist/chunk-GIUBARWS.js.map +0 -7
  316. package/dist/chunk-GQNJO2P2.js +0 -102
  317. package/dist/chunk-GQNJO2P2.js.map +0 -7
  318. package/dist/chunk-IJGF2ETG.js +0 -68
  319. package/dist/chunk-IJGF2ETG.js.map +0 -7
  320. package/dist/chunk-ILYDELUE.js +0 -46
  321. package/dist/chunk-ILYDELUE.js.map +0 -7
  322. package/dist/chunk-J6QFW4LD.js +0 -55
  323. package/dist/chunk-J6QFW4LD.js.map +0 -7
  324. package/dist/chunk-J7N3DLH6.js +0 -117
  325. package/dist/chunk-J7N3DLH6.js.map +0 -7
  326. package/dist/chunk-JFDWKLQC.js +0 -23
  327. package/dist/chunk-JFDWKLQC.js.map +0 -7
  328. package/dist/chunk-JULOLTZS.js +0 -61
  329. package/dist/chunk-JULOLTZS.js.map +0 -7
  330. package/dist/chunk-KJKBDQ4D.js +0 -220
  331. package/dist/chunk-KJKBDQ4D.js.map +0 -7
  332. package/dist/chunk-KRBQLMOP.js +0 -41
  333. package/dist/chunk-KRBQLMOP.js.map +0 -7
  334. package/dist/chunk-LXKPNATC.js +0 -624
  335. package/dist/chunk-LXKPNATC.js.map +0 -7
  336. package/dist/chunk-NSBPE2FW.js +0 -17
  337. package/dist/chunk-NSBPE2FW.js.map +0 -7
  338. package/dist/chunk-OCKHW72U.js +0 -55
  339. package/dist/chunk-OCKHW72U.js.map +0 -7
  340. package/dist/chunk-OKWCKCPE.js +0 -414
  341. package/dist/chunk-OKWCKCPE.js.map +0 -7
  342. package/dist/chunk-OO7JDFS4.js +0 -157
  343. package/dist/chunk-OO7JDFS4.js.map +0 -7
  344. package/dist/chunk-OQBBVTDG.js.map +0 -7
  345. package/dist/chunk-OQSQC7VB.js +0 -77
  346. package/dist/chunk-OQSQC7VB.js.map +0 -7
  347. package/dist/chunk-PED7L5GX.js +0 -92
  348. package/dist/chunk-PED7L5GX.js.map +0 -7
  349. package/dist/chunk-QJQS6TUN.js +0 -44
  350. package/dist/chunk-QJQS6TUN.js.map +0 -7
  351. package/dist/chunk-QN34TGD3.js +0 -83
  352. package/dist/chunk-QN34TGD3.js.map +0 -7
  353. package/dist/chunk-QSN77T7C.js +0 -250
  354. package/dist/chunk-QSN77T7C.js.map +0 -7
  355. package/dist/chunk-R56PH7YE.js +0 -78
  356. package/dist/chunk-R56PH7YE.js.map +0 -7
  357. package/dist/chunk-RAXRZYOB.js +0 -299
  358. package/dist/chunk-RAXRZYOB.js.map +0 -7
  359. package/dist/chunk-RH7NHVSK.js +0 -16
  360. package/dist/chunk-RH7NHVSK.js.map +0 -7
  361. package/dist/chunk-RMTT4KDY.js +0 -191
  362. package/dist/chunk-RMTT4KDY.js.map +0 -7
  363. package/dist/chunk-RQ2TMLKG.js +0 -142
  364. package/dist/chunk-RQ2TMLKG.js.map +0 -7
  365. package/dist/chunk-SO3T35U7.js +0 -80
  366. package/dist/chunk-SO3T35U7.js.map +0 -7
  367. package/dist/chunk-UKMLICWS.js +0 -51
  368. package/dist/chunk-UKMLICWS.js.map +0 -7
  369. package/dist/chunk-VA5FFOS7.js +0 -243
  370. package/dist/chunk-VA5FFOS7.js.map +0 -7
  371. package/dist/chunk-W2YERO7E.js +0 -170
  372. package/dist/chunk-W2YERO7E.js.map +0 -7
  373. package/dist/chunk-W53GKIZQ.js +0 -50
  374. package/dist/chunk-W53GKIZQ.js.map +0 -7
  375. package/dist/chunk-WA4MWYRW.js +0 -254
  376. package/dist/chunk-WA4MWYRW.js.map +0 -7
  377. package/dist/chunk-XC6M4CSW.js +0 -44
  378. package/dist/chunk-XC6M4CSW.js.map +0 -7
  379. package/dist/chunk-XK42ZBDE.js +0 -23
  380. package/dist/chunk-XK42ZBDE.js.map +0 -7
  381. package/dist/chunk-XUV6DDBF.js +0 -124
  382. package/dist/chunk-XUV6DDBF.js.map +0 -7
  383. package/dist/chunk-XZXS2W24.js.map +0 -7
  384. package/dist/chunk-Y3WD5CSW.js +0 -49
  385. package/dist/chunk-Y3WD5CSW.js.map +0 -7
  386. package/dist/chunk-Y4BJXXYV.js +0 -148
  387. package/dist/chunk-Y4BJXXYV.js.map +0 -7
  388. package/dist/chunk-YNIH3KMU.js +0 -121
  389. package/dist/chunk-YNIH3KMU.js.map +0 -7
  390. package/dist/chunk-ZUJBM6HE.js +0 -125
  391. package/dist/chunk-ZUJBM6HE.js.map +0 -7
  392. package/dist/commands/antigravity/backfill.js.map +0 -7
  393. package/dist/commands/auth/create-key.js.map +0 -7
  394. package/dist/commands/auth/login.js.map +0 -7
  395. package/dist/commands/auth/logout.js.map +0 -7
  396. package/dist/commands/auth/revoke-key.js.map +0 -7
  397. package/dist/commands/auth/signup.js.map +0 -7
  398. package/dist/commands/auth/status.js.map +0 -7
  399. package/dist/commands/catalog/index.js.map +0 -7
  400. package/dist/commands/catalog/recommend.js.map +0 -7
  401. package/dist/commands/convert.js.map +0 -7
  402. package/dist/commands/converters.js.map +0 -7
  403. package/dist/commands/crons/list.js.map +0 -7
  404. package/dist/commands/crons/run.js.map +0 -7
  405. package/dist/commands/dashboard.js.map +0 -7
  406. package/dist/commands/diagnostics.js.map +0 -7
  407. package/dist/commands/eval-targets/create.js.map +0 -7
  408. package/dist/commands/eval-targets/list.js.map +0 -7
  409. package/dist/commands/evals/agent.js.map +0 -7
  410. package/dist/commands/evals/benchmark.js.map +0 -7
  411. package/dist/commands/evals/compare.js.map +0 -7
  412. package/dist/commands/evals/create.js.map +0 -7
  413. package/dist/commands/evals/optimize-description.js.map +0 -7
  414. package/dist/commands/evals/optimize.js.map +0 -7
  415. package/dist/commands/evals/run.js.map +0 -7
  416. package/dist/commands/gateway/ensure.js.map +0 -7
  417. package/dist/commands/hooks/emit-instructions.js.map +0 -7
  418. package/dist/commands/hooks/install.js.map +0 -7
  419. package/dist/commands/hooks/run.js.map +0 -7
  420. package/dist/commands/hooks/uninstall.js.map +0 -7
  421. package/dist/commands/import.js.map +0 -7
  422. package/dist/commands/instructions/create.js.map +0 -7
  423. package/dist/commands/instructions/delete.js.map +0 -7
  424. package/dist/commands/instructions/fork.js.map +0 -7
  425. package/dist/commands/instructions/get.js.map +0 -7
  426. package/dist/commands/instructions/list.js.map +0 -7
  427. package/dist/commands/instructions/promote.js.map +0 -7
  428. package/dist/commands/instructions/pull.js.map +0 -7
  429. package/dist/commands/instructions/upstream.js.map +0 -7
  430. package/dist/commands/instructions/versions.js.map +0 -7
  431. package/dist/commands/launcher.js.map +0 -7
  432. package/dist/commands/org/current.js.map +0 -7
  433. package/dist/commands/org/list.js.map +0 -7
  434. package/dist/commands/org/switch.js.map +0 -7
  435. package/dist/commands/packs/add-instruction.js.map +0 -7
  436. package/dist/commands/packs/apply.js.map +0 -7
  437. package/dist/commands/packs/create.js.map +0 -7
  438. package/dist/commands/packs/fork.js.map +0 -7
  439. package/dist/commands/packs/get.js.map +0 -7
  440. package/dist/commands/packs/list.js.map +0 -7
  441. package/dist/commands/packs/remove-instruction.js.map +0 -7
  442. package/dist/commands/proxy/env.js.map +0 -7
  443. package/dist/commands/proxy/logs.js.map +0 -7
  444. package/dist/commands/proxy/restart.js.map +0 -7
  445. package/dist/commands/proxy/setup.js.map +0 -7
  446. package/dist/commands/proxy/start.js.map +0 -7
  447. package/dist/commands/proxy/status.js.map +0 -7
  448. package/dist/commands/proxy/stop.js.map +0 -7
  449. package/dist/commands/research/backfill.js.map +0 -7
  450. package/dist/commands/research/tail-transcript.js.map +0 -7
  451. package/dist/commands/service/install.js.map +0 -7
  452. package/dist/commands/service/status.js.map +0 -7
  453. package/dist/commands/service/uninstall.js.map +0 -7
  454. package/dist/commands/sessions/analyze.js.map +0 -7
  455. package/dist/commands/sessions/end.js.map +0 -7
  456. package/dist/commands/sessions/import.js.map +0 -7
  457. package/dist/commands/sessions/list.js.map +0 -7
  458. package/dist/commands/sessions/start.js.map +0 -7
  459. package/dist/commands/setup.js.map +0 -7
  460. package/dist/commands/skills/export-approved.js.map +0 -7
  461. package/dist/commands/skills/install.js.map +0 -7
  462. package/dist/commands/skills/list.js.map +0 -7
  463. package/dist/commands/skills/publish.js.map +0 -7
  464. package/dist/commands/skills/search.js.map +0 -7
  465. package/dist/commands/skills/update.js.map +0 -7
  466. package/dist/commands/suggestions/accept.js.map +0 -7
  467. package/dist/commands/suggestions/dismiss.js.map +0 -7
  468. package/dist/commands/suggestions/list.js.map +0 -7
  469. package/dist/commands/suggestions/refresh.js.map +0 -7
  470. package/dist/cursor-BGQJ4CWI.js +0 -134
  471. package/dist/cursor-BGQJ4CWI.js.map +0 -7
  472. package/dist/dashboard/Dashboard.js.map +0 -7
  473. package/dist/dashboard/data.js.map +0 -7
  474. package/dist/dashboard/launcher/ActiveJobsList.js.map +0 -7
  475. package/dist/dashboard/launcher/LauncherOverlay.js.map +0 -7
  476. package/dist/dashboard/launcher/NewLaunchForm.js.map +0 -7
  477. package/dist/dashboard/launcher/api.js.map +0 -7
  478. package/dist/dashboard/launcher/tool-labels.js.map +0 -7
  479. package/dist/dashboard/launcher/types.js.map +0 -7
  480. package/dist/dashboard/launcher/useLaunchJobs.js.map +0 -7
  481. package/dist/dashboard/panels/friction.js.map +0 -7
  482. package/dist/dashboard/panels/insights.js.map +0 -7
  483. package/dist/dashboard/panels/instructions.js.map +0 -7
  484. package/dist/dashboard/panels/outcomes.js.map +0 -7
  485. package/dist/dashboard/panels/overview.js.map +0 -7
  486. package/dist/dashboard/panels/shared.js.map +0 -7
  487. package/dist/dashboard/types.js.map +0 -7
  488. package/dist/dist-UNYP5PJR.js +0 -56
  489. package/dist/dist-UNYP5PJR.js.map +0 -7
  490. package/dist/index.js.map +0 -7
  491. package/dist/lib/active-org-refresh.js.map +0 -7
  492. package/dist/lib/active-org.js.map +0 -7
  493. package/dist/lib/agent-loop.js.map +0 -7
  494. package/dist/lib/antigravity-transcript.js.map +0 -7
  495. package/dist/lib/api-client.js.map +0 -7
  496. package/dist/lib/auth.js.map +0 -7
  497. package/dist/lib/capture-hosts.js.map +0 -7
  498. package/dist/lib/detect-languages.js.map +0 -7
  499. package/dist/lib/detect-tmux.js.map +0 -7
  500. package/dist/lib/diagnostics.js.map +0 -7
  501. package/dist/lib/editor-proxy-pins.js.map +0 -7
  502. package/dist/lib/ensure-api-key.js.map +0 -7
  503. package/dist/lib/eval-analyzer.js.map +0 -7
  504. package/dist/lib/eval-benchmark.js.map +0 -7
  505. package/dist/lib/eval-conversation-handler.js.map +0 -7
  506. package/dist/lib/eval-executor.js.map +0 -7
  507. package/dist/lib/eval-grader.js.map +0 -7
  508. package/dist/lib/eval-meta-judge.js.map +0 -7
  509. package/dist/lib/eval-trigger-tester.js.map +0 -7
  510. package/dist/lib/eval-worktree.js.map +0 -7
  511. package/dist/lib/gateway-entry.js.map +0 -7
  512. package/dist/lib/gateway-identity.js.map +0 -7
  513. package/dist/lib/gateway-lifecycle.js.map +0 -7
  514. package/dist/lib/gateway.js.map +0 -7
  515. package/dist/lib/handlers/cron-refresh-skills.js.map +0 -7
  516. package/dist/lib/handlers/cron-suggest-instructions.js.map +0 -7
  517. package/dist/lib/handlers/process-announcement.js.map +0 -7
  518. package/dist/lib/handlers/process-changelog.js.map +0 -7
  519. package/dist/lib/handlers/process-conversation.js.map +0 -7
  520. package/dist/lib/handlers/process-eval.js.map +0 -7
  521. package/dist/lib/handlers/process-insights.js.map +0 -7
  522. package/dist/lib/handlers/process-launch.js.map +0 -7
  523. package/dist/lib/handlers/process-run-cleanup.js.map +0 -7
  524. package/dist/lib/handlers/process-send-message.js.map +0 -7
  525. package/dist/lib/handlers/process-session-goal.js.map +0 -7
  526. package/dist/lib/hooks-config.js.map +0 -7
  527. package/dist/lib/insights-prompts.js.map +0 -7
  528. package/dist/lib/instruction-snapshot.js.map +0 -7
  529. package/dist/lib/job-helpers.js.map +0 -7
  530. package/dist/lib/llm-client.js.map +0 -7
  531. package/dist/lib/manual-tasks-meta.js.map +0 -7
  532. package/dist/lib/manual-tasks.js.map +0 -7
  533. package/dist/lib/output.js.map +0 -7
  534. package/dist/lib/permanent-job-error.js.map +0 -7
  535. package/dist/lib/pid-identity.js.map +0 -7
  536. package/dist/lib/proxy-respawn.js.map +0 -7
  537. package/dist/lib/research-client.js.map +0 -7
  538. package/dist/lib/setup-steps.js.map +0 -7
  539. package/dist/lib/skills-loader.js.map +0 -7
  540. package/dist/lib/statusline-shim.js.map +0 -7
  541. package/dist/lib/telemetry.js.map +0 -7
  542. package/dist/lib/terminal-target-heartbeat.js.map +0 -7
  543. package/dist/lib/tmux.js.map +0 -7
  544. package/dist/lib/transcript-rate-limit-watcher.js.map +0 -7
  545. package/dist/lib/types.js.map +0 -7
  546. package/dist/lib/version-check.js.map +0 -7
  547. package/dist/lib/which.js.map +0 -7
  548. package/dist/lib/worktree.js.map +0 -7
  549. package/dist/opencode-IQ7X5YMJ.js +0 -190
  550. package/dist/opencode-IQ7X5YMJ.js.map +0 -7
@@ -1,697 +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
- // systemd --user units get no shell PATH; without one the worker cannot
423
- // find `claude` and every eval/insights LLM call returns null. Same dir
424
- // set as the launchd worker plist (node siblings, native installer,
425
- // brew, system).
426
- PATH: [
427
- .../* @__PURE__ */ new Set(
428
- [dirname(nodePath), join(homedir(), ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin"]
429
- )
430
- ].join(":"),
431
- // Mirror the launchd worker's pooler bound (RCA 2026-06-21).
432
- PG_POOL_MAX: envVars.PG_POOL_MAX ?? "3",
433
- PG_IDLE_TIMEOUT: envVars.PG_IDLE_TIMEOUT ?? "10"
434
- };
435
- const envLines = Object.entries(env).map(([k, v]) => `Environment="${k}=${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`).join("\n");
436
- return `[Unit]
1
+ import{a as j}from"../../chunk-6XEC6474.js";import"../../chunk-N7ODX6PO.js";import{a as W}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import{c as M}from"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import{b as D}from"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.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 B}from"node:fs";import{execSync as N,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_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","WEB_URL","RULEMETRIC_WEB_URL","SENTRY_DSN"]),H="com.rulemetric.api",I=o(y(),"Library","LaunchAgents",`${H}.plist`),X="com.rulemetric.worker",b=o(y(),"Library","LaunchAgents",`${X}.plist`),F="com.rulemetric.gateway",G=o(y(),"Library","LaunchAgents",`${F}.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=N("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 j();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=N("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});B(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]
437
5
  Description=RuleMetric job worker (evals agent)
438
6
  After=network-online.target
439
7
  Wants=network-online.target
440
8
 
441
9
  [Service]
442
10
  Type=simple
443
- ExecStart=${nodePath} ${cliBin} evals agent
11
+ ExecStart=${e} ${t} evals agent
444
12
  Restart=on-failure
445
13
  RestartSec=15
446
- ${envLines}
14
+ ${n}
447
15
 
448
16
  [Install]
449
17
  WantedBy=default.target
450
- `;
451
- }
452
- findProjectRoot() {
453
- if (process.env.RULEMETRIC_PROJECT_ROOT) {
454
- return process.env.RULEMETRIC_PROJECT_ROOT;
455
- }
456
- let dir = process.cwd();
457
- for (let i = 0; i < 10; i++) {
458
- if (existsSync(join(dir, "apps", "api", "package.json"))) {
459
- return dir;
460
- }
461
- const parent = join(dir, "..");
462
- if (parent === dir) break;
463
- dir = parent;
464
- }
465
- return null;
466
- }
467
- findBinary(name) {
468
- try {
469
- return execFileSync("which", [name], { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).trim() || null;
470
- } catch {
471
- return null;
472
- }
473
- }
474
- loadEnvVars(projectRoot) {
475
- const vars = {};
476
- const envLocal = join(projectRoot, ".env.local");
477
- if (existsSync(envLocal)) {
478
- for (const line of readFileSync(envLocal, "utf-8").split("\n")) {
479
- const trimmed = line.trim();
480
- if (!trimmed || trimmed.startsWith("#")) continue;
481
- const eqIdx = trimmed.indexOf("=");
482
- if (eqIdx > 0) {
483
- vars[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
484
- }
485
- }
486
- }
487
- const globalEnv = join(CONFIG_DIR, "env");
488
- if (existsSync(globalEnv)) {
489
- for (const line of readFileSync(globalEnv, "utf-8").split("\n")) {
490
- const trimmed = line.trim();
491
- if (!trimmed || trimmed.startsWith("#")) continue;
492
- const eqIdx = trimmed.indexOf("=");
493
- if (eqIdx > 0) {
494
- vars[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
495
- }
496
- }
497
- }
498
- return Object.fromEntries(
499
- Object.entries(vars).filter(([k]) => ALLOWED_ENV_VARS.has(k))
500
- );
501
- }
502
- // Guard: the always-on API + worker MUST use the TRANSACTION-mode pooler
503
- // (port 6543). A SESSION-mode URL (:5432, 15-slot cap) baked into these
504
- // services was the trigger of the recurring pool saturation — a pool-cascade
505
- // debugging override leaked into the plists through this very installer. Auto-
506
- // correct the obvious session→transaction port and warn loudly; warn (but do
507
- // not block) on a direct, non-pooler URL. Pool-exhaustion RCA 2026-06-21.
508
- guardAlwaysOnDatabaseUrl(envVars) {
509
- const url = envVars.DATABASE_URL;
510
- if (!url) return envVars;
511
- if (url.includes("pooler.supabase.com:5432")) {
512
- this.warn(
513
- "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."
514
- );
515
- return { ...envVars, DATABASE_URL: url.replace("pooler.supabase.com:5432", "pooler.supabase.com:6543") };
516
- }
517
- if (/@db\.[a-z0-9]+\.supabase\.co[:/]/.test(url)) {
518
- this.warn(
519
- "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."
520
- );
521
- }
522
- return envVars;
523
- }
524
- // Reap orphaned, unsupervised `evals agent` worker processes before
525
- // (re)bootstrapping the launchd worker. The worker holds no listening port,
526
- // so killStaleProcess (port/pidfile based) cannot find detached agents — a
527
- // fleet of 4 ran 3+ days and helped saturate the pool (RCA 2026-06-21). pgrep
528
- // the command line and SIGTERM every match except ourselves; the agent's own
529
- // single-instance lock then keeps a fresh fleet from forming.
530
- killStaleAgents() {
531
- try {
532
- const out = execFileSync("pgrep", ["-f", "bin/run.js evals agent"], {
533
- encoding: "utf-8",
534
- stdio: ["ignore", "pipe", "ignore"]
535
- });
536
- const pids = out.trim().split("\n").filter(Boolean).map((s) => parseInt(s, 10)).filter((p) => !isNaN(p) && p !== process.pid);
537
- for (const pid of pids) {
538
- try {
539
- process.kill(pid, "SIGTERM");
540
- this.log(`[OK] Reaped orphan evals agent (PID ${pid})`);
541
- } catch {
542
- }
543
- }
544
- if (pids.length) spawnSync("sleep", ["1"], { stdio: "ignore" });
545
- } catch {
546
- }
547
- }
548
- // Best-effort cleanup of a process that would conflict with an
549
- // about-to-bootstrap launchd plist. Tries two routes:
550
- // (a) the PID file written by the legacy spawn path
551
- // (gateway-lifecycle / proxy start), if pidFile is non-null
552
- // (b) anything actively listening on the expected port
553
- // Either way: SIGTERM + small grace + SIGKILL fallback. Stale PID file
554
- // gets unlinked.
555
- killStaleProcess(port, pidFile, name) {
556
- let killedAny = false;
557
- if (pidFile && existsSync(pidFile)) {
558
- try {
559
- const pidStr = readFileSync(pidFile, "utf-8").trim();
560
- const pid = parseInt(pidStr, 10);
561
- if (!isNaN(pid)) {
562
- try {
563
- process.kill(pid, "SIGTERM");
564
- killedAny = true;
565
- this.log(`[OK] Stopped existing ${name} (PID ${pid} from ${pidFile})`);
566
- } catch {
567
- }
568
- }
569
- } catch {
570
- }
571
- try {
572
- execFileSync("rm", ["-f", pidFile]);
573
- } catch {
574
- }
575
- }
576
- try {
577
- const result = execFileSync("lsof", ["-ti", `:${port}`, "-sTCP:LISTEN"], {
578
- encoding: "utf-8",
579
- stdio: ["ignore", "pipe", "ignore"]
580
- });
581
- const pids = result.trim().split("\n").filter(Boolean);
582
- for (const pidStr of pids) {
583
- const pid = parseInt(pidStr, 10);
584
- if (!isNaN(pid)) {
585
- try {
586
- process.kill(pid, "SIGTERM");
587
- killedAny = true;
588
- this.log(`[OK] Stopped orphan on :${port} (PID ${pid})`);
589
- } catch {
590
- }
591
- }
592
- }
593
- } catch {
594
- }
595
- if (killedAny) {
596
- spawnSync("sleep", ["1"], { stdio: "ignore" });
597
- }
598
- }
599
- bootoutAndWrite(uid, plistPath, content, name) {
600
- const benignBootoutPatterns = [
601
- "Could not find specified service",
602
- "No such process",
603
- "3: No such process",
604
- "5: Input/output error"
605
- ];
606
- try {
607
- execFileSync("launchctl", ["bootout", `gui/${uid}`, plistPath], {
608
- encoding: "utf-8",
609
- // Capture stderr instead of letting it print to the user's terminal.
610
- // The plist was either already-loaded (we unload it cleanly) or not
611
- // loaded (we want to swallow the error) — the user shouldn't see
612
- // launchctl's raw output either way.
613
- stdio: ["ignore", "pipe", "pipe"]
614
- });
615
- this.log(`[OK] Unloaded existing ${name} service`);
616
- } catch (err) {
617
- const msg = err.message || "";
618
- const stderr = (err.stderr ?? "").toString();
619
- const combined = `${msg}
620
- ${stderr}`;
621
- if (!benignBootoutPatterns.some((p) => combined.includes(p))) {
622
- this.warn(`Could not unload existing ${name} service: ${msg.trim()}`);
623
- }
624
- }
625
- writeFileSync(plistPath, content, { mode: 384 });
626
- this.log(`[OK] ${name} plist written to ${plistPath}`);
627
- }
628
- bootstrapPlist(uid, plistPath, name) {
629
- try {
630
- execFileSync("launchctl", ["bootstrap", `gui/${uid}`, plistPath]);
631
- this.log(`[OK] ${name} service loaded into launchd`);
632
- } catch (bootstrapErr) {
633
- try {
634
- execFileSync("launchctl", ["load", plistPath]);
635
- this.log(`[OK] ${name} service loaded into launchd (legacy)`);
636
- } catch (loadErr) {
637
- this.warn(
638
- `Could not load ${name} service.
639
- bootstrap: ${bootstrapErr.message.trim()}
640
- load: ${loadErr.message.trim()}`
641
- );
642
- }
643
- }
644
- }
645
- buildPlist(opts) {
646
- const { port, projectRoot, nodePath, pnpmPath, envVars } = opts;
647
- const pathDirs = [.../* @__PURE__ */ new Set([dirname(nodePath), dirname(pnpmPath), "/usr/local/bin", "/usr/bin", "/bin"])];
648
- const envEntries = Object.entries({
649
- ...envVars,
650
- PORT: String(port),
651
- NODE_ENV: "production",
652
- PATH: pathDirs.join(":"),
653
- // Pool resilience for the always-on API (NOT the worker, which runs
654
- // legitimately long analytics queries). A wedged Supavisor socket with
655
- // the default max=3 pool and no query timeout hangs every authenticated
656
- // request — the 2026-06-09 login-hang. statement_timeout lets Postgres
657
- // cancel a stuck query so the connection returns to the pool (verified
658
- // honored through the transaction pooler); the larger pool adds headroom.
659
- // Both env-overridable. See packages/db/src/client.ts.
660
- PG_POOL_MAX: envVars.PG_POOL_MAX ?? "10",
661
- PG_STATEMENT_TIMEOUT_MS: envVars.PG_STATEMENT_TIMEOUT_MS ?? "10000",
662
- // Keep the pool warm so the API stops reconnecting (and re-resolving the
663
- // rotating pooler ELB) on nearly every request — the churn that exposed
664
- // it to intermittent CONNECT_TIMEOUT/ENOTFOUND. Worker/tests keep the
665
- // conservative 5s default. See packages/db/src/client.ts (2026-06-09).
666
- PG_IDLE_TIMEOUT: envVars.PG_IDLE_TIMEOUT ?? "30",
667
- // Silence per-span stdout dumps on the local API — it has no OTLP
668
- // endpoint and a fixed (now rotated) log file; the ConsoleSpanExporter
669
- // grew api-stdout to 370MB / ~400k spans. Fly leaves this unset so its
670
- // console spans stay grep-able in the managed log stream.
671
- OTEL_SPAN_EXPORT: envVars.OTEL_SPAN_EXPORT ?? "none"
672
- }).map(([k, v]) => ` <key>${escapeXml(k)}</key>
673
- <string>${escapeXml(v)}</string>`).join("\n");
674
- const apiEntry = join(projectRoot, "apps", "api", "dist", "index.js");
675
- const apiDist = join(projectRoot, "apps", "api", "dist");
676
- 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()}`)}B(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"?>
677
28
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
678
29
  <plist version="1.0">
679
30
  <dict>
680
31
  <key>Label</key>
681
- <string>${PLIST_LABEL}</string>
32
+ <string>${H}</string>
682
33
 
683
34
  <key>ProgramArguments</key>
684
35
  <array>
685
- <string>${escapeXml(nodePath)}</string>
686
- <string>${escapeXml(apiEntry)}</string>
36
+ <string>${l(s)}</string>
37
+ <string>${l(d)}</string>
687
38
  </array>
688
39
 
689
40
  <key>WorkingDirectory</key>
690
- <string>${escapeXml(projectRoot)}</string>
41
+ <string>${l(e)}</string>
691
42
 
692
43
  <key>EnvironmentVariables</key>
693
44
  <dict>
694
- ${envEntries}
45
+ ${c}
695
46
  </dict>
696
47
 
697
48
  <key>RunAtLoad</key>
@@ -708,71 +59,42 @@ ${envEntries}
708
59
 
709
60
  <key>WatchPaths</key>
710
61
  <array>
711
- <string>${escapeXml(apiDist)}</string>
62
+ <string>${l(u)}</string>
712
63
  </array>
713
64
 
714
65
  <key>StandardOutPath</key>
715
- <string>${escapeXml(join(LOG_DIR, "api-stdout.log"))}</string>
66
+ <string>${l(o(p,"api-stdout.log"))}</string>
716
67
 
717
68
  <key>StandardErrorPath</key>
718
- <string>${escapeXml(join(LOG_DIR, "api-stderr.log"))}</string>
69
+ <string>${l(o(p,"api-stderr.log"))}</string>
719
70
 
720
71
  <key>ProcessType</key>
721
72
  <string>Background</string>
722
73
  </dict>
723
74
  </plist>
724
- `;
725
- }
726
- buildWorkerPlist(opts) {
727
- const { cliBin, cliDist, workingDir, nodePath, pnpmPath, envVars } = opts;
728
- const nodeEnv = opts.nodeEnv ?? "development";
729
- const pathDirs = [
730
- ...new Set(
731
- [
732
- dirname(nodePath),
733
- pnpmPath ? dirname(pnpmPath) : null,
734
- join(homedir(), ".local", "bin"),
735
- "/opt/homebrew/bin",
736
- "/usr/local/bin",
737
- "/usr/bin",
738
- "/bin"
739
- ].filter((d) => Boolean(d))
740
- )
741
- ];
742
- const envEntries = Object.entries({
743
- ...envVars,
744
- NODE_ENV: nodeEnv,
745
- PATH: pathDirs.join(":"),
746
- // Bound the worker's pooler footprint. The worker is mostly idle (HTTP
747
- // long-poll); an UNPINNED pool plus the previously-missing single-instance
748
- // guard let an orphaned fleet of agents each hold a pool and saturate
749
- // Supavisor's 200-client cap. A small pool + short idle timeout releases
750
- // sessions promptly. Pool-exhaustion RCA 2026-06-21.
751
- PG_POOL_MAX: envVars.PG_POOL_MAX ?? "3",
752
- PG_IDLE_TIMEOUT: envVars.PG_IDLE_TIMEOUT ?? "10"
753
- }).map(([k, v]) => ` <key>${escapeXml(k)}</key>
754
- <string>${escapeXml(v)}</string>`).join("\n");
755
- 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"?>
756
78
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
757
79
  <plist version="1.0">
758
80
  <dict>
759
81
  <key>Label</key>
760
- <string>${WORKER_PLIST_LABEL}</string>
82
+ <string>${X}</string>
761
83
 
762
84
  <key>ProgramArguments</key>
763
85
  <array>
764
- <string>${escapeXml(nodePath)}</string>
765
- <string>${escapeXml(cliBin)}</string>
86
+ <string>${l(i)}</string>
87
+ <string>${l(t)}</string>
766
88
  <string>evals</string>
767
89
  <string>agent</string>
768
90
  </array>
769
91
 
770
92
  <key>WorkingDirectory</key>
771
- <string>${escapeXml(workingDir)}</string>
93
+ <string>${l(s)}</string>
772
94
 
773
95
  <key>EnvironmentVariables</key>
774
96
  <dict>
775
- ${envEntries}
97
+ ${u}
776
98
  </dict>
777
99
 
778
100
  <key>RunAtLoad</key>
@@ -789,58 +111,40 @@ ${envEntries}
789
111
 
790
112
  <key>WatchPaths</key>
791
113
  <array>
792
- <string>${escapeXml(cliDist)}</string>
114
+ <string>${l(e)}</string>
793
115
  </array>
794
116
 
795
117
  <key>StandardOutPath</key>
796
- <string>${escapeXml(join(LOG_DIR, "worker-stdout.log"))}</string>
118
+ <string>${l(o(p,"worker-stdout.log"))}</string>
797
119
 
798
120
  <key>StandardErrorPath</key>
799
- <string>${escapeXml(join(LOG_DIR, "worker-stderr.log"))}</string>
121
+ <string>${l(o(p,"worker-stderr.log"))}</string>
800
122
 
801
123
  <key>ProcessType</key>
802
124
  <string>Background</string>
803
125
  </dict>
804
126
  </plist>
805
- `;
806
- }
807
- // CONNECT-proxy router that fronts mitmproxy on :8787. Always-on so
808
- // .claude/settings.json's HTTPS_PROXY pointer never resolves to a dead
809
- // socket (which would break Claude Code entirely — see CLAUDE.md).
810
- // NOT watched on rebuild: bouncing the gateway mid-request would drop
811
- // in-flight streaming responses. Gateway code changes rarely; on
812
- // upgrade, the user can `launchctl kickstart gui/<uid>/com.rulemetric.gateway`.
813
- buildGatewayPlist(opts) {
814
- const { projectRoot, nodePath } = opts;
815
- const gatewayEntry = join(projectRoot, "apps", "cli", "dist", "lib", "gateway-entry.js");
816
- const cliBin = join(projectRoot, "apps", "cli", "bin", "run.js");
817
- const pathDirs = [.../* @__PURE__ */ new Set([dirname(nodePath), "/usr/local/bin", "/usr/bin", "/bin"])];
818
- const env = {
819
- RULEMETRIC_CLI_VERSION: this.config.version,
820
- RULEMETRIC_CLI_ENTRY: cliBin,
821
- PATH: pathDirs.join(":")
822
- };
823
- const envEntries = Object.entries(env).map(([k, v]) => ` <key>${escapeXml(k)}</key>
824
- <string>${escapeXml(v)}</string>`).join("\n");
825
- 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"?>
826
130
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
827
131
  <plist version="1.0">
828
132
  <dict>
829
133
  <key>Label</key>
830
- <string>${GATEWAY_PLIST_LABEL}</string>
134
+ <string>${F}</string>
831
135
 
832
136
  <key>ProgramArguments</key>
833
137
  <array>
834
- <string>${escapeXml(nodePath)}</string>
835
- <string>${escapeXml(gatewayEntry)}</string>
138
+ <string>${l(e)}</string>
139
+ <string>${l(s)}</string>
836
140
  </array>
837
141
 
838
142
  <key>WorkingDirectory</key>
839
- <string>${escapeXml(projectRoot)}</string>
143
+ <string>${l(t)}</string>
840
144
 
841
145
  <key>EnvironmentVariables</key>
842
146
  <dict>
843
- ${envEntries}
147
+ ${c}
844
148
  </dict>
845
149
 
846
150
  <key>RunAtLoad</key>
@@ -856,58 +160,41 @@ ${envEntries}
856
160
  <integer>10</integer>
857
161
 
858
162
  <key>StandardOutPath</key>
859
- <string>${escapeXml(join(LOG_DIR, "gateway-stdout.log"))}</string>
163
+ <string>${l(o(p,"gateway-stdout.log"))}</string>
860
164
 
861
165
  <key>StandardErrorPath</key>
862
- <string>${escapeXml(join(LOG_DIR, "gateway-stderr.log"))}</string>
166
+ <string>${l(o(p,"gateway-stderr.log"))}</string>
863
167
 
864
168
  <key>ProcessType</key>
865
169
  <string>Background</string>
866
170
  </dict>
867
171
  </plist>
868
- `;
869
- }
870
- // mitmproxy with the RuleMetric capture addon. Same invocation as
871
- // `rulemetric proxy start` (see commands/proxy/start.ts:308) so the
872
- // launchd path and the CLI path are interchangeable. We don't WatchPath
873
- // the Python addon — mitmdump has its own addon reload that handles
874
- // edits without a full process restart.
875
- buildProxyPlist(opts) {
876
- const { projectRoot, mitmdumpPath, envVars } = opts;
877
- const addonPath = join(projectRoot, "packages", "proxy", "addon", "rulemetric_addon.py");
878
- const pathDirs = [.../* @__PURE__ */ new Set([dirname(mitmdumpPath), "/usr/local/bin", "/usr/bin", "/bin"])];
879
- const env = {
880
- ...envVars,
881
- RULEMETRIC_PROJECT_PATH: projectRoot,
882
- RULEMETRIC_CLI_VERSION: this.config.version,
883
- PATH: pathDirs.join(":")
884
- };
885
- const envEntries = Object.entries(env).map(([k, v]) => ` <key>${escapeXml(k)}</key>
886
- <string>${escapeXml(v)}</string>`).join("\n");
887
- 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"?>
888
175
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
889
176
  <plist version="1.0">
890
177
  <dict>
891
178
  <key>Label</key>
892
- <string>${PROXY_PLIST_LABEL}</string>
179
+ <string>${J}</string>
893
180
 
894
181
  <key>ProgramArguments</key>
895
182
  <array>
896
- <string>${escapeXml(mitmdumpPath)}</string>
183
+ <string>${l(e)}</string>
897
184
  <string>--listen-port</string>
898
- <string>${PROXY_PORT}</string>
185
+ <string>${V}</string>
899
186
  <string>-s</string>
900
- <string>${escapeXml(addonPath)}</string>
187
+ <string>${l(i)}</string>
901
188
  <string>--set</string>
902
189
  <string>console_eventlog_verbosity=info</string>
903
190
  </array>
904
191
 
905
192
  <key>WorkingDirectory</key>
906
- <string>${escapeXml(projectRoot)}</string>
193
+ <string>${l(t)}</string>
907
194
 
908
195
  <key>EnvironmentVariables</key>
909
196
  <dict>
910
- ${envEntries}
197
+ ${c}
911
198
  </dict>
912
199
 
913
200
  <key>RunAtLoad</key>
@@ -923,39 +210,13 @@ ${envEntries}
923
210
  <integer>15</integer>
924
211
 
925
212
  <key>StandardOutPath</key>
926
- <string>${escapeXml(join(LOG_DIR, "proxy-stdout.log"))}</string>
213
+ <string>${l(o(p,"proxy-stdout.log"))}</string>
927
214
 
928
215
  <key>StandardErrorPath</key>
929
- <string>${escapeXml(join(LOG_DIR, "proxy-stderr.log"))}</string>
216
+ <string>${l(o(p,"proxy-stderr.log"))}</string>
930
217
 
931
218
  <key>ProcessType</key>
932
219
  <string>Background</string>
933
220
  </dict>
934
221
  </plist>
935
- `;
936
- }
937
- async waitForApi(port, timeoutSecs) {
938
- let lastError = null;
939
- for (let i = 0; i < timeoutSecs; i++) {
940
- try {
941
- const res = await fetch(`http://localhost:${port}/health`);
942
- if (res.ok) return true;
943
- lastError = `health check returned ${res.status}`;
944
- } catch (err) {
945
- lastError = err.message;
946
- }
947
- await new Promise((r) => setTimeout(r, 1e3));
948
- }
949
- if (lastError) {
950
- this.warn(`Last health check error: ${lastError}`);
951
- }
952
- return false;
953
- }
954
- };
955
- function escapeXml(s) {
956
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
957
- }
958
- export {
959
- ServiceInstall as default
960
- };
961
- //# 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};