@rulemetric/cli 0.7.3 → 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.
- package/dist/base-command.js +1 -14
- package/dist/chunk-2TC6WCUT.js +34 -0
- package/dist/chunk-2UC3ULIG.js +1 -0
- package/dist/chunk-3AV3GTMP.js +1 -0
- package/dist/chunk-4Z5ECCJE.js +1 -0
- package/dist/chunk-5RBLIVBF.js +1 -0
- package/dist/chunk-67QCYUJU.js +1 -0
- package/dist/chunk-6QKI756T.js +2 -0
- package/dist/chunk-6V4WM73L.js +1 -0
- package/dist/chunk-6XEC6474.js +1 -0
- package/dist/chunk-72XLQE3X.js +2 -0
- package/dist/chunk-7DFNBRLY.js +61 -0
- package/dist/chunk-7XQ4VPLC.js +2 -0
- package/dist/chunk-AHRHCERJ.js +1 -0
- package/dist/chunk-ARNZQBMX.js +1 -0
- package/dist/chunk-CADKBP3D.js +58 -0
- package/dist/chunk-CDI5CCHU.js +1 -0
- package/dist/chunk-CNQ5DTNC.js +1 -0
- package/dist/chunk-CRAKDQ4H.js +1 -0
- package/dist/chunk-DNF4HDI6.js +14 -0
- package/dist/chunk-DSO2U4Y6.js +56 -0
- package/dist/chunk-DT4GKEP5.js +5 -0
- package/dist/chunk-DVN7GFJG.js +1 -0
- package/dist/chunk-E4SFUPYR.js +15 -0
- package/dist/chunk-EUHNCVJQ.js +33 -0
- package/dist/chunk-F2VP4B4J.js +1 -0
- package/dist/chunk-FEHM5OKW.js +1 -0
- package/dist/chunk-FHVBTDBM.js +69 -0
- package/dist/chunk-GBMF3TP6.js +1 -0
- package/dist/chunk-GY5IJ4RS.js +1 -0
- package/dist/chunk-HOHD5HY2.js +5 -0
- package/dist/chunk-HP2BUPGS.js +24 -0
- package/dist/{chunk-OQBBVTDG.js → chunk-I2DZGJRR.js} +6 -71
- package/dist/chunk-I4YJ7NTX.js +1 -0
- package/dist/chunk-IY5NXR3N.js +1 -0
- package/dist/chunk-IZTIYR5Q.js +2 -0
- package/dist/chunk-KKDHD4XA.js +2 -0
- package/dist/chunk-LQRYQE6Q.js +4 -0
- package/dist/chunk-M6AJDVCL.js +5 -0
- package/dist/chunk-MGHFDHHM.js +1 -0
- package/dist/chunk-ML36XQW7.js +1 -0
- package/dist/chunk-MODXEGCU.js +1 -0
- package/dist/chunk-MVM6OGAF.js +4 -0
- package/dist/chunk-N7ODX6PO.js +1 -0
- package/dist/chunk-NBTC5FNV.js +1 -0
- package/dist/chunk-NJ5UED3H.js +1 -0
- package/dist/chunk-NVKX36YN.js +3 -0
- package/dist/chunk-NVOTOQBA.js +1 -0
- package/dist/chunk-O7ZMHCMG.js +31 -0
- package/dist/chunk-OMXUK4M6.js +1 -0
- package/dist/chunk-PZS2KOU7.js +1 -0
- package/dist/chunk-RSKQRVPJ.js +1 -0
- package/dist/chunk-RTEATXTP.js +1 -0
- package/dist/chunk-RTWRHIKY.js +7 -0
- package/dist/chunk-RVO4HV3M.js +1 -0
- package/dist/chunk-SBILN45P.js +1 -0
- package/dist/chunk-SZ62CP55.js +1 -0
- package/dist/chunk-T3W5N3BP.js +2 -0
- package/dist/chunk-TDD7IOV2.js +1 -0
- package/dist/chunk-TIQ7DQ3M.js +1 -0
- package/dist/chunk-TU2AR6XO.js +1 -0
- package/dist/chunk-UF6US7VU.js +1 -0
- package/dist/chunk-V5QFOF4F.js +9 -0
- package/dist/chunk-V5U3E4BZ.js +1 -0
- package/dist/chunk-VAFAH6QL.js +1 -0
- package/dist/chunk-VMWY7KHH.js +1 -0
- package/dist/chunk-VUGRXM7R.js +1 -0
- package/dist/{chunk-XZXS2W24.js → chunk-VWEXKDWG.js} +10 -56
- package/dist/chunk-W2MV25SB.js +1 -0
- package/dist/chunk-WJ3H73G6.js +1 -0
- package/dist/chunk-WJUQBMTF.js +9 -0
- package/dist/chunk-WLVQJH4E.js +1 -0
- package/dist/chunk-WPJ2BND4.js +1 -0
- package/dist/chunk-WSCK4WNK.js +1 -0
- package/dist/chunk-Y65CSJFF.js +3 -0
- package/dist/chunk-ZL4MZMUK.js +34 -0
- package/dist/chunk-ZLLER3HP.js +1 -0
- package/dist/chunk-ZXF5NE54.js +1 -0
- package/dist/commands/antigravity/backfill.js +2 -136
- package/dist/commands/auth/create-key.js +1 -52
- package/dist/commands/auth/login.js +1 -85
- package/dist/commands/auth/logout.js +1 -29
- package/dist/commands/auth/revoke-key.js +1 -33
- package/dist/commands/auth/signup.js +1 -89
- package/dist/commands/auth/status.js +1 -42
- package/dist/commands/catalog/index.js +2 -52
- package/dist/commands/catalog/recommend.js +3 -43
- package/dist/commands/convert.js +1 -75
- package/dist/commands/converters.js +1 -54
- package/dist/commands/crons/list.js +1 -41
- package/dist/commands/crons/run.js +2 -76
- package/dist/commands/dashboard.js +1 -46
- package/dist/commands/diagnostics.js +1 -117
- package/dist/commands/eval-targets/create.js +1 -53
- package/dist/commands/eval-targets/list.js +1 -54
- package/dist/commands/evals/agent.js +3 -310
- package/dist/commands/evals/benchmark.js +6 -73
- package/dist/commands/evals/compare.js +13 -96
- package/dist/commands/evals/create.js +1 -67
- package/dist/commands/evals/optimize-description.js +25 -239
- package/dist/commands/evals/optimize.js +5 -211
- package/dist/commands/evals/run.js +3 -183
- package/dist/commands/gateway/ensure.js +1 -104
- package/dist/commands/hooks/emit-instructions.js +1 -25
- package/dist/commands/hooks/install.js +1 -442
- package/dist/commands/hooks/run.js +3 -81
- package/dist/commands/hooks/uninstall.js +2 -156
- package/dist/commands/import.js +1 -66
- package/dist/commands/instructions/create.js +1 -74
- package/dist/commands/instructions/delete.js +1 -55
- package/dist/commands/instructions/fork.js +1 -34
- package/dist/commands/instructions/get.js +1 -68
- package/dist/commands/instructions/list.js +1 -65
- package/dist/commands/instructions/promote.js +1 -42
- package/dist/commands/instructions/pull.js +1 -39
- package/dist/commands/instructions/upstream.js +1 -38
- package/dist/commands/instructions/versions.js +1 -53
- package/dist/commands/launcher.js +1 -40
- package/dist/commands/org/current.js +1 -77
- package/dist/commands/org/list.js +1 -52
- package/dist/commands/org/switch.js +1 -71
- package/dist/commands/packs/add-instruction.js +1 -37
- package/dist/commands/packs/apply.js +1 -39
- package/dist/commands/packs/create.js +1 -50
- package/dist/commands/packs/fork.js +1 -34
- package/dist/commands/packs/get.js +3 -56
- package/dist/commands/packs/list.js +1 -66
- package/dist/commands/packs/remove-instruction.js +1 -35
- package/dist/commands/proxy/env.js +3 -131
- package/dist/commands/proxy/logs.js +3 -85
- package/dist/commands/proxy/restart.js +1 -35
- package/dist/commands/proxy/setup.js +15 -454
- package/dist/commands/proxy/start.js +10 -333
- package/dist/commands/proxy/status.js +1 -78
- package/dist/commands/proxy/stop.js +1 -94
- package/dist/commands/research/backfill.js +1 -59
- package/dist/commands/research/tail-transcript.js +1 -70
- package/dist/commands/service/install.js +57 -796
- package/dist/commands/service/status.js +1 -180
- package/dist/commands/service/uninstall.js +1 -119
- package/dist/commands/sessions/analyze.js +3 -48
- package/dist/commands/sessions/end.js +2 -85
- package/dist/commands/sessions/import.js +1 -46
- package/dist/commands/sessions/list.js +1 -48
- package/dist/commands/sessions/start.js +3 -90
- package/dist/commands/setup.js +3 -150
- package/dist/commands/skills/export-approved.js +1 -46
- package/dist/commands/skills/install.js +4 -107
- package/dist/commands/skills/list.js +4 -65
- package/dist/commands/skills/publish.js +2 -98
- package/dist/commands/skills/search.js +3 -72
- package/dist/commands/skills/update.js +3 -55
- package/dist/commands/suggestions/accept.js +8 -84
- package/dist/commands/suggestions/dismiss.js +1 -45
- package/dist/commands/suggestions/list.js +1 -61
- package/dist/commands/suggestions/refresh.js +1 -27
- package/dist/cursor-T7AMCMKS.js +13 -0
- package/dist/dashboard/Dashboard.js +1 -243
- package/dist/dashboard/data.js +1 -15
- package/dist/dashboard/launcher/ActiveJobsList.js +1 -10
- package/dist/dashboard/launcher/LauncherOverlay.js +1 -16
- package/dist/dashboard/launcher/NewLaunchForm.js +1 -10
- package/dist/dashboard/launcher/api.js +1 -16
- package/dist/dashboard/launcher/tool-labels.js +1 -10
- package/dist/dashboard/launcher/types.js +0 -1
- package/dist/dashboard/launcher/useLaunchJobs.js +1 -11
- package/dist/dashboard/panels/friction.js +1 -10
- package/dist/dashboard/panels/insights.js +1 -10
- package/dist/dashboard/panels/instructions.js +1 -10
- package/dist/dashboard/panels/outcomes.js +1 -10
- package/dist/dashboard/panels/overview.js +1 -10
- package/dist/dashboard/panels/shared.js +1 -19
- package/dist/dashboard/types.js +1 -24
- package/dist/dist-FAVALJ5C.js +1 -0
- package/dist/index.js +1 -8
- package/dist/lib/active-org-refresh.js +1 -15
- package/dist/lib/active-org.js +1 -16
- package/dist/lib/agent-loop.js +1 -47
- package/dist/lib/antigravity-transcript.js +1 -22
- package/dist/lib/api-client.js +1 -23
- package/dist/lib/auth.js +1 -30
- package/dist/lib/capture-hosts.js +1 -8
- package/dist/lib/detect-languages.js +1 -8
- package/dist/lib/detect-tmux.js +1 -9
- package/dist/lib/diagnostics.js +1 -12
- package/dist/lib/editor-proxy-pins.js +1 -14
- package/dist/lib/ensure-api-key.js +1 -11
- package/dist/lib/eval-analyzer.js +1 -9
- package/dist/lib/eval-benchmark.js +1 -12
- package/dist/lib/eval-conversation-handler.js +1 -13
- package/dist/lib/eval-executor.js +1 -8
- package/dist/lib/eval-grader.js +1 -9
- package/dist/lib/eval-meta-judge.js +1 -9
- package/dist/lib/eval-trigger-tester.js +1 -11
- package/dist/lib/eval-worktree.js +1 -8
- package/dist/lib/gateway-entry.js +1 -61
- package/dist/lib/gateway-identity.js +1 -16
- package/dist/lib/gateway-lifecycle.js +1 -32
- package/dist/lib/gateway.js +1 -14
- package/dist/lib/handlers/cron-refresh-pricing.js +1 -0
- package/dist/lib/handlers/cron-refresh-skills.js +1 -8
- package/dist/lib/handlers/cron-suggest-instructions.js +1 -16
- package/dist/lib/handlers/process-announcement.js +1 -11
- package/dist/lib/handlers/process-changelog.js +1 -11
- package/dist/lib/handlers/process-conversation.js +1 -14
- package/dist/lib/handlers/process-eval.js +1 -15
- package/dist/lib/handlers/process-insights.js +1 -15
- package/dist/lib/handlers/process-launch.js +1 -16
- package/dist/lib/handlers/process-run-cleanup.js +1 -13
- package/dist/lib/handlers/process-send-message.js +1 -10
- package/dist/lib/handlers/process-session-goal.js +1 -12
- package/dist/lib/hooks-config.js +1 -81
- package/dist/lib/insights-prompts.js +1 -12
- package/dist/lib/instruction-snapshot.js +1 -8
- package/dist/lib/job-helpers.js +0 -1
- package/dist/lib/llm-client.js +1 -20
- package/dist/lib/manual-tasks-meta.js +1 -8
- package/dist/lib/manual-tasks.js +1 -80
- package/dist/lib/output.js +1 -12
- package/dist/lib/permanent-job-error.js +1 -10
- package/dist/lib/pid-identity.js +1 -14
- package/dist/lib/proxy-respawn.js +1 -12
- package/dist/lib/research-client.js +1 -12
- package/dist/lib/setup-steps.js +1 -33
- package/dist/lib/skills-loader.js +1 -8
- package/dist/lib/statusline-shim.js +1 -20
- package/dist/lib/telemetry.js +1 -16
- package/dist/lib/terminal-target-heartbeat.js +1 -15
- package/dist/lib/tmux.js +1 -16
- package/dist/lib/transcript-rate-limit-watcher.js +1 -22
- package/dist/lib/types.js +1 -8
- package/dist/lib/version-check.js +1 -12
- package/dist/lib/which.js +1 -8
- package/dist/lib/worktree.js +1 -17
- package/dist/opencode-QRJ3BH23.js +1 -0
- package/oclif.manifest.json +135 -135
- package/package.json +9 -8
- package/dist/base-command.js.map +0 -7
- package/dist/chunk-2HK7RGZB.js +0 -82
- package/dist/chunk-2HK7RGZB.js.map +0 -7
- package/dist/chunk-2ORJWTNZ.js +0 -307
- package/dist/chunk-2ORJWTNZ.js.map +0 -7
- package/dist/chunk-37LN5O7M.js +0 -59
- package/dist/chunk-37LN5O7M.js.map +0 -7
- package/dist/chunk-3S7223UR.js +0 -81
- package/dist/chunk-3S7223UR.js.map +0 -7
- package/dist/chunk-3TIMQ3O6.js +0 -96
- package/dist/chunk-3TIMQ3O6.js.map +0 -7
- package/dist/chunk-42GFSAJP.js +0 -32
- package/dist/chunk-42GFSAJP.js.map +0 -7
- package/dist/chunk-4BHDHHKL.js +0 -48
- package/dist/chunk-4BHDHHKL.js.map +0 -7
- package/dist/chunk-4D537GXE.js +0 -99
- package/dist/chunk-4D537GXE.js.map +0 -7
- package/dist/chunk-4LYCDS2N.js +0 -139
- package/dist/chunk-4LYCDS2N.js.map +0 -7
- package/dist/chunk-4SCZK7AL.js +0 -129
- package/dist/chunk-4SCZK7AL.js.map +0 -7
- package/dist/chunk-4XAWK6S2.js +0 -161
- package/dist/chunk-4XAWK6S2.js.map +0 -7
- package/dist/chunk-52WIYRZH.js +0 -73
- package/dist/chunk-52WIYRZH.js.map +0 -7
- package/dist/chunk-5BAOGNUH.js +0 -79
- package/dist/chunk-5BAOGNUH.js.map +0 -7
- package/dist/chunk-5EDMGK3W.js +0 -39
- package/dist/chunk-5EDMGK3W.js.map +0 -7
- package/dist/chunk-6NBS5XFS.js +0 -99
- package/dist/chunk-6NBS5XFS.js.map +0 -7
- package/dist/chunk-7LVVKQMZ.js +0 -98
- package/dist/chunk-7LVVKQMZ.js.map +0 -7
- package/dist/chunk-7NNFYWKK.js +0 -243
- package/dist/chunk-7NNFYWKK.js.map +0 -7
- package/dist/chunk-7NYKWN7U.js +0 -12
- package/dist/chunk-7NYKWN7U.js.map +0 -7
- package/dist/chunk-BO76WKJR.js +0 -42
- package/dist/chunk-BO76WKJR.js.map +0 -7
- package/dist/chunk-BRD5RUGM.js +0 -53
- package/dist/chunk-BRD5RUGM.js.map +0 -7
- package/dist/chunk-BT6Z6545.js +0 -43
- package/dist/chunk-BT6Z6545.js.map +0 -7
- package/dist/chunk-BZDKEQKU.js +0 -39
- package/dist/chunk-BZDKEQKU.js.map +0 -7
- package/dist/chunk-DGHWRQXL.js +0 -17
- package/dist/chunk-DGHWRQXL.js.map +0 -7
- package/dist/chunk-DIQUV5FR.js +0 -257
- package/dist/chunk-DIQUV5FR.js.map +0 -7
- package/dist/chunk-DMX5YOTM.js +0 -167
- package/dist/chunk-DMX5YOTM.js.map +0 -7
- package/dist/chunk-DNKSVWMD.js +0 -108
- package/dist/chunk-DNKSVWMD.js.map +0 -7
- package/dist/chunk-DQ3KELXD.js +0 -74
- package/dist/chunk-DQ3KELXD.js.map +0 -7
- package/dist/chunk-DUJSRBLP.js +0 -122
- package/dist/chunk-DUJSRBLP.js.map +0 -7
- package/dist/chunk-E3BIT53W.js +0 -154
- package/dist/chunk-E3BIT53W.js.map +0 -7
- package/dist/chunk-EARWG4EV.js +0 -22
- package/dist/chunk-EARWG4EV.js.map +0 -7
- package/dist/chunk-EI5BHWXA.js +0 -1662
- package/dist/chunk-EI5BHWXA.js.map +0 -7
- package/dist/chunk-EJ3YAFDP.js +0 -37
- package/dist/chunk-EJ3YAFDP.js.map +0 -7
- package/dist/chunk-EKJ2CABV.js +0 -76
- package/dist/chunk-EKJ2CABV.js.map +0 -7
- package/dist/chunk-EKP32DLN.js +0 -16
- package/dist/chunk-EKP32DLN.js.map +0 -7
- package/dist/chunk-EYPAAGN5.js +0 -51
- package/dist/chunk-EYPAAGN5.js.map +0 -7
- package/dist/chunk-F5N6CLJJ.js +0 -1995
- package/dist/chunk-F5N6CLJJ.js.map +0 -7
- package/dist/chunk-GIUBARWS.js +0 -99
- package/dist/chunk-GIUBARWS.js.map +0 -7
- package/dist/chunk-GQNJO2P2.js +0 -102
- package/dist/chunk-GQNJO2P2.js.map +0 -7
- package/dist/chunk-IJGF2ETG.js +0 -68
- package/dist/chunk-IJGF2ETG.js.map +0 -7
- package/dist/chunk-ILYDELUE.js +0 -46
- package/dist/chunk-ILYDELUE.js.map +0 -7
- package/dist/chunk-J6QFW4LD.js +0 -55
- package/dist/chunk-J6QFW4LD.js.map +0 -7
- package/dist/chunk-J7N3DLH6.js +0 -117
- package/dist/chunk-J7N3DLH6.js.map +0 -7
- package/dist/chunk-JFDWKLQC.js +0 -23
- package/dist/chunk-JFDWKLQC.js.map +0 -7
- package/dist/chunk-JULOLTZS.js +0 -61
- package/dist/chunk-JULOLTZS.js.map +0 -7
- package/dist/chunk-KJKBDQ4D.js +0 -220
- package/dist/chunk-KJKBDQ4D.js.map +0 -7
- package/dist/chunk-KRBQLMOP.js +0 -41
- package/dist/chunk-KRBQLMOP.js.map +0 -7
- package/dist/chunk-LXKPNATC.js +0 -624
- package/dist/chunk-LXKPNATC.js.map +0 -7
- package/dist/chunk-NSBPE2FW.js +0 -17
- package/dist/chunk-NSBPE2FW.js.map +0 -7
- package/dist/chunk-OCKHW72U.js +0 -55
- package/dist/chunk-OCKHW72U.js.map +0 -7
- package/dist/chunk-OKWCKCPE.js +0 -414
- package/dist/chunk-OKWCKCPE.js.map +0 -7
- package/dist/chunk-OO7JDFS4.js +0 -157
- package/dist/chunk-OO7JDFS4.js.map +0 -7
- package/dist/chunk-OQBBVTDG.js.map +0 -7
- package/dist/chunk-OQSQC7VB.js +0 -77
- package/dist/chunk-OQSQC7VB.js.map +0 -7
- package/dist/chunk-PED7L5GX.js +0 -92
- package/dist/chunk-PED7L5GX.js.map +0 -7
- package/dist/chunk-QJQS6TUN.js +0 -44
- package/dist/chunk-QJQS6TUN.js.map +0 -7
- package/dist/chunk-QN34TGD3.js +0 -83
- package/dist/chunk-QN34TGD3.js.map +0 -7
- package/dist/chunk-QSN77T7C.js +0 -250
- package/dist/chunk-QSN77T7C.js.map +0 -7
- package/dist/chunk-R56PH7YE.js +0 -78
- package/dist/chunk-R56PH7YE.js.map +0 -7
- package/dist/chunk-RAXRZYOB.js +0 -299
- package/dist/chunk-RAXRZYOB.js.map +0 -7
- package/dist/chunk-RH7NHVSK.js +0 -16
- package/dist/chunk-RH7NHVSK.js.map +0 -7
- package/dist/chunk-RMTT4KDY.js +0 -191
- package/dist/chunk-RMTT4KDY.js.map +0 -7
- package/dist/chunk-RQ2TMLKG.js +0 -142
- package/dist/chunk-RQ2TMLKG.js.map +0 -7
- package/dist/chunk-SO3T35U7.js +0 -80
- package/dist/chunk-SO3T35U7.js.map +0 -7
- package/dist/chunk-UKMLICWS.js +0 -51
- package/dist/chunk-UKMLICWS.js.map +0 -7
- package/dist/chunk-VA5FFOS7.js +0 -243
- package/dist/chunk-VA5FFOS7.js.map +0 -7
- package/dist/chunk-W2YERO7E.js +0 -170
- package/dist/chunk-W2YERO7E.js.map +0 -7
- package/dist/chunk-W53GKIZQ.js +0 -50
- package/dist/chunk-W53GKIZQ.js.map +0 -7
- package/dist/chunk-WA4MWYRW.js +0 -254
- package/dist/chunk-WA4MWYRW.js.map +0 -7
- package/dist/chunk-XC6M4CSW.js +0 -44
- package/dist/chunk-XC6M4CSW.js.map +0 -7
- package/dist/chunk-XK42ZBDE.js +0 -23
- package/dist/chunk-XK42ZBDE.js.map +0 -7
- package/dist/chunk-XUV6DDBF.js +0 -124
- package/dist/chunk-XUV6DDBF.js.map +0 -7
- package/dist/chunk-XZXS2W24.js.map +0 -7
- package/dist/chunk-Y3WD5CSW.js +0 -49
- package/dist/chunk-Y3WD5CSW.js.map +0 -7
- package/dist/chunk-Y4BJXXYV.js +0 -148
- package/dist/chunk-Y4BJXXYV.js.map +0 -7
- package/dist/chunk-YNIH3KMU.js +0 -121
- package/dist/chunk-YNIH3KMU.js.map +0 -7
- package/dist/chunk-ZUJBM6HE.js +0 -125
- package/dist/chunk-ZUJBM6HE.js.map +0 -7
- package/dist/commands/antigravity/backfill.js.map +0 -7
- package/dist/commands/auth/create-key.js.map +0 -7
- package/dist/commands/auth/login.js.map +0 -7
- package/dist/commands/auth/logout.js.map +0 -7
- package/dist/commands/auth/revoke-key.js.map +0 -7
- package/dist/commands/auth/signup.js.map +0 -7
- package/dist/commands/auth/status.js.map +0 -7
- package/dist/commands/catalog/index.js.map +0 -7
- package/dist/commands/catalog/recommend.js.map +0 -7
- package/dist/commands/convert.js.map +0 -7
- package/dist/commands/converters.js.map +0 -7
- package/dist/commands/crons/list.js.map +0 -7
- package/dist/commands/crons/run.js.map +0 -7
- package/dist/commands/dashboard.js.map +0 -7
- package/dist/commands/diagnostics.js.map +0 -7
- package/dist/commands/eval-targets/create.js.map +0 -7
- package/dist/commands/eval-targets/list.js.map +0 -7
- package/dist/commands/evals/agent.js.map +0 -7
- package/dist/commands/evals/benchmark.js.map +0 -7
- package/dist/commands/evals/compare.js.map +0 -7
- package/dist/commands/evals/create.js.map +0 -7
- package/dist/commands/evals/optimize-description.js.map +0 -7
- package/dist/commands/evals/optimize.js.map +0 -7
- package/dist/commands/evals/run.js.map +0 -7
- package/dist/commands/gateway/ensure.js.map +0 -7
- package/dist/commands/hooks/emit-instructions.js.map +0 -7
- package/dist/commands/hooks/install.js.map +0 -7
- package/dist/commands/hooks/run.js.map +0 -7
- package/dist/commands/hooks/uninstall.js.map +0 -7
- package/dist/commands/import.js.map +0 -7
- package/dist/commands/instructions/create.js.map +0 -7
- package/dist/commands/instructions/delete.js.map +0 -7
- package/dist/commands/instructions/fork.js.map +0 -7
- package/dist/commands/instructions/get.js.map +0 -7
- package/dist/commands/instructions/list.js.map +0 -7
- package/dist/commands/instructions/promote.js.map +0 -7
- package/dist/commands/instructions/pull.js.map +0 -7
- package/dist/commands/instructions/upstream.js.map +0 -7
- package/dist/commands/instructions/versions.js.map +0 -7
- package/dist/commands/launcher.js.map +0 -7
- package/dist/commands/org/current.js.map +0 -7
- package/dist/commands/org/list.js.map +0 -7
- package/dist/commands/org/switch.js.map +0 -7
- package/dist/commands/packs/add-instruction.js.map +0 -7
- package/dist/commands/packs/apply.js.map +0 -7
- package/dist/commands/packs/create.js.map +0 -7
- package/dist/commands/packs/fork.js.map +0 -7
- package/dist/commands/packs/get.js.map +0 -7
- package/dist/commands/packs/list.js.map +0 -7
- package/dist/commands/packs/remove-instruction.js.map +0 -7
- package/dist/commands/proxy/env.js.map +0 -7
- package/dist/commands/proxy/logs.js.map +0 -7
- package/dist/commands/proxy/restart.js.map +0 -7
- package/dist/commands/proxy/setup.js.map +0 -7
- package/dist/commands/proxy/start.js.map +0 -7
- package/dist/commands/proxy/status.js.map +0 -7
- package/dist/commands/proxy/stop.js.map +0 -7
- package/dist/commands/research/backfill.js.map +0 -7
- package/dist/commands/research/tail-transcript.js.map +0 -7
- package/dist/commands/service/install.js.map +0 -7
- package/dist/commands/service/status.js.map +0 -7
- package/dist/commands/service/uninstall.js.map +0 -7
- package/dist/commands/sessions/analyze.js.map +0 -7
- package/dist/commands/sessions/end.js.map +0 -7
- package/dist/commands/sessions/import.js.map +0 -7
- package/dist/commands/sessions/list.js.map +0 -7
- package/dist/commands/sessions/start.js.map +0 -7
- package/dist/commands/setup.js.map +0 -7
- package/dist/commands/skills/export-approved.js.map +0 -7
- package/dist/commands/skills/install.js.map +0 -7
- package/dist/commands/skills/list.js.map +0 -7
- package/dist/commands/skills/publish.js.map +0 -7
- package/dist/commands/skills/search.js.map +0 -7
- package/dist/commands/skills/update.js.map +0 -7
- package/dist/commands/suggestions/accept.js.map +0 -7
- package/dist/commands/suggestions/dismiss.js.map +0 -7
- package/dist/commands/suggestions/list.js.map +0 -7
- package/dist/commands/suggestions/refresh.js.map +0 -7
- package/dist/cursor-BGQJ4CWI.js +0 -134
- package/dist/cursor-BGQJ4CWI.js.map +0 -7
- package/dist/dashboard/Dashboard.js.map +0 -7
- package/dist/dashboard/data.js.map +0 -7
- package/dist/dashboard/launcher/ActiveJobsList.js.map +0 -7
- package/dist/dashboard/launcher/LauncherOverlay.js.map +0 -7
- package/dist/dashboard/launcher/NewLaunchForm.js.map +0 -7
- package/dist/dashboard/launcher/api.js.map +0 -7
- package/dist/dashboard/launcher/tool-labels.js.map +0 -7
- package/dist/dashboard/launcher/types.js.map +0 -7
- package/dist/dashboard/launcher/useLaunchJobs.js.map +0 -7
- package/dist/dashboard/panels/friction.js.map +0 -7
- package/dist/dashboard/panels/insights.js.map +0 -7
- package/dist/dashboard/panels/instructions.js.map +0 -7
- package/dist/dashboard/panels/outcomes.js.map +0 -7
- package/dist/dashboard/panels/overview.js.map +0 -7
- package/dist/dashboard/panels/shared.js.map +0 -7
- package/dist/dashboard/types.js.map +0 -7
- package/dist/dist-UNYP5PJR.js +0 -56
- package/dist/dist-UNYP5PJR.js.map +0 -7
- package/dist/index.js.map +0 -7
- package/dist/lib/active-org-refresh.js.map +0 -7
- package/dist/lib/active-org.js.map +0 -7
- package/dist/lib/agent-loop.js.map +0 -7
- package/dist/lib/antigravity-transcript.js.map +0 -7
- package/dist/lib/api-client.js.map +0 -7
- package/dist/lib/auth.js.map +0 -7
- package/dist/lib/capture-hosts.js.map +0 -7
- package/dist/lib/detect-languages.js.map +0 -7
- package/dist/lib/detect-tmux.js.map +0 -7
- package/dist/lib/diagnostics.js.map +0 -7
- package/dist/lib/editor-proxy-pins.js.map +0 -7
- package/dist/lib/ensure-api-key.js.map +0 -7
- package/dist/lib/eval-analyzer.js.map +0 -7
- package/dist/lib/eval-benchmark.js.map +0 -7
- package/dist/lib/eval-conversation-handler.js.map +0 -7
- package/dist/lib/eval-executor.js.map +0 -7
- package/dist/lib/eval-grader.js.map +0 -7
- package/dist/lib/eval-meta-judge.js.map +0 -7
- package/dist/lib/eval-trigger-tester.js.map +0 -7
- package/dist/lib/eval-worktree.js.map +0 -7
- package/dist/lib/gateway-entry.js.map +0 -7
- package/dist/lib/gateway-identity.js.map +0 -7
- package/dist/lib/gateway-lifecycle.js.map +0 -7
- package/dist/lib/gateway.js.map +0 -7
- package/dist/lib/handlers/cron-refresh-skills.js.map +0 -7
- package/dist/lib/handlers/cron-suggest-instructions.js.map +0 -7
- package/dist/lib/handlers/process-announcement.js.map +0 -7
- package/dist/lib/handlers/process-changelog.js.map +0 -7
- package/dist/lib/handlers/process-conversation.js.map +0 -7
- package/dist/lib/handlers/process-eval.js.map +0 -7
- package/dist/lib/handlers/process-insights.js.map +0 -7
- package/dist/lib/handlers/process-launch.js.map +0 -7
- package/dist/lib/handlers/process-run-cleanup.js.map +0 -7
- package/dist/lib/handlers/process-send-message.js.map +0 -7
- package/dist/lib/handlers/process-session-goal.js.map +0 -7
- package/dist/lib/hooks-config.js.map +0 -7
- package/dist/lib/insights-prompts.js.map +0 -7
- package/dist/lib/instruction-snapshot.js.map +0 -7
- package/dist/lib/job-helpers.js.map +0 -7
- package/dist/lib/llm-client.js.map +0 -7
- package/dist/lib/manual-tasks-meta.js.map +0 -7
- package/dist/lib/manual-tasks.js.map +0 -7
- package/dist/lib/output.js.map +0 -7
- package/dist/lib/permanent-job-error.js.map +0 -7
- package/dist/lib/pid-identity.js.map +0 -7
- package/dist/lib/proxy-respawn.js.map +0 -7
- package/dist/lib/research-client.js.map +0 -7
- package/dist/lib/setup-steps.js.map +0 -7
- package/dist/lib/skills-loader.js.map +0 -7
- package/dist/lib/statusline-shim.js.map +0 -7
- package/dist/lib/telemetry.js.map +0 -7
- package/dist/lib/terminal-target-heartbeat.js.map +0 -7
- package/dist/lib/tmux.js.map +0 -7
- package/dist/lib/transcript-rate-limit-watcher.js.map +0 -7
- package/dist/lib/types.js.map +0 -7
- package/dist/lib/version-check.js.map +0 -7
- package/dist/lib/which.js.map +0 -7
- package/dist/lib/worktree.js.map +0 -7
- package/dist/opencode-IQ7X5YMJ.js +0 -190
- 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
|
-
}
|
package/dist/chunk-NSBPE2FW.js
DELETED
|
@@ -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
|
package/dist/chunk-OCKHW72U.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getDb,
|
|
3
|
-
sessionEvents,
|
|
4
|
-
sessions
|
|
5
|
-
} from "./chunk-EI5BHWXA.js";
|
|
6
|
-
import {
|
|
7
|
-
runLlmPrompt
|
|
8
|
-
} from "./chunk-DIQUV5FR.js";
|
|
9
|
-
|
|
10
|
-
// src/lib/handlers/process-session-goal.ts
|
|
11
|
-
import { eq, asc, sql } from "drizzle-orm";
|
|
12
|
-
var ACTIVE_WINDOW_MS = 30 * 60 * 1e3;
|
|
13
|
-
var RECENT_WINDOW_MS = 5 * 60 * 1e3;
|
|
14
|
-
var MAX_TURNS = 10;
|
|
15
|
-
var PROMPT = `Given these messages from an AI coding session, write a 1-2 sentence summary of what the user is trying to accomplish. Focus on the goal, not the steps. No preamble.
|
|
16
|
-
|
|
17
|
-
Return strict JSON in the form: {"goalSummary": "..."}`;
|
|
18
|
-
async function processSessionGoal(payload, deps = {}) {
|
|
19
|
-
const db = deps.db ?? getDb();
|
|
20
|
-
const llm = deps.llm ?? runLlmPrompt;
|
|
21
|
-
const now = deps.now ?? Date.now;
|
|
22
|
-
const [s] = await db.select().from(sessions).where(eq(sessions.id, payload.sessionId)).limit(1);
|
|
23
|
-
if (!s) return { skipped: "not_found" };
|
|
24
|
-
const lastAtRows = await db.execute(
|
|
25
|
-
sql`SELECT MAX(timestamp) AS last_at FROM session_events WHERE session_id = ${payload.sessionId}`
|
|
26
|
-
);
|
|
27
|
-
const lastAtRaw = lastAtRows?.[0]?.last_at ?? s.startedAt;
|
|
28
|
-
const lastAt = new Date(lastAtRaw).getTime();
|
|
29
|
-
if (now() - lastAt > ACTIVE_WINDOW_MS) return { skipped: "stale" };
|
|
30
|
-
const analysis = s.analysis ?? {};
|
|
31
|
-
const lastGoalAt = analysis.goalSummaryAt ? new Date(analysis.goalSummaryAt).getTime() : 0;
|
|
32
|
-
if (lastGoalAt && now() - lastGoalAt < RECENT_WINDOW_MS) {
|
|
33
|
-
return { skipped: "recent" };
|
|
34
|
-
}
|
|
35
|
-
const events = await db.select().from(sessionEvents).where(eq(sessionEvents.sessionId, payload.sessionId)).orderBy(asc(sessionEvents.timestamp)).limit(MAX_TURNS * 2);
|
|
36
|
-
const turns = events.filter(
|
|
37
|
-
(e) => e.content && (e.eventType === "user_message" || e.eventType === "assistant_response")
|
|
38
|
-
).map(
|
|
39
|
-
(e) => `${e.eventType === "user_message" ? "USER" : "ASSISTANT"}: ${e.content}`
|
|
40
|
-
).join("\n\n");
|
|
41
|
-
if (!turns) return { skipped: "no_content" };
|
|
42
|
-
const parsed = await llm(PROMPT, turns, 200);
|
|
43
|
-
const summary = typeof parsed?.goalSummary === "string" ? parsed.goalSummary.trim() : "";
|
|
44
|
-
if (!summary) return { skipped: "llm_empty" };
|
|
45
|
-
const goalSummaryAt = new Date(now()).toISOString();
|
|
46
|
-
await db.update(sessions).set({
|
|
47
|
-
analysis: { ...analysis, goalSummary: summary, goalSummaryAt }
|
|
48
|
-
}).where(eq(sessions.id, payload.sessionId));
|
|
49
|
-
return { goalSummary: summary };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export {
|
|
53
|
-
processSessionGoal
|
|
54
|
-
};
|
|
55
|
-
//# sourceMappingURL=chunk-OCKHW72U.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/lib/handlers/process-session-goal.ts"],
|
|
4
|
-
"sourcesContent": ["import { eq, asc, sql } from 'drizzle-orm';\nimport { sessions, sessionEvents, getDb } from '@rulemetric/db';\nimport { runLlmPrompt } from '../llm-client.js';\n\nconst ACTIVE_WINDOW_MS = 30 * 60 * 1000;\nconst RECENT_WINDOW_MS = 5 * 60 * 1000;\nconst MAX_TURNS = 10;\n\nconst PROMPT = `Given these messages from an AI coding session, write a 1-2 sentence summary of what the user is trying to accomplish. Focus on the goal, not the steps. No preamble.\n\nReturn strict JSON in the form: {\"goalSummary\": \"...\"}`;\n\nexport interface ProcessSessionGoalPayload {\n sessionId: string;\n milestone: 5 | 20 | 50;\n}\n\nexport interface ProcessSessionGoalResult {\n skipped?: 'not_found' | 'stale' | 'recent' | 'no_content' | 'llm_empty';\n goalSummary?: string;\n}\n\nexport interface ProcessSessionGoalDeps {\n db?: any;\n llm?: typeof runLlmPrompt;\n now?: () => number;\n}\n\n/**\n * Fire-and-forget background job triggered at event milestones (5/20/50).\n * Generates a short \"what is the user trying to do\" summary and writes it\n * to `sessions.analysis.goalSummary` + `goalSummaryAt`, preserving any\n * existing analysis keys.\n *\n * Guards:\n * - stale: skip if no activity in last 30 min (session is dead, don't waste an LLM call)\n * - recent: skip if we already generated a summary in the last 5 min (dedup milestone burst)\n *\n * No mirror table \u2014 this is fire-and-forget, similar to crons. Errors\n * propagate so Graphile retries.\n */\nexport async function processSessionGoal(\n payload: ProcessSessionGoalPayload,\n deps: ProcessSessionGoalDeps = {},\n): Promise<ProcessSessionGoalResult> {\n const db = deps.db ?? getDb();\n const llm = deps.llm ?? runLlmPrompt;\n const now = deps.now ?? Date.now;\n\n const [s] = await db\n .select()\n .from(sessions)\n .where(eq(sessions.id, payload.sessionId))\n .limit(1);\n if (!s) return { skipped: 'not_found' };\n\n // Single-roundtrip MAX(timestamp) \u2014 fall back to startedAt if no events yet.\n const lastAtRows = await db.execute(\n sql`SELECT MAX(timestamp) AS last_at FROM session_events WHERE session_id = ${payload.sessionId}`,\n );\n const lastAtRaw = lastAtRows?.[0]?.last_at ?? s.startedAt;\n const lastAt = new Date(lastAtRaw as string | Date).getTime();\n if (now() - lastAt > ACTIVE_WINDOW_MS) return { skipped: 'stale' };\n\n const analysis = (s.analysis ?? {}) as Record<string, unknown>;\n const lastGoalAt = analysis.goalSummaryAt\n ? new Date(analysis.goalSummaryAt as string).getTime()\n : 0;\n if (lastGoalAt && now() - lastGoalAt < RECENT_WINDOW_MS) {\n return { skipped: 'recent' };\n }\n\n const events = await db\n .select()\n .from(sessionEvents)\n .where(eq(sessionEvents.sessionId, payload.sessionId))\n .orderBy(asc(sessionEvents.timestamp))\n .limit(MAX_TURNS * 2);\n\n const turns = (events as Array<{ eventType: string; content: string | null }>)\n .filter(\n (e) =>\n e.content &&\n (e.eventType === 'user_message' || e.eventType === 'assistant_response'),\n )\n .map(\n (e) =>\n `${e.eventType === 'user_message' ? 'USER' : 'ASSISTANT'}: ${e.content}`,\n )\n .join('\\n\\n');\n\n if (!turns) return { skipped: 'no_content' };\n\n // Let LLM errors throw \u2014 Graphile will retry.\n const parsed = await llm(PROMPT, turns, 200);\n const summary =\n typeof parsed?.goalSummary === 'string' ? parsed.goalSummary.trim() : '';\n if (!summary) return { skipped: 'llm_empty' };\n\n const goalSummaryAt = new Date(now()).toISOString();\n await db\n .update(sessions)\n .set({\n analysis: { ...analysis, goalSummary: summary, goalSummaryAt },\n })\n .where(eq(sessions.id, payload.sessionId));\n\n return { goalSummary: summary };\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;AAAA,SAAS,IAAI,KAAK,WAAW;AAI7B,IAAM,mBAAmB,KAAK,KAAK;AACnC,IAAM,mBAAmB,IAAI,KAAK;AAClC,IAAM,YAAY;AAElB,IAAM,SAAS;AAAA;AAAA;AAiCf,eAAsB,mBACpB,SACA,OAA+B,CAAC,GACG;AACnC,QAAM,KAAK,KAAK,MAAM,MAAM;AAC5B,QAAM,MAAM,KAAK,OAAO;AACxB,QAAM,MAAM,KAAK,OAAO,KAAK;AAE7B,QAAM,CAAC,CAAC,IAAI,MAAM,GACf,OAAO,EACP,KAAK,QAAQ,EACb,MAAM,GAAG,SAAS,IAAI,QAAQ,SAAS,CAAC,EACxC,MAAM,CAAC;AACV,MAAI,CAAC,EAAG,QAAO,EAAE,SAAS,YAAY;AAGtC,QAAM,aAAa,MAAM,GAAG;AAAA,IAC1B,8EAA8E,QAAQ,SAAS;AAAA,EACjG;AACA,QAAM,YAAY,aAAa,CAAC,GAAG,WAAW,EAAE;AAChD,QAAM,SAAS,IAAI,KAAK,SAA0B,EAAE,QAAQ;AAC5D,MAAI,IAAI,IAAI,SAAS,iBAAkB,QAAO,EAAE,SAAS,QAAQ;AAEjE,QAAM,WAAY,EAAE,YAAY,CAAC;AACjC,QAAM,aAAa,SAAS,gBACxB,IAAI,KAAK,SAAS,aAAuB,EAAE,QAAQ,IACnD;AACJ,MAAI,cAAc,IAAI,IAAI,aAAa,kBAAkB;AACvD,WAAO,EAAE,SAAS,SAAS;AAAA,EAC7B;AAEA,QAAM,SAAS,MAAM,GAClB,OAAO,EACP,KAAK,aAAa,EAClB,MAAM,GAAG,cAAc,WAAW,QAAQ,SAAS,CAAC,EACpD,QAAQ,IAAI,cAAc,SAAS,CAAC,EACpC,MAAM,YAAY,CAAC;AAEtB,QAAM,QAAS,OACZ;AAAA,IACC,CAAC,MACC,EAAE,YACD,EAAE,cAAc,kBAAkB,EAAE,cAAc;AAAA,EACvD,EACC;AAAA,IACC,CAAC,MACC,GAAG,EAAE,cAAc,iBAAiB,SAAS,WAAW,KAAK,EAAE,OAAO;AAAA,EAC1E,EACC,KAAK,MAAM;AAEd,MAAI,CAAC,MAAO,QAAO,EAAE,SAAS,aAAa;AAG3C,QAAM,SAAS,MAAM,IAAI,QAAQ,OAAO,GAAG;AAC3C,QAAM,UACJ,OAAO,QAAQ,gBAAgB,WAAW,OAAO,YAAY,KAAK,IAAI;AACxE,MAAI,CAAC,QAAS,QAAO,EAAE,SAAS,YAAY;AAE5C,QAAM,gBAAgB,IAAI,KAAK,IAAI,CAAC,EAAE,YAAY;AAClD,QAAM,GACH,OAAO,QAAQ,EACf,IAAI;AAAA,IACH,UAAU,EAAE,GAAG,UAAU,aAAa,SAAS,cAAc;AAAA,EAC/D,CAAC,EACA,MAAM,GAAG,SAAS,IAAI,QAAQ,SAAS,CAAC;AAE3C,SAAO,EAAE,aAAa,QAAQ;AAChC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/dist/chunk-OKWCKCPE.js
DELETED
|
@@ -1,414 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RULEMETRIC_NO_PROXY,
|
|
3
|
-
detectInstalledTools,
|
|
4
|
-
hasRulemetricClaudeHooks,
|
|
5
|
-
mergeClaudeCodeHooks,
|
|
6
|
-
removeRulemetricMachineState
|
|
7
|
-
} from "./chunk-LXKPNATC.js";
|
|
8
|
-
import {
|
|
9
|
-
GATEWAY_PORT
|
|
10
|
-
} from "./chunk-4LYCDS2N.js";
|
|
11
|
-
import {
|
|
12
|
-
apiGet
|
|
13
|
-
} from "./chunk-ZUJBM6HE.js";
|
|
14
|
-
import {
|
|
15
|
-
getDefaultConfigDir,
|
|
16
|
-
isAuthenticated
|
|
17
|
-
} from "./chunk-W2YERO7E.js";
|
|
18
|
-
|
|
19
|
-
// src/lib/setup-steps.ts
|
|
20
|
-
import { execSync } from "node:child_process";
|
|
21
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
22
|
-
import { homedir } from "node:os";
|
|
23
|
-
import { join } from "node:path";
|
|
24
|
-
var CORE_STEP_IDS = ["install", "auth", "hooks", "worker"];
|
|
25
|
-
var OPTIONAL_STEP_IDS = [];
|
|
26
|
-
var ALL_STEP_IDS = [...CORE_STEP_IDS, ...OPTIONAL_STEP_IDS];
|
|
27
|
-
function defaultContext() {
|
|
28
|
-
return {
|
|
29
|
-
projectPath: process.cwd(),
|
|
30
|
-
configDir: getDefaultConfigDir()
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
var CERT_PATH = join(homedir(), ".mitmproxy", "mitmproxy-ca-cert.pem");
|
|
34
|
-
function maskToken(s) {
|
|
35
|
-
if (!s) return "";
|
|
36
|
-
if (s.length <= 8) return "*".repeat(s.length);
|
|
37
|
-
const head = s.slice(0, 4);
|
|
38
|
-
const tail = s.slice(-4);
|
|
39
|
-
return `${head}${"*".repeat(Math.max(4, s.length - 8))}${tail}`;
|
|
40
|
-
}
|
|
41
|
-
function renderDiff(before, after) {
|
|
42
|
-
const beforeLines = before === null ? [] : before.replace(/\n$/, "").split("\n");
|
|
43
|
-
const afterLines = after === null ? [] : after.replace(/\n$/, "").split("\n");
|
|
44
|
-
const out = [];
|
|
45
|
-
const max = Math.max(beforeLines.length, afterLines.length);
|
|
46
|
-
for (let i = 0; i < max; i++) {
|
|
47
|
-
const b = beforeLines[i];
|
|
48
|
-
const a = afterLines[i];
|
|
49
|
-
if (b === a) {
|
|
50
|
-
out.push(` ${b}`);
|
|
51
|
-
} else {
|
|
52
|
-
if (b !== void 0) out.push(`-${b}`);
|
|
53
|
-
if (a !== void 0) out.push(`+${a}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return out.join("\n");
|
|
57
|
-
}
|
|
58
|
-
function readEnvValue(configDir, key) {
|
|
59
|
-
const envPath = join(configDir, "env");
|
|
60
|
-
if (!existsSync(envPath)) return null;
|
|
61
|
-
try {
|
|
62
|
-
const content = readFileSync(envPath, "utf-8");
|
|
63
|
-
const match = content.match(new RegExp(`^${key}=(.+)$`, "m"));
|
|
64
|
-
return match ? match[1] : null;
|
|
65
|
-
} catch {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async function workerActive() {
|
|
70
|
-
if (!isAuthenticated()) return false;
|
|
71
|
-
try {
|
|
72
|
-
const status = await Promise.race([
|
|
73
|
-
apiGet("/api/setup/status"),
|
|
74
|
-
new Promise(
|
|
75
|
-
(_, reject) => setTimeout(() => reject(new Error("setup/status timeout")), 2500)
|
|
76
|
-
)
|
|
77
|
-
]);
|
|
78
|
-
return status?.workerActive === true;
|
|
79
|
-
} catch {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function readProjectSettings(projectPath, fileName) {
|
|
84
|
-
const settingsPath = join(projectPath, ".claude", fileName);
|
|
85
|
-
let settings = {};
|
|
86
|
-
let before = null;
|
|
87
|
-
if (existsSync(settingsPath)) {
|
|
88
|
-
try {
|
|
89
|
-
before = readFileSync(settingsPath, "utf-8").replace(/\n$/, "");
|
|
90
|
-
settings = JSON.parse(before);
|
|
91
|
-
} catch {
|
|
92
|
-
settings = {};
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return { settings, before };
|
|
96
|
-
}
|
|
97
|
-
function projectHooksSettings(projectPath) {
|
|
98
|
-
const { settings, before } = readProjectSettings(projectPath, "settings.local.json");
|
|
99
|
-
mergeClaudeCodeHooks(settings);
|
|
100
|
-
return { before, after: JSON.stringify(settings, null, 2) };
|
|
101
|
-
}
|
|
102
|
-
function projectProxyEnvSettings(projectPath) {
|
|
103
|
-
const { settings, before } = readProjectSettings(projectPath, "settings.local.json");
|
|
104
|
-
const env = { ...settings.env ?? {} };
|
|
105
|
-
env.HTTPS_PROXY = `http://localhost:${GATEWAY_PORT}`;
|
|
106
|
-
env.NO_PROXY = RULEMETRIC_NO_PROXY;
|
|
107
|
-
env.NODE_EXTRA_CA_CERTS = CERT_PATH;
|
|
108
|
-
return { before, after: JSON.stringify({ ...settings, env }, null, 2) };
|
|
109
|
-
}
|
|
110
|
-
function projectSharedSettingsMigration(projectPath) {
|
|
111
|
-
const { settings, before } = readProjectSettings(projectPath, "settings.json");
|
|
112
|
-
if (before === null) return null;
|
|
113
|
-
const { removed } = removeRulemetricMachineState(settings, GATEWAY_PORT);
|
|
114
|
-
if (!removed) return null;
|
|
115
|
-
return { before, after: JSON.stringify(settings, null, 2) };
|
|
116
|
-
}
|
|
117
|
-
var WORKER_PLIST_PATH = join(homedir(), "Library", "LaunchAgents", "com.rulemetric.worker.plist");
|
|
118
|
-
var WORKER_SYSTEMD_PATH = join(homedir(), ".config", "systemd", "user", "rulemetric-worker.service");
|
|
119
|
-
function runCommand(cmd) {
|
|
120
|
-
execSync(cmd, { stdio: "inherit" });
|
|
121
|
-
}
|
|
122
|
-
var STEPS = [
|
|
123
|
-
{
|
|
124
|
-
id: "install",
|
|
125
|
-
title: "Install the CLI",
|
|
126
|
-
command: "npm install -g @rulemetric/cli",
|
|
127
|
-
// Monotonic: the CLI must exist to produce any downstream signal, so it
|
|
128
|
-
// greens off auth or worker presence (nothing local phones home before).
|
|
129
|
-
async detect() {
|
|
130
|
-
return isAuthenticated() || await workerActive();
|
|
131
|
-
},
|
|
132
|
-
async plan() {
|
|
133
|
-
return {
|
|
134
|
-
id: "install",
|
|
135
|
-
title: "Install the CLI",
|
|
136
|
-
command: "npm install -g @rulemetric/cli",
|
|
137
|
-
artifacts: [
|
|
138
|
-
{
|
|
139
|
-
path: "npm install -g @rulemetric/cli",
|
|
140
|
-
kind: "command",
|
|
141
|
-
before: null,
|
|
142
|
-
after: "rulemetric --version # verifies the binary is on PATH"
|
|
143
|
-
}
|
|
144
|
-
]
|
|
145
|
-
};
|
|
146
|
-
},
|
|
147
|
-
async apply() {
|
|
148
|
-
runCommand("npm install -g @rulemetric/cli");
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
id: "auth",
|
|
153
|
-
title: "Authenticate",
|
|
154
|
-
command: "rulemetric auth login",
|
|
155
|
-
async detect() {
|
|
156
|
-
return isAuthenticated();
|
|
157
|
-
},
|
|
158
|
-
async plan(ctx) {
|
|
159
|
-
const envPath = join(ctx.configDir, "env");
|
|
160
|
-
let before = null;
|
|
161
|
-
if (existsSync(envPath)) {
|
|
162
|
-
try {
|
|
163
|
-
before = maskEnvFile(readFileSync(envPath, "utf-8"));
|
|
164
|
-
} catch {
|
|
165
|
-
before = "(unreadable)";
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
const rawToken = readEnvValue(ctx.configDir, "RULEMETRIC_ACCESS_TOKEN");
|
|
169
|
-
const tokenDisplay = rawToken ? maskToken(rawToken) : maskToken("<token-from-login>");
|
|
170
|
-
const afterLines = [`RULEMETRIC_ACCESS_TOKEN=${tokenDisplay}`];
|
|
171
|
-
const rawApiKey = readEnvValue(ctx.configDir, "RULEMETRIC_API_KEY");
|
|
172
|
-
if (rawApiKey) {
|
|
173
|
-
afterLines.push(`RULEMETRIC_API_KEY=${maskToken(rawApiKey)}`);
|
|
174
|
-
}
|
|
175
|
-
const loginUrl = process.env.RULEMETRIC_API_URL;
|
|
176
|
-
if (loginUrl) {
|
|
177
|
-
afterLines.push(`RULEMETRIC_API_URL=${loginUrl}`);
|
|
178
|
-
}
|
|
179
|
-
const after = afterLines.join("\n");
|
|
180
|
-
return {
|
|
181
|
-
id: "auth",
|
|
182
|
-
title: "Authenticate",
|
|
183
|
-
command: "rulemetric auth login",
|
|
184
|
-
artifacts: [
|
|
185
|
-
{
|
|
186
|
-
path: envPath,
|
|
187
|
-
kind: "file",
|
|
188
|
-
before,
|
|
189
|
-
after,
|
|
190
|
-
masked: true
|
|
191
|
-
},
|
|
192
|
-
// `auth login` (saveToken) also writes auth.json — disclose it so the
|
|
193
|
-
// plan matches every file apply() touches.
|
|
194
|
-
{
|
|
195
|
-
path: join(ctx.configDir, "auth.json"),
|
|
196
|
-
kind: "file",
|
|
197
|
-
before: existsSync(join(ctx.configDir, "auth.json")) ? "(existing session tokens)" : null,
|
|
198
|
-
after: "{ accessToken, refreshToken, expiresAt, email } \u2014 OAuth session tokens (secret)",
|
|
199
|
-
masked: true
|
|
200
|
-
}
|
|
201
|
-
]
|
|
202
|
-
};
|
|
203
|
-
},
|
|
204
|
-
async apply() {
|
|
205
|
-
runCommand("rulemetric auth login");
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
id: "hooks",
|
|
210
|
-
title: "Install hooks + capture proxy",
|
|
211
|
-
// Default onboarding installs the FULL capture path: session hooks PLUS the
|
|
212
|
-
// MITM proxy (rendered-system-prompt / instruction linking + cross-tool
|
|
213
|
-
// capture). Every invasive side effect is disclosed up front in plan()
|
|
214
|
-
// below — nothing is silent. `hooks install` fails SAFE: if the CA sudo
|
|
215
|
-
// trust is declined it degrades to hooks-only (no machine-wide proxy pin),
|
|
216
|
-
// and HTTPS_PROXY is only pinned once the gateway actually answers on
|
|
217
|
-
// :8787 — so the default never bricks Claude Code. detect() greens on the
|
|
218
|
-
// capture hooks being present, so `coreComplete` is reachable even when the
|
|
219
|
-
// user declines the proxy.
|
|
220
|
-
command: "rulemetric hooks install",
|
|
221
|
-
async detect(ctx) {
|
|
222
|
-
for (const fileName of ["settings.local.json", "settings.json"]) {
|
|
223
|
-
const settingsPath = join(ctx.projectPath, ".claude", fileName);
|
|
224
|
-
if (!existsSync(settingsPath)) continue;
|
|
225
|
-
try {
|
|
226
|
-
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
227
|
-
if (hasRulemetricClaudeHooks(settings)) return true;
|
|
228
|
-
} catch {
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return false;
|
|
232
|
-
},
|
|
233
|
-
async plan(ctx) {
|
|
234
|
-
const settingsPath = join(ctx.projectPath, ".claude", "settings.local.json");
|
|
235
|
-
const { before, after } = projectHooksSettings(ctx.projectPath);
|
|
236
|
-
const artifacts = [
|
|
237
|
-
{ path: settingsPath, kind: "file", before, after },
|
|
238
|
-
// Disclose what the hooks DO, not just that they're registered — these
|
|
239
|
-
// are the privacy-relevant behaviors a user is consenting to.
|
|
240
|
-
{
|
|
241
|
-
path: "what these hooks capture",
|
|
242
|
-
kind: "service",
|
|
243
|
-
before: null,
|
|
244
|
-
after: "session-end reimports the FULL transcript to the API; post-tool-use records each tool call and snapshots the working tree to a LOCAL shadow git ref (paper-trail, never pushed); user-prompt posts prompt text. All scoped to sessions in this project."
|
|
245
|
-
},
|
|
246
|
-
// FULL DISCLOSURE of the proxy layer — every invasive side effect of
|
|
247
|
-
// `hooks install` §2 is enumerated here so the default path hides
|
|
248
|
-
// nothing. Each degrades gracefully (see the step comment): a declined
|
|
249
|
-
// CA-trust sudo skips the machine-wide layer and stays hooks-only.
|
|
250
|
-
{
|
|
251
|
-
// The proxy env block `hooks install` §2 adds to the SAME
|
|
252
|
-
// .claude/settings.local.json (HTTPS_PROXY / NO_PROXY / NODE_EXTRA_CA_CERTS).
|
|
253
|
-
path: `${settingsPath} (proxy env block)`,
|
|
254
|
-
kind: "file",
|
|
255
|
-
...projectProxyEnvSettings(ctx.projectPath)
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
path: "system keychain \u2014 mitmproxy root CA",
|
|
259
|
-
kind: "service",
|
|
260
|
-
before: existsSync(CERT_PATH) ? "(CA generated; trust state unchanged)" : "(no CA yet)",
|
|
261
|
-
after: "Installs + trusts the mitmproxy CA (requires sudo). This lets the proxy DECRYPT Claude Code HTTPS request/response bodies \u2014 the capability that powers rendered-system-prompt / instruction linking. Decline the sudo prompt and setup stays hooks-only (still fully onboarded)."
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
path: "launchctl setenv HTTPS_PROXY (machine-wide, all GUI apps)",
|
|
265
|
-
kind: "command",
|
|
266
|
-
before: null,
|
|
267
|
-
after: `http://localhost:${GATEWAY_PORT} \u2014 routes every GUI app's HTTPS through the local gateway (only when the CA is trusted AND :${GATEWAY_PORT} is live)`
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
path: "VS Code + Cursor user settings (http.proxy)",
|
|
271
|
-
kind: "file",
|
|
272
|
-
before: null,
|
|
273
|
-
after: `http.proxy \u2192 http://localhost:${GATEWAY_PORT} (+ http.proxyStrictSSL=false)`
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
path: `gateway process on :${GATEWAY_PORT}`,
|
|
277
|
-
kind: "service",
|
|
278
|
-
before: null,
|
|
279
|
-
after: "started (routes Claude Code \u2192 mitmproxy \u2192 Anthropic; falls back to direct if mitmproxy is down)"
|
|
280
|
-
}
|
|
281
|
-
];
|
|
282
|
-
const sharedMigration = projectSharedSettingsMigration(ctx.projectPath);
|
|
283
|
-
if (sharedMigration) {
|
|
284
|
-
artifacts.push({
|
|
285
|
-
path: `${join(ctx.projectPath, ".claude", "settings.json")} (removes RuleMetric machine-local state left by an older install \u2014 see the local-file artifacts above for where it moves)`,
|
|
286
|
-
kind: "file",
|
|
287
|
-
...sharedMigration
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
for (const tool of detectInstalledTools(ctx.projectPath).filter((t) => t === "cursor" || t === "copilot_agent")) {
|
|
291
|
-
artifacts.push({
|
|
292
|
-
path: `${ctx.projectPath} (${tool} workspace proxy config)`,
|
|
293
|
-
kind: "file",
|
|
294
|
-
before: null,
|
|
295
|
-
after: `proxy \u2192 http://localhost:${GATEWAY_PORT}`
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
for (const [tool, home, file] of [
|
|
299
|
-
["Cursor", join(homedir(), ".cursor"), join(homedir(), ".cursor", "hooks.json")],
|
|
300
|
-
["Antigravity/Gemini", join(homedir(), ".gemini"), join(homedir(), ".gemini", "config", "hooks.json")]
|
|
301
|
-
]) {
|
|
302
|
-
if (existsSync(home)) {
|
|
303
|
-
artifacts.push({
|
|
304
|
-
path: `${file} (${tool} user hooks)`,
|
|
305
|
-
kind: "file",
|
|
306
|
-
before: existsSync(file) ? "(existing config)" : null,
|
|
307
|
-
after: "adds RuleMetric session-capture hooks for this tool"
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return {
|
|
312
|
-
id: "hooks",
|
|
313
|
-
title: "Install hooks + capture proxy",
|
|
314
|
-
command: "rulemetric hooks install",
|
|
315
|
-
artifacts
|
|
316
|
-
};
|
|
317
|
-
},
|
|
318
|
-
async apply() {
|
|
319
|
-
runCommand("rulemetric hooks install");
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
id: "worker",
|
|
324
|
-
title: "Run the worker",
|
|
325
|
-
command: "rulemetric service install --worker-only",
|
|
326
|
-
async detect() {
|
|
327
|
-
return workerActive();
|
|
328
|
-
},
|
|
329
|
-
async plan() {
|
|
330
|
-
const isMac = process.platform === "darwin";
|
|
331
|
-
const servicePath = isMac ? WORKER_PLIST_PATH : WORKER_SYSTEMD_PATH;
|
|
332
|
-
const before = existsSync(servicePath) ? `(service already installed at ${servicePath})` : null;
|
|
333
|
-
const after = isMac ? [
|
|
334
|
-
`Label: com.rulemetric.worker`,
|
|
335
|
-
`ProgramArguments: <node> <cli>/bin/run.js evals agent`,
|
|
336
|
-
`RunAtLoad: true, KeepAlive: true`
|
|
337
|
-
].join("\n") : [
|
|
338
|
-
`[Service]`,
|
|
339
|
-
`ExecStart=<node> <cli>/bin/run.js evals agent`,
|
|
340
|
-
`Restart=on-failure`
|
|
341
|
-
].join("\n");
|
|
342
|
-
return {
|
|
343
|
-
id: "worker",
|
|
344
|
-
title: "Run the worker",
|
|
345
|
-
command: "rulemetric service install --worker-only",
|
|
346
|
-
artifacts: [
|
|
347
|
-
{ path: servicePath, kind: "service", before, after }
|
|
348
|
-
]
|
|
349
|
-
};
|
|
350
|
-
},
|
|
351
|
-
async apply() {
|
|
352
|
-
runCommand("rulemetric service install --worker-only");
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
];
|
|
356
|
-
var STEP_BY_ID = new Map(STEPS.map((s) => [s.id, s]));
|
|
357
|
-
function getStep(id) {
|
|
358
|
-
const step = STEP_BY_ID.get(id);
|
|
359
|
-
if (!step) throw new Error(`Unknown setup step: ${id}`);
|
|
360
|
-
return step;
|
|
361
|
-
}
|
|
362
|
-
function isStepId(value) {
|
|
363
|
-
return ALL_STEP_IDS.includes(value);
|
|
364
|
-
}
|
|
365
|
-
var SAFE_ENV_KEYS = /* @__PURE__ */ new Set([
|
|
366
|
-
"RULEMETRIC_API_URL",
|
|
367
|
-
"RULEMETRIC_USER_ID",
|
|
368
|
-
"RULEMETRIC_CLIENT_NAME",
|
|
369
|
-
"RESEND_FROM_EMAIL",
|
|
370
|
-
"SENTRY_DSN",
|
|
371
|
-
// a DSN is not a secret
|
|
372
|
-
"PG_POOL_MAX",
|
|
373
|
-
"PG_IDLE_TIMEOUT",
|
|
374
|
-
"PG_STATEMENT_TIMEOUT_MS",
|
|
375
|
-
"NODE_ENV"
|
|
376
|
-
]);
|
|
377
|
-
function maskEnvFile(content) {
|
|
378
|
-
return content.replace(/\n$/, "").split("\n").map((line) => {
|
|
379
|
-
const match = line.match(/^([A-Z0-9_]+)=(.+)$/);
|
|
380
|
-
if (!match) return line;
|
|
381
|
-
const [, key, value] = match;
|
|
382
|
-
return SAFE_ENV_KEYS.has(key) ? line : `${key}=${maskToken(value)}`;
|
|
383
|
-
}).join("\n");
|
|
384
|
-
}
|
|
385
|
-
async function computeStatus(ctx = defaultContext()) {
|
|
386
|
-
const steps = [];
|
|
387
|
-
for (const step of STEPS) {
|
|
388
|
-
const done = await step.detect(ctx);
|
|
389
|
-
steps.push({ id: step.id, done });
|
|
390
|
-
}
|
|
391
|
-
const install = steps.find((s) => s.id === "install");
|
|
392
|
-
if (install && !install.done) {
|
|
393
|
-
install.done = steps.some((s) => s.id !== "install" && s.done);
|
|
394
|
-
}
|
|
395
|
-
const coreIds = new Set(CORE_STEP_IDS);
|
|
396
|
-
const coreSteps = steps.filter((s) => coreIds.has(s.id));
|
|
397
|
-
const currentStepId = coreSteps.find((s) => !s.done)?.id ?? null;
|
|
398
|
-
const coreComplete = coreSteps.every((s) => s.done);
|
|
399
|
-
return { steps, coreComplete, currentStepId };
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
export {
|
|
403
|
-
CORE_STEP_IDS,
|
|
404
|
-
OPTIONAL_STEP_IDS,
|
|
405
|
-
ALL_STEP_IDS,
|
|
406
|
-
defaultContext,
|
|
407
|
-
maskToken,
|
|
408
|
-
renderDiff,
|
|
409
|
-
STEPS,
|
|
410
|
-
getStep,
|
|
411
|
-
isStepId,
|
|
412
|
-
computeStatus
|
|
413
|
-
};
|
|
414
|
-
//# sourceMappingURL=chunk-OKWCKCPE.js.map
|