@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,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/lib/hooks-config.ts"],
4
- "sourcesContent": ["import { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, copyFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, dirname } from 'node:path';\nimport { removeStatuslineShimAnyHome } from './statusline-shim.js';\n\nexport type DetectedTool = 'claude_code' | 'cursor' | 'copilot_agent' | 'antigravity';\n\n/**\n * Detect which AI coding tools are installed in the project by checking\n * for their config directories.\n */\nexport function detectInstalledTools(projectPath: string): DetectedTool[] {\n const tools: DetectedTool[] = ['claude_code'];\n\n if (existsSync(join(projectPath, '.cursor'))) {\n tools.push('cursor');\n }\n\n if (existsSync(join(projectPath, '.github'))) {\n tools.push('copilot_agent');\n }\n\n // Antigravity's workspace config lives at `.agents/`. The user-level hooks\n // file at ~/.gemini/config/hooks.json is written by writeAntigravityUserHooks()\n // ONLY when ~/.gemini already exists (the tool is present) \u2014 see F2.\n if (existsSync(join(projectPath, '.agents'))) {\n tools.push('antigravity');\n }\n\n return tools;\n}\n\n/**\n * Generate Cursor hooks config object.\n *\n * Cursor uses event names like beforeSubmitPrompt, afterFileEdit, etc.\n * Each event maps to an array of hook objects with a `command` field.\n */\nexport function generateCursorHooksConfig(binDir?: string): object {\n // Event coverage matches Cursor 1.7+ hook API (cursor.com/docs/hooks).\n // `sessionStart` is required so the registry file is written with\n // conversation_id before any tool runs; without it the proxy-based linker\n // path would have nothing to map and we'd drop captures. `sessionEnd`\n // emits the session-end signal once per chat conversation (vs `stop`\n // which fires per-turn \u2014 those go through post-tool-use).\n //\n // binDir: prepended to PATH like the Claude Code hooks \u2014 Cursor is a GUI app\n // launched with launchd's minimal PATH (no nvm/pnpm-global bin), so a bare\n // `rulemetric` silently fails with command-not-found.\n const prefix = binDir ? `PATH=\"${binDir}:$PATH\" ` : '';\n const cmd = (name: string) => ({ command: `${prefix}rulemetric hooks run ${name}` });\n return {\n version: 1,\n hooks: {\n sessionStart: [cmd('session-start')],\n beforeSubmitPrompt: [cmd('user-prompt')],\n afterFileEdit: [cmd('post-tool-use')],\n beforeShellExecution: [cmd('post-tool-use')],\n afterShellExecution: [cmd('post-tool-use')],\n beforeMCPExecution: [cmd('post-tool-use')],\n afterMCPExecution: [cmd('post-tool-use')],\n // `afterAgentResponse` carries the full assistant response text +\n // token usage. Verified empirically via a probe hook on\n // 2026-05-12 \u2014 Cursor passes `text`, `input_tokens`,\n // `output_tokens`, `cache_read_tokens`, `cache_write_tokens`. This\n // is the cleanest path to per-turn assistant content for Cursor\n // (chat traffic itself bypasses the proxy via HTTP/2 \u2014 see\n // docs/audits/2026-05-11-cursor-capture-architecture.md).\n afterAgentResponse: [cmd('assistant-response')],\n // `stop` fires when the agent loop ends for a single turn (status:\n // completed|aborted|error). Per-turn, NOT per-session \u2014 route it to\n // post-tool-use, not session-end. The real session boundary is\n // `sessionEnd` below.\n stop: [cmd('post-tool-use')],\n sessionEnd: [cmd('session-end')],\n },\n };\n}\n\n/**\n * Generate Copilot Agent hooks config object.\n *\n * Copilot uses event names like sessionStart, userPromptSubmitted, etc.\n * Each event maps to an array of hook objects with `type` and `bash` fields.\n */\nexport function generateCopilotHooksConfig(binDir?: string): object {\n // binDir prepended to PATH \u2014 Copilot Agent runs in the same GUI/minimal-PATH\n // environment class as Cursor, so a bare `rulemetric` silently fails.\n const prefix = binDir ? `PATH=\"${binDir}:$PATH\" ` : '';\n const cmd = (name: string) => ({ type: 'command', bash: `${prefix}rulemetric hooks run ${name}` });\n return {\n version: 1,\n hooks: {\n sessionStart: [cmd('session-start')],\n userPromptSubmitted: [cmd('user-prompt')],\n postToolUse: [cmd('post-tool-use')],\n sessionEnd: [cmd('session-end')],\n },\n };\n}\n\ninterface ClaudeHookEntry {\n type: 'command';\n command: string;\n}\n\ninterface ClaudeHookBlock {\n matcher?: string;\n hooks: ClaudeHookEntry[];\n}\n\n/** The `settings.hooks` map RuleMetric installs into a project's `.claude/settings.json`. */\nexport type ClaudeCodeHooksConfig = Record<\n 'SessionStart' | 'UserPromptSubmit' | 'PostToolUse' | 'Stop' | 'SessionEnd',\n ClaudeHookBlock[]\n>;\n\n/**\n * Generate the Claude Code hooks map for `.claude/settings.json`.\n *\n * Claude Code keys hook blocks by native event name, each block being\n * `{ matcher?, hooks: [{ type: 'command', command }] }`. Unlike Antigravity\n * these carry NO `RULEMETRIC_HOOK_TOOL` prefix \u2014 `_normalize.sh` defaults to\n * the `claude_code` branch (session_id + transcript_path payload shape).\n *\n * This is the hooks-first, zero-proxy capture path: SessionEnd runs\n * `session-end.sh`, which reimports the whole transcript via\n * `POST /api/sessions/:id/reimport` \u2014 no mitmproxy / CA trust / gateway needed.\n * The rendered system prompt is still proxy-only, so instruction-effectiveness\n * linking is handled separately (Phase 2 synthetic snapshot).\n */\nexport function generateClaudeCodeHooksConfig(binDir?: string): ClaudeCodeHooksConfig {\n // The literal `rulemetric` is always present: it's the marker that install.ts\n // \u00A71 and mergeClaudeCodeHooks use to dedup/strip our hooks (a resolved\n // node+run.js path omits 'rulemetric' in a dev checkout, which would silently\n // break that dedup).\n //\n // `binDir`, when provided, is prepended to PATH so the command resolves even\n // in Claude Code's hook shell \u2014 which runs `/bin/sh -c` with a minimal PATH\n // that does NOT include nvm/pnpm global bin dirs. Without it, a fresh-install\n // user hits `rulemetric: command not found` on every hook, so capture (and\n // the session-start gateway auto-start that keeps the proxy alive) silently\n // fails. Callers resolve the real bin dir at install time and pass it here.\n const prefix = binDir ? `PATH=\"${binDir}:$PATH\" ` : '';\n const mk = (name: string): ClaudeHookEntry => ({\n type: 'command',\n command: `${prefix}rulemetric hooks run ${name}`,\n });\n return {\n SessionStart: [{ hooks: [mk('session-start')] }],\n UserPromptSubmit: [{ hooks: [mk('user-prompt')] }],\n PostToolUse: [{ matcher: '.*', hooks: [mk('post-tool-use')] }],\n Stop: [{ hooks: [mk('assistant-response')] }],\n SessionEnd: [{ hooks: [mk('session-end')] }],\n };\n}\n\n/**\n * Read a Claude Code `settings.json` for merging, WITHOUT ever crashing the\n * install on a fresh machine. A missing file yields `{}`. A malformed file\n * (hand-edited JSONC, a stray trailing comma, a half-written file) is NOT\n * allowed to throw \u2014 that used to hard-fail `hooks install` with a raw\n * SyntaxError and leave the user with NO capture. Instead we back the\n * unparseable file up (so nothing is silently lost) and proceed on a fresh\n * object so capture still installs.\n *\n * Returns the parsed settings plus `recoveredBackup`: the path the corrupt\n * original was copied to, or `null` when the file was absent/valid.\n */\nexport function readClaudeSettings(configPath: string): {\n settings: Record<string, unknown>;\n recoveredBackup: string | null;\n} {\n if (!existsSync(configPath)) return { settings: {}, recoveredBackup: null };\n const raw = readFileSync(configPath, 'utf-8');\n try {\n return { settings: JSON.parse(raw) as Record<string, unknown>, recoveredBackup: null };\n } catch {\n const recoveredBackup = `${configPath}.corrupt.bak`;\n writeFileSync(recoveredBackup, raw);\n return { settings: {}, recoveredBackup };\n }\n}\n\n/**\n * Write a Claude Code `settings.json`, backing up any prior file first so the\n * change is reversible: the `.bak` holds the previous contents for the user to\n * restore manually if a merge ever goes wrong. Creates the parent dir as needed.\n * Returns `backupPath` (the `.bak` written) or `null` when there was no\n * pre-existing file to back up.\n */\nexport function writeClaudeSettingsWithBackup(\n configPath: string,\n settings: Record<string, unknown>,\n): { backupPath: string | null } {\n mkdirSync(dirname(configPath), { recursive: true });\n let backupPath: string | null = null;\n if (existsSync(configPath)) {\n backupPath = `${configPath}.bak`;\n copyFileSync(configPath, backupPath);\n }\n writeFileSync(configPath, JSON.stringify(settings, null, 2) + '\\n');\n return { backupPath };\n}\n\n/**\n * Read a JSON config file for a safe in-place merge. Returns `{}` when the file\n * is absent, the parsed object when it's valid, and `null` when it EXISTS but is\n * unparseable \u2014 in which case the original is first backed up to `.corrupt.bak`.\n * Callers MUST treat `null` as \"skip, do not write\": editor settings.json files\n * are JSONC (comments + trailing commas are legal and common), so a strict\n * JSON.parse throws on valid user files; blindly resetting to `{}` and writing\n * would clobber the user's ENTIRE editor config down to our few keys. Backing up\n * + skipping is the non-destructive floor (mirrors readClaudeSettings).\n */\nfunction readMergeableJson(configPath: string): Record<string, unknown> | null {\n if (!existsSync(configPath)) return {};\n const raw = readFileSync(configPath, 'utf-8');\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n try {\n writeFileSync(`${configPath}.corrupt.bak`, raw);\n } catch {\n /* best-effort backup */\n }\n return null;\n }\n}\n\n/**\n * Merge RuleMetric's Claude Code hooks into an in-memory `.claude/settings.json`\n * object. Claude Code hooks share the same settings.json that install.ts reads,\n * strips (\u00A71), and writes (\u00A75), so this mutates `settings.hooks` in place rather\n * than doing its own file I/O. Idempotent + non-destructive: per event it skips\n * adding when a rulemetric command is already present and otherwise appends,\n * preserving the user's own hooks.\n */\nexport function mergeClaudeCodeHooks(settings: Record<string, unknown>, binDir?: string): void {\n const generated = generateClaudeCodeHooksConfig(binDir);\n const hooks = (settings.hooks ?? {}) as Record<string, ClaudeHookBlock[]>;\n for (const [event, blocks] of Object.entries(generated)) {\n const current = (hooks[event] ?? []) as ClaudeHookBlock[];\n const alreadyPresent = current.some((b) =>\n b?.hooks?.some((h) => typeof h?.command === 'string' && h.command.includes('rulemetric')),\n );\n if (!alreadyPresent) {\n hooks[event] = [...current, ...blocks];\n }\n }\n settings.hooks = hooks;\n}\n\n/**\n * True iff RuleMetric's Claude Code session hooks are present in a settings\n * object \u2014 i.e. capture is actually wired up. This is the honest readiness\n * signal for the onboarding hooks step: capture works when the hooks exist,\n * NOT merely because a proxy env var was written (which greened even when the\n * proxy pointed at a dead port \u2014 the fresh-laptop ConnectionRefused footgun).\n */\nexport function hasRulemetricClaudeHooks(settings: Record<string, unknown>): boolean {\n if (!settings.hooks || typeof settings.hooks !== 'object') return false;\n const hooks = settings.hooks as Record<string, ClaudeHookBlock[]>;\n return Object.values(hooks).some(\n (blocks) =>\n Array.isArray(blocks) &&\n blocks.some((b) =>\n b?.hooks?.some((h) => typeof h?.command === 'string' && h.command.includes('rulemetric')),\n ),\n );\n}\n\n/**\n * Strip RuleMetric's Claude Code hooks from an in-memory settings object while\n * preserving the user's own hook entries. Mirrors install.ts \u00A71 but is reusable\n * for uninstall. Removes emptied event arrays and deletes `settings.hooks` if it\n * ends up empty. Returns true iff anything was removed.\n */\nexport function removeClaudeCodeHooks(settings: Record<string, unknown>): boolean {\n if (!settings.hooks || typeof settings.hooks !== 'object') return false;\n const hooks = settings.hooks as Record<string, ClaudeHookBlock[]>;\n let removed = 0;\n for (const event of Object.keys(hooks)) {\n const entries = hooks[event];\n if (!Array.isArray(entries)) continue;\n const kept = entries.filter((block) => {\n const isRulemetric = block?.hooks?.some(\n (h) => typeof h?.command === 'string' && h.command.includes('rulemetric'),\n );\n if (isRulemetric) removed += 1;\n return !isRulemetric;\n });\n if (kept.length === 0) delete hooks[event];\n else hooks[event] = kept;\n }\n if (Object.keys(hooks).length === 0) delete settings.hooks;\n return removed > 0;\n}\n\n// ---------------------------------------------------------------------------\n// Machine-local Claude Code settings (settings.local.json) + shared-file healing\n// ---------------------------------------------------------------------------\n\n/** The NO_PROXY value `hooks install` writes alongside HTTPS_PROXY. */\nexport const RULEMETRIC_NO_PROXY = 'localhost,127.0.0.1,*.supabase.co,*.supabase.in';\n\n/**\n * The settings file `hooks install` owns for RuleMetric's machine-local state.\n * Project installs write `settings.local.json`: the shared `settings.json` is\n * typically checked into git, and everything we write is machine-local by\n * nature \u2014 hook commands carry a per-user PATH prefix, and the proxy env pins\n * HTTPS_PROXY + a per-user CA path that BREAK Claude Code's HTTPS on any clone\n * without a live gateway on that port. Claude Code merges settings.local.json\n * on top of settings.json, runs hooks from both, and auto-gitignores the local\n * file. Global installs keep writing `~/.claude/settings.json` \u2014 the home file\n * is not in a repo, so machine-local state is safe there.\n */\nexport function claudeSettingsInstallPath(configDir: string, isGlobal: boolean): string {\n return join(configDir, isGlobal ? 'settings.json' : 'settings.local.json');\n}\n\n/**\n * Remove the gateway proxy env keys `hooks install` writes, and ONLY those:\n * each key is deleted solely when its value is one RuleMetric itself produces,\n * so a user-owned corporate proxy / custom CA is never touched.\n * - HTTPS_PROXY: points at the local gateway port (localhost or 127.0.0.1)\n * - NO_PROXY: exactly RULEMETRIC_NO_PROXY\n * - NODE_EXTRA_CA_CERTS: the mitmproxy default CA path \u2014 suffix-matched, not\n * exact, because a shared file poisoned by a teammate's install carries\n * THEIR $HOME prefix\n * Drops the `env` block entirely when the removal empties it. Returns true iff\n * anything was removed.\n */\nexport function removeRulemetricProxyEnv(\n settings: Record<string, unknown>,\n gatewayPort: number,\n): boolean {\n const env = settings.env as Record<string, unknown> | undefined;\n if (!env || typeof env !== 'object') return false;\n let removed = false;\n const proxy = env.HTTPS_PROXY;\n if (proxy === `http://localhost:${gatewayPort}` || proxy === `http://127.0.0.1:${gatewayPort}`) {\n delete env.HTTPS_PROXY;\n removed = true;\n }\n if (env.NO_PROXY === RULEMETRIC_NO_PROXY) {\n delete env.NO_PROXY;\n removed = true;\n }\n const ca = env.NODE_EXTRA_CA_CERTS;\n if (typeof ca === 'string' && ca.includes('.mitmproxy') && ca.endsWith('mitmproxy-ca-cert.pem')) {\n delete env.NODE_EXTRA_CA_CERTS;\n removed = true;\n }\n if (removed && Object.keys(env).length === 0) delete settings.env;\n return removed;\n}\n\nexport interface RulemetricStateRemoval {\n removedHooks: boolean;\n removedProxyEnv: boolean;\n removedStatusline: boolean;\n /** True iff any of the three categories removed something. */\n removed: boolean;\n}\n\n/**\n * Strip ALL RuleMetric-owned machine-local state from an in-memory settings\n * object: session hooks, gateway proxy env keys, and the statusline shim. Each\n * remover has its own user-preserving predicate, so anything the user owns\n * survives untouched. Shared by uninstall and the shared-file migration.\n */\nexport function removeRulemetricMachineState(\n settings: Record<string, unknown>,\n gatewayPort: number,\n): RulemetricStateRemoval {\n const removedHooks = removeClaudeCodeHooks(settings);\n const removedProxyEnv = removeRulemetricProxyEnv(settings, gatewayPort);\n const removedStatusline = removeStatuslineShimAnyHome(settings);\n return {\n removedHooks,\n removedProxyEnv,\n removedStatusline,\n removed: removedHooks || removedProxyEnv || removedStatusline,\n };\n}\n\nexport interface SharedSettingsMigration extends RulemetricStateRemoval {\n /** True iff something was removed and the file was rewritten. */\n migrated: boolean;\n backupPath: string | null;\n}\n\n/**\n * Heal a shared `.claude/settings.json` that an older `hooks install` (this\n * machine's or a teammate's) filled with machine-local state: PATH-prefixed,\n * username-leaking hook commands, the gateway proxy env keys (an HTTPS_PROXY\n * pin breaks Claude Code's HTTPS entirely on any clone without a live gateway\n * on that port), and the $HOME-anchored statusline shim. User-owned hooks/env/\n * statusLine are never touched. The file is rewritten (with the standard\n * backup) ONLY when something was actually removed; an unparseable file is\n * left exactly as-is \u2014 we cannot safely edit what we cannot parse.\n */\nexport function migrateSharedClaudeSettings(\n sharedPath: string,\n gatewayPort: number,\n): SharedSettingsMigration {\n const none: SharedSettingsMigration = {\n migrated: false,\n backupPath: null,\n removedHooks: false,\n removedProxyEnv: false,\n removedStatusline: false,\n removed: false,\n };\n if (!existsSync(sharedPath)) return none;\n let settings: Record<string, unknown>;\n try {\n settings = JSON.parse(readFileSync(sharedPath, 'utf-8')) as Record<string, unknown>;\n } catch {\n return none;\n }\n const removal = removeRulemetricMachineState(settings, gatewayPort);\n if (!removal.removed) return none;\n const { backupPath } = writeClaudeSettingsWithBackup(sharedPath, settings);\n return { ...removal, migrated: true, backupPath };\n}\n\nexport interface ClaudeSettingsCleanup extends RulemetricStateRemoval {\n configPath: string;\n /** `settings.json` or `settings.local.json` \u2014 for log lines. */\n fileName: string;\n recoveredBackup: string | null;\n /** True iff the file was rewritten. */\n changed: boolean;\n}\n\n/**\n * Remove all RuleMetric-owned state from BOTH Claude Code settings files in a\n * project: the shared `settings.json` (legacy installs wrote there) and\n * `settings.local.json` (where current installs put machine-local state). Each\n * file is rewritten (with backup) only when something was actually removed.\n * Returns one entry per file that exists, with per-category flags so the\n * caller can log precisely what was cleaned where.\n */\nexport function cleanClaudeSettingsFiles(\n claudeDir: string,\n gatewayPort: number,\n): ClaudeSettingsCleanup[] {\n const results: ClaudeSettingsCleanup[] = [];\n for (const fileName of ['settings.json', 'settings.local.json'] as const) {\n const configPath = join(claudeDir, fileName);\n if (!existsSync(configPath)) continue;\n const { settings, recoveredBackup } = readClaudeSettings(configPath);\n const removal = removeRulemetricMachineState(settings, gatewayPort);\n if (removal.removed) {\n writeClaudeSettingsWithBackup(configPath, settings);\n }\n results.push({\n ...removal,\n configPath,\n fileName,\n recoveredBackup,\n changed: removal.removed,\n });\n }\n return results;\n}\n\n/**\n * Merge rulemetric hooks into a Cursor `hooks.json` at the given directory.\n *\n * Used by both the project (`<repo>/.cursor/`) and user (`~/.cursor/`) writers.\n * Returns the config file path, or null if the cursor dir doesn't exist.\n */\nfunction writeCursorHooksToDir(cursorDir: string, binDir?: string): string | null {\n if (!existsSync(cursorDir)) {\n return null;\n }\n\n const configPath = join(cursorDir, 'hooks.json');\n const generated = generateCursorHooksConfig(binDir) as {\n version: number;\n hooks: Record<string, Array<{ command: string }>>;\n };\n\n const parsed = readMergeableJson(configPath);\n if (parsed === null) return null; // unparseable \u2014 backed up, don't drop sibling hooks\n const existing = parsed as { version?: number; hooks?: Record<string, unknown[]> };\n\n const merged: Record<string, unknown[]> = { ...(existing.hooks ?? {}) };\n\n const isRulemetricHook = (h: unknown): boolean =>\n typeof h === 'object' &&\n h !== null &&\n 'command' in h &&\n typeof (h as { command: string }).command === 'string' &&\n (h as { command: string }).command.includes('rulemetric');\n\n for (const [event, hooks] of Object.entries(generated.hooks)) {\n const current = merged[event] ?? [];\n // REPLACE prior rulemetric entries, never skip-if-present: a stale command\n // (old format, moved binary, outdated PATH prefix) must be repairable by\n // re-running `hooks install` \u2014 skip-if-present froze broken Cursor capture\n // forever. Sibling (non-rulemetric) hooks are preserved untouched.\n const siblings = current.filter((h: unknown) => !isRulemetricHook(h));\n merged[event] = [...siblings, ...hooks];\n }\n\n const result = {\n version: existing.version ?? generated.version,\n hooks: merged,\n };\n\n writeFileSync(configPath, JSON.stringify(result, null, 2) + '\\n');\n return configPath;\n}\n\n/**\n * Write Cursor hooks config to `<projectPath>/.cursor/hooks.json`.\n * Merges with existing config \u2014 appends rulemetric hooks without duplicating.\n * Returns the config file path, or null if `.cursor/` doesn't exist.\n */\nexport function writeCursorHooks(projectPath: string, binDir?: string): string | null {\n return writeCursorHooksToDir(join(projectPath, '.cursor'), binDir);\n}\n\n/**\n * Write Cursor hooks config to user-level `~/.cursor/hooks.json` so capture\n * works for every Cursor conversation without per-project setup.\n *\n * Returns the config file path, or null if `~/.cursor/` doesn't exist\n * (i.e., Cursor has never been launched on this machine).\n */\nexport function writeCursorUserHooks(binDir?: string, home: string = homedir()): string | null {\n // Only wire user-level Cursor hooks if Cursor is actually present \u2014 never\n // manufacture ~/.cursor for a user who doesn't use it (undisclosed scope,\n // onboarding field report 2026-07-07 F2). `home` is injectable for tests.\n const cursorHome = join(home, '.cursor');\n if (!existsSync(cursorHome)) return null;\n return writeCursorHooksToDir(cursorHome, binDir);\n}\n\n/**\n * Write Copilot Agent hooks config to `.github/hooks/rulemetric.json`.\n * Creates the hooks directory if needed.\n * Returns the config file path, or null if `.github/` doesn't exist.\n */\nexport function writeCopilotHooks(projectPath: string, binDir?: string): string | null {\n const githubDir = join(projectPath, '.github');\n if (!existsSync(githubDir)) {\n return null;\n }\n\n const hooksDir = join(githubDir, 'hooks');\n mkdirSync(hooksDir, { recursive: true });\n\n const configPath = join(hooksDir, 'rulemetric.json');\n const config = generateCopilotHooksConfig(binDir);\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n return configPath;\n}\n\n/**\n * Strip rulemetric hooks from a Cursor `hooks.json` at the given path.\n * Preserves other hooks and removes empty event arrays.\n * Returns true if changes were made.\n */\nfunction removeCursorHooksFromFile(configPath: string): boolean {\n if (!existsSync(configPath)) {\n return false;\n }\n\n let config: { version?: number; hooks?: Record<string, unknown[]> };\n try {\n config = JSON.parse(readFileSync(configPath, 'utf-8'));\n } catch {\n return false;\n }\n\n if (!config.hooks) {\n return false;\n }\n\n let changed = false;\n for (const [event, hooks] of Object.entries(config.hooks)) {\n const filtered = hooks.filter((h: unknown) => {\n if (typeof h !== 'object' || h === null || !('command' in h)) return true;\n const cmd = (h as { command: string }).command;\n if (typeof cmd === 'string' && cmd.includes('rulemetric')) {\n changed = true;\n return false;\n }\n return true;\n });\n\n if (filtered.length === 0) {\n delete config.hooks[event];\n } else {\n config.hooks[event] = filtered;\n }\n }\n\n if (changed) {\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n }\n\n return changed;\n}\n\n/**\n * Remove rulemetric hooks from `<projectPath>/.cursor/hooks.json`.\n */\nexport function removeCursorHooks(projectPath: string): boolean {\n return removeCursorHooksFromFile(join(projectPath, '.cursor', 'hooks.json'));\n}\n\n/**\n * Remove rulemetric hooks from user-level `~/.cursor/hooks.json`.\n */\nexport function removeCursorUserHooks(): boolean {\n return removeCursorHooksFromFile(join(homedir(), '.cursor', 'hooks.json'));\n}\n\n/**\n * Write Cursor proxy config to `.cursor/settings.json`.\n * Sets `http.proxy` and `http.proxyStrictSSL` while preserving existing settings.\n * Returns true if `.cursor/` exists and config was written, false otherwise.\n */\nexport function writeCursorProxyConfig(projectPath: string, gatewayPort: number, certPath: string): boolean {\n const cursorDir = join(projectPath, '.cursor');\n if (!existsSync(cursorDir)) return false;\n\n const settingsPath = join(cursorDir, 'settings.json');\n const settings = readMergeableJson(settingsPath);\n if (settings === null) return false; // unparseable JSONC \u2014 backed up, don't clobber\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = existsSync(certPath);\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Write VS Code proxy config to `.vscode/settings.json` for Copilot capture.\n * Sets `http.proxy`, `http.proxyStrictSSL`, and Copilot-specific override\n * while preserving existing settings.\n * Returns true if config was written, false if `.vscode/` doesn't exist.\n */\nexport function writeVSCodeProxyConfig(projectPath: string, gatewayPort: number, certPath: string): boolean {\n const vscodeDir = join(projectPath, '.vscode');\n // Only touch projects that already use VS Code \u2014 do NOT manufacture a\n // `.vscode/` in every repo (matches writeCursorProxyConfig's contract and this\n // function's own docstring). Creating it pollutes Claude-Code-only repos with\n // an untracked, proxy-pinning settings.json.\n if (!existsSync(vscodeDir)) return false;\n\n const settingsPath = join(vscodeDir, 'settings.json');\n const settings = readMergeableJson(settingsPath);\n if (settings === null) return false; // unparseable JSONC \u2014 backed up, don't clobber\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = existsSync(certPath);\n\n // Copilot-specific override for surgical proxy targeting\n const copilotAdvanced = (settings['github.copilot.advanced'] ?? {}) as Record<string, unknown>;\n copilotAdvanced['debug.overrideProxyUrl'] = `http://localhost:${gatewayPort}`;\n settings['github.copilot.advanced'] = copilotAdvanced;\n\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Remove VS Code proxy config from `.vscode/settings.json`.\n * Removes `http.proxy`, `http.proxyStrictSSL`, and Copilot proxy override.\n * Returns true if changes were made.\n */\nexport function removeVSCodeProxyConfig(projectPath: string): boolean {\n const settingsPath = join(projectPath, '.vscode', 'settings.json');\n if (!existsSync(settingsPath)) return false;\n\n let settings: Record<string, unknown>;\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { return false; }\n\n let changed = false;\n\n if (settings['http.proxy']) {\n delete settings['http.proxy'];\n delete settings['http.proxyStrictSSL'];\n changed = true;\n }\n\n const copilotAdvanced = settings['github.copilot.advanced'] as Record<string, unknown> | undefined;\n if (copilotAdvanced?.['debug.overrideProxyUrl']) {\n delete copilotAdvanced['debug.overrideProxyUrl'];\n if (Object.keys(copilotAdvanced).length === 0) {\n delete settings['github.copilot.advanced'];\n }\n changed = true;\n }\n\n if (changed) {\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n }\n\n return changed;\n}\n\n/**\n * Remove Copilot Agent hooks by deleting `.github/hooks/rulemetric.json`.\n * Returns true if the file was removed.\n */\nexport function removeCopilotHooks(projectPath: string): boolean {\n const configPath = join(projectPath, '.github', 'hooks', 'rulemetric.json');\n if (!existsSync(configPath)) {\n return false;\n }\n\n unlinkSync(configPath);\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// macOS LaunchAgent for GUI app env vars (HTTPS_PROXY, NODE_EXTRA_CA_CERTS)\n// ---------------------------------------------------------------------------\n\nconst LAUNCH_AGENT_LABEL = 'com.rulemetric.env';\n\nfunction getLaunchAgentPath(): string {\n return join(homedir(), 'Library', 'LaunchAgents', `${LAUNCH_AGENT_LABEL}.plist`);\n}\n\n/**\n * Set HTTPS_PROXY and NODE_EXTRA_CA_CERTS for all GUI apps on macOS.\n *\n * Two layers:\n * 1. `launchctl setenv` \u2014 immediate effect for newly launched apps\n * 2. LaunchAgent plist \u2014 persists across reboots\n *\n * This ensures VS Code / Copilot / Cursor route LLM traffic through the\n * gateway even when launched from Dock or Spotlight (not a terminal).\n *\n * References:\n * - anthropics/claude-code#30318 (same pattern for Claude Desktop)\n * - Snyk IDE docs recommend launchctl setenv for macOS\n * - Apple QA1067 (archived) \u2014 original env var mechanism removed in 10.10\n */\nexport function installMacOSProxyEnv(gatewayPort: number, certPath: string): boolean {\n if (process.platform !== 'darwin') return false;\n\n const proxyUrl = `http://localhost:${gatewayPort}`;\n\n // Layer 1: immediate effect via launchctl setenv\n try {\n execSync(`launchctl setenv HTTPS_PROXY ${proxyUrl}`, { stdio: 'pipe' });\n if (existsSync(certPath)) {\n execSync(`launchctl setenv NODE_EXTRA_CA_CERTS ${certPath}`, { stdio: 'pipe' });\n }\n } catch {\n return false;\n }\n\n // Layer 2: LaunchAgent plist for persistence across reboots\n const plistPath = getLaunchAgentPath();\n const agentsDir = join(homedir(), 'Library', 'LaunchAgents');\n mkdirSync(agentsDir, { recursive: true });\n\n const certLine = existsSync(certPath)\n ? `launchctl setenv NODE_EXTRA_CA_CERTS ${certPath};`\n : '';\n\n // LIVENESS-GUARDED boot command: at every login this re-pins HTTPS_PROXY\n // machine-wide, but the gateway on :8787 is not a supervised service on the\n // end-user path \u2014 it dies on logout and nothing restarts it. Pinning a dead\n // port breaks HTTPS for every GUI app. So probe :8787 first and only setenv\n // when the gateway actually answers; otherwise clear it (the session-start\n // hook will re-pin once Claude Code brings the gateway back up).\n const bootCmd =\n `if nc -z -w 1 127.0.0.1 ${gatewayPort} 2>/dev/null; then ` +\n `launchctl setenv HTTPS_PROXY ${proxyUrl};${certLine} ` +\n `else launchctl unsetenv HTTPS_PROXY; launchctl unsetenv NODE_EXTRA_CA_CERTS; fi`;\n\n const plist = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"\n \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${LAUNCH_AGENT_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>/bin/sh</string>\n <string>-c</string>\n <string>${bootCmd}</string>\n </array>\n <key>RunAtLoad</key>\n <true/>\n</dict>\n</plist>\n`;\n\n writeFileSync(plistPath, plist);\n return true;\n}\n\n/**\n * Remove the RuleMetric LaunchAgent and unset env vars.\n */\nexport function uninstallMacOSProxyEnv(): boolean {\n if (process.platform !== 'darwin') return false;\n\n let changed = false;\n\n // Unset env vars for current session\n try {\n execSync('launchctl unsetenv HTTPS_PROXY', { stdio: 'pipe' });\n execSync('launchctl unsetenv NODE_EXTRA_CA_CERTS', { stdio: 'pipe' });\n } catch { /* may not be set */ }\n\n // Remove LaunchAgent plist\n const plistPath = getLaunchAgentPath();\n if (existsSync(plistPath)) {\n unlinkSync(plistPath);\n changed = true;\n }\n\n return changed;\n}\n\n// ---------------------------------------------------------------------------\n// VS Code user-level proxy settings\n// ---------------------------------------------------------------------------\n\nexport function getVSCodeUserSettingsPath(): string {\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Application Support', 'Code', 'User', 'settings.json');\n }\n if (process.platform === 'win32') {\n return join(process.env.APPDATA ?? '', 'Code', 'User', 'settings.json');\n }\n return join(homedir(), '.config', 'Code', 'User', 'settings.json');\n}\n\n/**\n * Set http.proxy in VS Code user settings (not workspace).\n *\n * Workspace-level http.proxy is silently ignored because VS Code restricts\n * it to APPLICATION scope (microsoft/vscode#236932). User-level settings\n * are the only reliable way to configure http.proxy.\n */\nexport function writeVSCodeUserProxyConfig(gatewayPort: number): boolean {\n const settingsPath = getVSCodeUserSettingsPath();\n if (!existsSync(join(settingsPath, '..'))) return false;\n\n const settings = readMergeableJson(settingsPath);\n if (settings === null) return false; // unparseable JSONC \u2014 backed up, don't clobber user config\n\n // Only set if not already configured by the user\n if (settings['http.proxy'] && !(settings['http.proxy'] as string).includes('localhost')) {\n return false; // user has a custom proxy, don't overwrite\n }\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = false;\n\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Remove RuleMetric proxy config from VS Code user settings.\n */\nexport function removeVSCodeUserProxyConfig(): boolean {\n const settingsPath = getVSCodeUserSettingsPath();\n if (!existsSync(settingsPath)) return false;\n\n let settings: Record<string, unknown>;\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { return false; }\n\n const proxy = settings['http.proxy'] as string | undefined;\n if (!proxy?.includes('localhost')) return false;\n\n delete settings['http.proxy'];\n delete settings['http.proxyStrictSSL'];\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Cursor user-level proxy settings\n// ---------------------------------------------------------------------------\n//\n// Cursor is a VS Code fork and uses the same settings.json shape, but reads\n// from `Cursor/User/settings.json` instead of `Code/User/settings.json`. The\n// `.cursor/settings.json` (workspace) path can't reach Cursor's Electron main\n// process for the same reason VS Code's workspace path can't reach VS Code's\n// \u2014 the http.proxy setting is restricted to APPLICATION scope and only the\n// user-level file is honored.\n\nexport function getCursorUserSettingsPath(): string {\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Application Support', 'Cursor', 'User', 'settings.json');\n }\n if (process.platform === 'win32') {\n return join(process.env.APPDATA ?? '', 'Cursor', 'User', 'settings.json');\n }\n return join(homedir(), '.config', 'Cursor', 'User', 'settings.json');\n}\n\n/**\n * Set http.proxy in Cursor user settings (not workspace). Mirrors\n * `writeVSCodeUserProxyConfig` \u2014 workspace-level http.proxy is silently\n * ignored due to APPLICATION-scope restriction (Cursor inherits this from\n * VS Code, see microsoft/vscode#236932).\n *\n * Returns true if config was written, false if Cursor isn't installed\n * (User dir absent) or the user already has a non-localhost proxy set.\n */\nexport function writeCursorUserProxyConfig(gatewayPort: number): boolean {\n const settingsPath = getCursorUserSettingsPath();\n if (!existsSync(join(settingsPath, '..'))) return false;\n\n const settings = readMergeableJson(settingsPath);\n if (settings === null) return false; // unparseable JSONC \u2014 backed up, don't clobber user config\n\n if (settings['http.proxy'] && !(settings['http.proxy'] as string).includes('localhost')) {\n return false;\n }\n\n settings['http.proxy'] = `http://localhost:${gatewayPort}`;\n settings['http.proxyStrictSSL'] = false;\n\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n/**\n * Remove RuleMetric proxy config from Cursor user settings.\n */\nexport function removeCursorUserProxyConfig(): boolean {\n const settingsPath = getCursorUserSettingsPath();\n if (!existsSync(settingsPath)) return false;\n\n let settings: Record<string, unknown>;\n try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { return false; }\n\n const proxy = settings['http.proxy'] as string | undefined;\n if (!proxy?.includes('localhost')) return false;\n\n delete settings['http.proxy'];\n delete settings['http.proxyStrictSSL'];\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n return true;\n}\n\n// \u2500\u2500\u2500 Antigravity (Google's Gemini-based agentic IDE) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Antigravity hooks live in `.agents/hooks.json` (workspace) and\n// `~/.gemini/config/hooks.json` (user-level). Events follow the\n// SessionStart / UserPromptSubmit / PreToolUse / PostToolUse / Stop /\n// SessionEnd vocabulary. Each hook command sets `RULEMETRIC_HOOK_TOOL=\n// antigravity` so `_normalize.sh` routes through the Antigravity branch.\n\ninterface AntigravityHookEntry {\n type: 'command';\n command: string;\n timeout?: number;\n}\n\ninterface AntigravityHookBlock {\n matcher?: string;\n hooks: AntigravityHookEntry[];\n}\n\ninterface AntigravityRuleMetricBlock {\n enabled: boolean;\n SessionStart: AntigravityHookBlock[];\n UserPromptSubmit: AntigravityHookBlock[];\n PreToolUse: AntigravityHookBlock[];\n PostToolUse: AntigravityHookBlock[];\n Stop: AntigravityHookBlock[];\n SessionEnd: AntigravityHookBlock[];\n}\n\nexport type AntigravityHooksConfig = { rulemetric: AntigravityRuleMetricBlock };\n\n/** Resolve the binary string to invoke for a hook command. */\nfunction getRulemetricCommand(): string {\n // Prefer the local Node binary + bin/run.js so the hook works even when\n // `rulemetric` isn't on PATH for the GUI Antigravity process.\n const nodeBin = process.execPath;\n // bin/run.js lives next to dist/ in the installed CLI; resolve from\n // import.meta isn't available in a portable way here, so we use the\n // process argv1 if it's pointing at the CLI entry, else fall back to\n // the bare command name. In practice this function is called inside\n // `rulemetric hooks install`, where process.argv[1] is bin/run.js.\n const cliEntry = process.argv[1];\n if (cliEntry && cliEntry.endsWith('run.js')) {\n return `${nodeBin} ${cliEntry}`;\n }\n return 'rulemetric';\n}\n\nexport function generateAntigravityHooksConfig(): AntigravityHooksConfig {\n const cmd = getRulemetricCommand();\n const mk = (name: string): AntigravityHookEntry => ({\n type: 'command',\n command: `RULEMETRIC_HOOK_TOOL=antigravity ${cmd} hooks run ${name}`,\n timeout: 30,\n });\n return {\n rulemetric: {\n enabled: true,\n SessionStart: [{ hooks: [mk('session-start')] }],\n UserPromptSubmit: [{ hooks: [mk('user-prompt')] }],\n PreToolUse: [{ matcher: '.*', hooks: [mk('post-tool-use')] }],\n PostToolUse: [{ matcher: '.*', hooks: [mk('post-tool-use')] }],\n Stop: [{ hooks: [mk('assistant-response')] }],\n SessionEnd: [{ hooks: [mk('session-end')] }],\n },\n };\n}\n\nfunction writeAntigravityHooksToDir(dir: string): string | null {\n const configPath = join(dir, 'hooks.json');\n const existing = readMergeableJson(configPath);\n if (existing === null) return null; // unparseable \u2014 backed up, don't drop sibling blocks\n const generated = generateAntigravityHooksConfig();\n // Antigravity keys hook blocks by name; RuleMetric owns its own block\n // and never touches sibling blocks the user may have added.\n const merged = { ...existing, rulemetric: generated.rulemetric };\n mkdirSync(dir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\\n');\n return configPath;\n}\n\nexport function writeAntigravityHooks(projectPath: string): string | null {\n return writeAntigravityHooksToDir(join(projectPath, '.agents'));\n}\n\nexport function writeAntigravityUserHooks(home: string = homedir()): string | null {\n // Only wire user-level Antigravity/Gemini hooks if the tool is actually\n // present \u2014 never manufacture ~/.gemini for a user who doesn't use it\n // (undisclosed scope, onboarding field report 2026-07-07 F2). `home` is\n // injectable for tests.\n const geminiHome = join(home, '.gemini');\n if (!existsSync(geminiHome)) return null;\n return writeAntigravityHooksToDir(join(geminiHome, 'config'));\n}\n\nfunction removeAntigravityHooksFromFile(configPath: string): boolean {\n if (!existsSync(configPath)) return false;\n let existing: Record<string, unknown>;\n try { existing = JSON.parse(readFileSync(configPath, 'utf-8')); } catch { return false; }\n if (!('rulemetric' in existing)) return false;\n delete existing.rulemetric;\n if (Object.keys(existing).length === 0) {\n // No other blocks \u2014 remove the file entirely.\n try { unlinkSync(configPath); } catch { /* ignore */ }\n } else {\n writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\\n');\n }\n return true;\n}\n\nexport function removeAntigravityHooks(projectPath: string): boolean {\n return removeAntigravityHooksFromFile(join(projectPath, '.agents', 'hooks.json'));\n}\n\nexport function removeAntigravityUserHooks(): boolean {\n const modern = removeAntigravityHooksFromFile(join(homedir(), '.gemini', 'config', 'hooks.json'));\n const legacy = removeAntigravityHooksFromFile(join(homedir(), '.gemini', 'hooks.json'));\n return modern || legacy;\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,17 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
-
13
- export {
14
- __require,
15
- __export
16
- };
17
- //# sourceMappingURL=chunk-NSBPE2FW.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,243 +0,0 @@
1
- import {
2
- AT_A_GLANCE_PROMPT,
3
- FACET_GENERATION_PROMPT,
4
- RECOMMENDATION_PROMPTS
5
- } from "./chunk-XZXS2W24.js";
6
- import {
7
- detectLlmBackend,
8
- runLlmPrompt,
9
- runToolPrompt
10
- } from "./chunk-FZKLLNDS.js";
11
- import {
12
- PermanentJobError
13
- } from "./chunk-DGHWRQXL.js";
14
- import {
15
- apiGet,
16
- apiPatch,
17
- apiPost
18
- } from "./chunk-ZUJBM6HE.js";
19
-
20
- // src/lib/handlers/process-insights.ts
21
- async function processInsights(payload, helpers) {
22
- const { mirrorId, projectPath, projectId, config } = payload;
23
- const log = (msg) => helpers.logger.info(msg);
24
- if (config?.sessionId) {
25
- return processSessionAnalysisInline({ mirrorId, sessionId: config.sessionId }, log);
26
- }
27
- log(`Processing insights job ${mirrorId}...`);
28
- await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {
29
- status: "running",
30
- progress: { step: "reading_data" }
31
- });
32
- try {
33
- const { repaired } = await apiPost(
34
- "/api/sessions/repair-analyzed-at",
35
- {}
36
- );
37
- if (repaired > 0) {
38
- log(` Repaired analyzed_at on ${repaired} orphan session(s).`);
39
- }
40
- } catch (repairErr) {
41
- log(` Warning: analyzed_at repair failed: ${repairErr instanceof Error ? repairErr.message : String(repairErr)}`);
42
- }
43
- const data = await buildDataSummaryFromApi(projectPath, projectId);
44
- if (!data) {
45
- throw new PermanentJobError(
46
- "No session data found \u2014 ensure sessions are captured and enriched."
47
- );
48
- }
49
- log(` Found ${data.stats.sessions} sessions, generating recommendations...`);
50
- const FACET_BATCH_SIZE = 20;
51
- const FACET_HARD_CAP = 200;
52
- if (detectLlmBackend() !== "none") {
53
- let totalFaceted = 0;
54
- try {
55
- while (totalFaceted < FACET_HARD_CAP) {
56
- const unfaceted = await apiGet(
57
- `/api/sessions?hasAnalysis=false&limit=${FACET_BATCH_SIZE}`
58
- );
59
- if (unfaceted.length === 0) break;
60
- log(` Generating facets for ${unfaceted.length} un-analyzed sessions (drained ${totalFaceted} so far)...`);
61
- for (const session of unfaceted) {
62
- if (totalFaceted >= FACET_HARD_CAP) break;
63
- try {
64
- const events = await apiGet(
65
- `/api/sessions/${session.id}/events?limit=100`
66
- );
67
- if (events.length < 2) {
68
- totalFaceted++;
69
- continue;
70
- }
71
- const eventSummary = events.filter((e) => e.eventType === "user_message" || e.eventType === "human").map((e) => e.content?.slice(0, 200) ?? "").filter(Boolean).join("\n---\n");
72
- if (!eventSummary) {
73
- totalFaceted++;
74
- continue;
75
- }
76
- const facets = await runLlmPrompt(FACET_GENERATION_PROMPT, eventSummary, 4096);
77
- if (facets) {
78
- const userMessageCount = events.filter(
79
- (e) => e.eventType === "user_message" || e.eventType === "human"
80
- ).length;
81
- await apiPatch(`/api/sessions/${session.id}/enrich`, {
82
- analysis: { source: "generated_facets", ...facets },
83
- analyzedEventCount: events.length,
84
- analyzedTurnCount: userMessageCount
85
- });
86
- log(` Generated facets for session ${session.id} (${session.tool})`);
87
- }
88
- totalFaceted++;
89
- } catch (sessionErr) {
90
- log(` Failed to generate facets for session ${session.id}: ${sessionErr instanceof Error ? sessionErr.message : String(sessionErr)}`);
91
- totalFaceted++;
92
- }
93
- }
94
- if (unfaceted.length < FACET_BATCH_SIZE) break;
95
- }
96
- } catch (facetErr) {
97
- log(` Warning: facet generation failed after ${totalFaceted} sessions: ${facetErr instanceof Error ? facetErr.message : String(facetErr)}`);
98
- }
99
- }
100
- const recommendations = {};
101
- const totalPrompts = RECOMMENDATION_PROMPTS.length + 1;
102
- for (let i = 0; i < RECOMMENDATION_PROMPTS.length; i++) {
103
- const spec = RECOMMENDATION_PROMPTS[i];
104
- log(` [${i + 1}/${totalPrompts}] Generating ${spec.name}...`);
105
- try {
106
- await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {
107
- status: "running",
108
- progress: {
109
- step: spec.name,
110
- current: i + 1,
111
- total: totalPrompts,
112
- partial: { ...recommendations }
113
- }
114
- });
115
- } catch (patchErr) {
116
- log(` Warning: progress update failed for ${spec.name}: ${patchErr instanceof Error ? patchErr.message : String(patchErr)}`);
117
- }
118
- log(` Running LLM prompt for ${spec.name}...`);
119
- const result2 = await runLlmPrompt(spec.prompt, data.summary, spec.maxTokens);
120
- if (result2) {
121
- recommendations[spec.name] = result2;
122
- log(` Got result for ${spec.name}`);
123
- } else {
124
- log(` No result for ${spec.name} (LLM returned null)`);
125
- }
126
- }
127
- log(` [${totalPrompts}/${totalPrompts}] Generating at_a_glance...`);
128
- await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {
129
- status: "running",
130
- progress: {
131
- step: "at_a_glance",
132
- current: totalPrompts,
133
- total: totalPrompts,
134
- partial: { ...recommendations }
135
- }
136
- });
137
- const glanceData = [
138
- data.summary,
139
- recommendations.what_works ? `
140
- ## What Works
141
- ${JSON.stringify(recommendations.what_works)}` : "",
142
- recommendations.friction_analysis ? `
143
- ## Friction
144
- ${JSON.stringify(recommendations.friction_analysis)}` : "",
145
- recommendations.suggestions ? `
146
- ## Suggestions
147
- ${JSON.stringify(recommendations.suggestions)}` : "",
148
- recommendations.on_the_horizon ? `
149
- ## On the Horizon
150
- ${JSON.stringify(recommendations.on_the_horizon)}` : ""
151
- ].join("\n");
152
- const glance = await runLlmPrompt(AT_A_GLANCE_PROMPT, glanceData, 8192);
153
- if (glance) {
154
- recommendations.at_a_glance = glance;
155
- }
156
- log(" Uploading results...");
157
- log(` Done! Recommendations generated for job ${mirrorId}`);
158
- const result = { recommendations };
159
- await apiPatch(`/api/insights-jobs/${mirrorId}/state`, { result }).catch((err) => {
160
- log(`result persist failed: ${err instanceof Error ? err.message : String(err)}`);
161
- });
162
- return result;
163
- }
164
- async function processSessionAnalysisInline(args, log) {
165
- const { mirrorId, sessionId } = args;
166
- log(`Analyzing session ${sessionId} via tool CLI...`);
167
- await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {
168
- status: "running",
169
- progress: { step: "fetching_session" }
170
- });
171
- const session = await apiGet(`/api/sessions/${sessionId}`);
172
- if (session.analysis && session.analysis.source === "session_analysis") {
173
- log(` Session ${sessionId} already analyzed \u2014 skipping (idempotency guard)`);
174
- return { sessionId, skipped: true, reason: "already_analyzed" };
175
- }
176
- const events = await apiGet(
177
- `/api/sessions/${sessionId}/events?limit=100`
178
- );
179
- if (events.length < 2) {
180
- throw new PermanentJobError("Session has too few events to analyze");
181
- }
182
- const eventSummary = events.filter((e) => e.eventType === "user_message" || e.eventType === "human").map((e) => e.content?.slice(0, 200) ?? "").filter(Boolean).join("\n---\n");
183
- if (!eventSummary) {
184
- throw new PermanentJobError("No user messages found in session");
185
- }
186
- await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {
187
- status: "running",
188
- progress: { step: "running_analysis", tool: session.tool }
189
- });
190
- const facets = runToolPrompt(session.tool, FACET_GENERATION_PROMPT, eventSummary);
191
- if (!facets) {
192
- throw new Error(`Analysis failed \u2014 ${session.tool} CLI returned no result`);
193
- }
194
- const userMessageCount = events.filter(
195
- (e) => e.eventType === "user_message" || e.eventType === "human"
196
- ).length;
197
- await apiPatch(`/api/sessions/${sessionId}/enrich`, {
198
- analysis: { source: "session_analysis", tool: session.tool, ...facets },
199
- analyzedEventCount: events.length,
200
- analyzedTurnCount: userMessageCount
201
- });
202
- log(` Session ${sessionId} analyzed via ${session.tool}`);
203
- return { sessionId, tool: session.tool, facets };
204
- }
205
- async function buildDataSummaryFromApi(projectPath, projectId) {
206
- try {
207
- const params = new URLSearchParams();
208
- if (projectId) {
209
- params.set("projectId", projectId);
210
- } else if (projectPath) {
211
- params.set("projectPath", projectPath);
212
- }
213
- const computed = await apiGet(`/api/insights/compute?${params}`);
214
- if (!computed || computed.total_sessions === 0) return null;
215
- const topTools = Object.entries(computed.tool_counts ?? {}).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([t, c]) => `${t}: ${c}`).join(", ");
216
- const summary = [
217
- `Sessions: ${computed.total_sessions}, Messages: ${computed.total_messages}, Hours: ${Math.round(computed.total_duration_hours)}`,
218
- `Top tools: ${topTools}`,
219
- computed.goal_categories && Object.keys(computed.goal_categories).length > 0 ? `Goals: ${JSON.stringify(computed.goal_categories)}` : "",
220
- computed.friction && Object.keys(computed.friction).length > 0 ? `Friction: ${JSON.stringify(computed.friction)}` : "",
221
- computed.outcomes && Object.keys(computed.outcomes).length > 0 ? `Outcomes: ${JSON.stringify(computed.outcomes)}` : "",
222
- computed.projects && Object.keys(computed.projects).length > 0 ? `Projects: ${JSON.stringify(computed.projects)}` : ""
223
- ].filter(Boolean).join("\n");
224
- return {
225
- summary,
226
- stats: {
227
- sessions: computed.total_sessions,
228
- totalMessages: computed.total_messages,
229
- totalHours: computed.total_duration_hours,
230
- toolCounts: computed.tool_counts,
231
- goalCounts: computed.goal_categories,
232
- frictionCounts: computed.friction
233
- }
234
- };
235
- } catch {
236
- return null;
237
- }
238
- }
239
-
240
- export {
241
- processInsights
242
- };
243
- //# sourceMappingURL=chunk-OK3I555A.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/lib/handlers/process-insights.ts"],
4
- "sourcesContent": ["import type { JobHelpers } from '../job-helpers.js';\nimport { apiGet, apiPost, apiPatch } from '../api-client.js';\nimport { RECOMMENDATION_PROMPTS, AT_A_GLANCE_PROMPT, FACET_GENERATION_PROMPT } from '../insights-prompts.js';\nimport { runLlmPrompt, detectLlmBackend, runToolPrompt } from '../llm-client.js';\nimport { PermanentJobError } from '../permanent-job-error.js';\n\ninterface InsightsPayload {\n mirrorId: string;\n projectPath: string | null;\n // Canonical project identity resolved at enqueue time (best-effort; null when\n // unresolved). When present, the worker scopes its compute call to the\n // cross-path cohort via ?projectId; otherwise it falls back to ?projectPath.\n projectId?: string | null;\n config?: {\n sessionId?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Graphile-shaped handler for the `process_insights` task.\n *\n * Lifted from the legacy `insights-worker.ts:processInsightsJob` and\n * `processSessionAnalysisJob`, with the queue plumbing stripped out:\n * - no claim \u2014 Graphile already claimed the job before invoking us\n * - no /complete POST \u2014 we return the result object (or throw)\n * - no \"could not claim\" early-return branches\n *\n * Mid-job progress patches still hit the existing\n * `PATCH /api/insights-jobs/:id/progress` endpoint, just keyed by the\n * mirror row's id.\n *\n * The session-analysis branch (selected when `payload.config.sessionId`\n * is set) lives inline below \u2014 it's a different code path but cheap to\n * keep co-located.\n *\n * The `buildDataSummary*` helpers are duplicated here as private locals;\n * Task 21 will hoist them into a shared `insights-data.ts` once\n * `insights-worker.ts` is deleted.\n *\n * User-facing notifications go through the API's `notifyUser()` path\n * (insert into `notifications` \u2192 Supabase Realtime \u2192 service-worker\n * `showNotification` with a deep-link). The worker no longer fires native\n * `osascript` banners \u2014 those duplicated the browser path, weren't\n * clickable to a URL, and stacked one-per-project on macOS.\n */\nexport async function processInsights(\n payload: InsightsPayload,\n helpers: JobHelpers,\n): Promise<Record<string, unknown>> {\n const { mirrorId, projectPath, projectId, config } = payload;\n const log = (msg: string) => helpers.logger.info(msg);\n\n // Session-analysis branch \u2014 single-session deep analysis through tool CLI\n if (config?.sessionId) {\n return processSessionAnalysisInline({ mirrorId, sessionId: config.sessionId }, log);\n }\n\n log(`Processing insights job ${mirrorId}...`);\n\n // Update status to running\n await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {\n status: 'running',\n progress: { step: 'reading_data' },\n });\n\n // Self-heal orphan analyses missing `analyzed_at`. Without this, the\n // freshness banner on the dashboard nags forever \u2014 the worker's\n // facet-drain query (`hasAnalysis=false`) skips already-analyzed rows,\n // so pre-instrumentation orphans never get touched. Stamps a conservative\n // lower bound (`analyzed_at = started_at`); idempotent on subsequent runs.\n // Best-effort: a failure here must not block the recommendation pass.\n try {\n const { repaired } = await apiPost<{ repaired: number }>(\n '/api/sessions/repair-analyzed-at',\n {},\n );\n if (repaired > 0) {\n log(` Repaired analyzed_at on ${repaired} orphan session(s).`);\n }\n } catch (repairErr) {\n log(` Warning: analyzed_at repair failed: ${repairErr instanceof Error ? repairErr.message : String(repairErr)}`);\n }\n\n // API-based summary is the only source. The previous file-based fallback\n // (`buildDataSummary` reading ~/.claude/usage-data/) was deleted on\n // 2026-05-05 \u2014 it required `rulemetric insights sync` to populate JSON\n // files locally, which nobody ever ran. The DB-derived summary is\n // tool-agnostic and authoritative.\n const data = await buildDataSummaryFromApi(projectPath, projectId);\n if (!data) {\n throw new PermanentJobError(\n 'No session data found \u2014 ensure sessions are captured and enriched.',\n );\n }\n\n log(` Found ${data.stats.sessions} sessions, generating recommendations...`);\n\n // Drain un-analyzed sessions in batches until empty (or until we hit the\n // hard cap, to keep the per-job runtime bounded). Previously this took at\n // most 20 sessions per run, which meant catch-up after a backlog could\n // span days. Batching keeps memory bounded while letting one job clear\n // the entire queue when needed.\n const FACET_BATCH_SIZE = 20;\n const FACET_HARD_CAP = 200; // protect against runaway runtime\n if (detectLlmBackend() !== 'none') {\n let totalFaceted = 0;\n try {\n while (totalFaceted < FACET_HARD_CAP) {\n const unfaceted = await apiGet<Array<{ id: string; tool: string }>>(\n `/api/sessions?hasAnalysis=false&limit=${FACET_BATCH_SIZE}`,\n );\n if (unfaceted.length === 0) break;\n log(` Generating facets for ${unfaceted.length} un-analyzed sessions (drained ${totalFaceted} so far)...`);\n for (const session of unfaceted) {\n if (totalFaceted >= FACET_HARD_CAP) break;\n try {\n const events = await apiGet<Array<{ eventType: string; content: string | null }>>(\n `/api/sessions/${session.id}/events?limit=100`,\n );\n if (events.length < 2) {\n totalFaceted++;\n continue;\n }\n\n const eventSummary = events\n .filter(e => e.eventType === 'user_message' || e.eventType === 'human')\n .map(e => e.content?.slice(0, 200) ?? '')\n .filter(Boolean)\n .join('\\n---\\n');\n\n if (!eventSummary) {\n totalFaceted++;\n continue;\n }\n\n const facets = await runLlmPrompt(FACET_GENERATION_PROMPT, eventSummary, 4096);\n if (facets) {\n const userMessageCount = events.filter(\n e => e.eventType === 'user_message' || e.eventType === 'human',\n ).length;\n await apiPatch(`/api/sessions/${session.id}/enrich`, {\n analysis: { source: 'generated_facets', ...facets },\n analyzedEventCount: events.length,\n analyzedTurnCount: userMessageCount,\n });\n log(` Generated facets for session ${session.id} (${session.tool})`);\n }\n totalFaceted++;\n } catch (sessionErr) {\n log(` Failed to generate facets for session ${session.id}: ${sessionErr instanceof Error ? sessionErr.message : String(sessionErr)}`);\n totalFaceted++; // count it so we don't infinite-loop on a poison row\n }\n }\n // If the batch returned fewer than the requested size, the queue is\n // empty \u2014 break before another fetch.\n if (unfaceted.length < FACET_BATCH_SIZE) break;\n }\n } catch (facetErr) {\n log(` Warning: facet generation failed after ${totalFaceted} sessions: ${facetErr instanceof Error ? facetErr.message : String(facetErr)}`);\n }\n }\n\n // Run recommendation prompts sequentially\n const recommendations: Record<string, unknown> = {};\n const totalPrompts = RECOMMENDATION_PROMPTS.length + 1; // +1 for at_a_glance\n\n // Persist sections-so-far on every progress PATCH so the web UI can render\n // them incrementally \u2014 each prompt takes 30-60s and shipping a label-only\n // progress update for that whole window leaves the page looking dead. The\n // detail page reads `progress.partial` and renders each section card as it\n // arrives.\n for (let i = 0; i < RECOMMENDATION_PROMPTS.length; i++) {\n const spec = RECOMMENDATION_PROMPTS[i];\n log(` [${i + 1}/${totalPrompts}] Generating ${spec.name}...`);\n\n try {\n await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {\n status: 'running',\n progress: {\n step: spec.name,\n current: i + 1,\n total: totalPrompts,\n partial: { ...recommendations },\n },\n });\n } catch (patchErr) {\n log(` Warning: progress update failed for ${spec.name}: ${patchErr instanceof Error ? patchErr.message : String(patchErr)}`);\n }\n\n log(` Running LLM prompt for ${spec.name}...`);\n const result = await runLlmPrompt(spec.prompt, data.summary, spec.maxTokens);\n if (result) {\n recommendations[spec.name] = result;\n log(` Got result for ${spec.name}`);\n } else {\n log(` No result for ${spec.name} (LLM returned null)`);\n }\n }\n\n // At a glance (uses outputs from previous prompts)\n log(` [${totalPrompts}/${totalPrompts}] Generating at_a_glance...`);\n await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {\n status: 'running',\n progress: {\n step: 'at_a_glance',\n current: totalPrompts,\n total: totalPrompts,\n partial: { ...recommendations },\n },\n });\n\n const glanceData = [\n data.summary,\n recommendations.what_works ? `\\n## What Works\\n${JSON.stringify(recommendations.what_works)}` : '',\n recommendations.friction_analysis ? `\\n## Friction\\n${JSON.stringify(recommendations.friction_analysis)}` : '',\n recommendations.suggestions ? `\\n## Suggestions\\n${JSON.stringify(recommendations.suggestions)}` : '',\n recommendations.on_the_horizon ? `\\n## On the Horizon\\n${JSON.stringify(recommendations.on_the_horizon)}` : '',\n ].join('\\n');\n\n const glance = await runLlmPrompt(AT_A_GLANCE_PROMPT, glanceData, 8192);\n if (glance) {\n recommendations.at_a_glance = glance;\n }\n\n log(' Uploading results...');\n log(` Done! Recommendations generated for job ${mirrorId}`);\n\n const result = { recommendations };\n\n // Graphile discards task return values, so persist `{ recommendations }`\n // onto the mirror row here so the dashboard can read it. Best-effort.\n await apiPatch(`/api/insights-jobs/${mirrorId}/state`, { result }).catch((err: unknown) => {\n log(`result persist failed: ${err instanceof Error ? err.message : String(err)}`);\n });\n\n return result;\n}\n\n/**\n * Single-session deep analysis branch. Runs the session's own tool CLI\n * against the captured event stream to produce facets, then enriches the\n * session row.\n *\n * Idempotency guard: if the session already has analysis from a prior\n * `session_analysis` run, we short-circuit. This is independent of the\n * Graphile-side `job_key` dedup added in Task 9 \u2014 that prevents duplicate\n * enqueues; this prevents redoing work even if a different mirrorId\n * targets the same session.\n */\nasync function processSessionAnalysisInline(\n args: { mirrorId: string; sessionId: string },\n log: (msg: string) => void,\n): Promise<Record<string, unknown>> {\n const { mirrorId, sessionId } = args;\n\n log(`Analyzing session ${sessionId} via tool CLI...`);\n\n await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {\n status: 'running',\n progress: { step: 'fetching_session' },\n });\n\n const session = await apiGet<{ id: string; tool: string; analysis: Record<string, unknown> | null }>(`/api/sessions/${sessionId}`);\n\n // Idempotency: skip if session already has analysis from a prior run\n if (session.analysis && (session.analysis as Record<string, unknown>).source === 'session_analysis') {\n log(` Session ${sessionId} already analyzed \u2014 skipping (idempotency guard)`);\n return { sessionId, skipped: true, reason: 'already_analyzed' };\n }\n\n const events = await apiGet<Array<{ eventType: string; content: string | null }>>(\n `/api/sessions/${sessionId}/events?limit=100`,\n );\n\n if (events.length < 2) {\n throw new PermanentJobError('Session has too few events to analyze');\n }\n\n const eventSummary = events\n .filter(e => e.eventType === 'user_message' || e.eventType === 'human')\n .map(e => e.content?.slice(0, 200) ?? '')\n .filter(Boolean)\n .join('\\n---\\n');\n\n if (!eventSummary) {\n throw new PermanentJobError('No user messages found in session');\n }\n\n await apiPatch(`/api/insights-jobs/${mirrorId}/progress`, {\n status: 'running',\n progress: { step: 'running_analysis', tool: session.tool },\n });\n\n // Run through the session's tool CLI\n const facets = runToolPrompt(session.tool, FACET_GENERATION_PROMPT, eventSummary);\n\n if (!facets) {\n throw new Error(`Analysis failed \u2014 ${session.tool} CLI returned no result`);\n }\n\n const userMessageCount = events.filter(\n e => e.eventType === 'user_message' || e.eventType === 'human',\n ).length;\n await apiPatch(`/api/sessions/${sessionId}/enrich`, {\n analysis: { source: 'session_analysis', tool: session.tool, ...facets },\n analyzedEventCount: events.length,\n analyzedTurnCount: userMessageCount,\n });\n\n log(` Session ${sessionId} analyzed via ${session.tool}`);\n\n return { sessionId, tool: session.tool, facets };\n}\n\n// ---------------------------------------------------------------------------\n// Local helpers (copied from `insights-worker.ts`; Task 21 hoists to shared)\n// ---------------------------------------------------------------------------\n\nasync function buildDataSummaryFromApi(projectPath: string | null, projectId?: string | null): Promise<{ summary: string; stats: Record<string, unknown> } | null> {\n try {\n const params = new URLSearchParams();\n // Prefer the canonical project_id \u2014 /api/insights/compute aggregates the\n // project's sessions across every path variant (repo root, /src, worktrees,\n // home-dir captures). Fall back to project_path when no id was resolved.\n if (projectId) {\n params.set('projectId', projectId);\n } else if (projectPath) {\n params.set('projectPath', projectPath);\n }\n\n const computed = await apiGet<{\n total_sessions: number;\n sessions_with_meta: number;\n total_messages: number;\n total_duration_hours: number;\n tool_counts: Record<string, number>;\n goal_categories: Record<string, number>;\n friction: Record<string, number>;\n outcomes: Record<string, number>;\n git_commits: number;\n total_lines_added: number;\n total_lines_removed: number;\n projects: Record<string, number>;\n }>(`/api/insights/compute?${params}`);\n\n if (!computed || computed.total_sessions === 0) return null;\n\n // Build the same text summary format the prompts expect\n const topTools = Object.entries(computed.tool_counts ?? {})\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([t, c]) => `${t}: ${c}`)\n .join(', ');\n\n const summary = [\n `Sessions: ${computed.total_sessions}, Messages: ${computed.total_messages}, Hours: ${Math.round(computed.total_duration_hours)}`,\n `Top tools: ${topTools}`,\n computed.goal_categories && Object.keys(computed.goal_categories).length > 0\n ? `Goals: ${JSON.stringify(computed.goal_categories)}`\n : '',\n computed.friction && Object.keys(computed.friction).length > 0\n ? `Friction: ${JSON.stringify(computed.friction)}`\n : '',\n computed.outcomes && Object.keys(computed.outcomes).length > 0\n ? `Outcomes: ${JSON.stringify(computed.outcomes)}`\n : '',\n computed.projects && Object.keys(computed.projects).length > 0\n ? `Projects: ${JSON.stringify(computed.projects)}`\n : '',\n ].filter(Boolean).join('\\n');\n\n return {\n summary,\n stats: {\n sessions: computed.total_sessions,\n totalMessages: computed.total_messages,\n totalHours: computed.total_duration_hours,\n toolCounts: computed.tool_counts,\n goalCounts: computed.goal_categories,\n frictionCounts: computed.friction,\n },\n };\n } catch {\n return null;\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["result"]
7
- }