@rulemetric/cli 0.6.8 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/dist/base-command.js +4 -3
  2. package/dist/{chunk-SZ7VDCD6.js → chunk-2HK7RGZB.js} +22 -3
  3. package/dist/chunk-2HK7RGZB.js.map +7 -0
  4. package/dist/{chunk-RUCSRN7F.js → chunk-2ORJWTNZ.js} +2 -2
  5. package/dist/{chunk-SLL3OBKN.js → chunk-37LN5O7M.js} +2 -2
  6. package/dist/{chunk-RCMXTLQF.js → chunk-3LKVS6W5.js} +5 -5
  7. package/dist/{chunk-XN23W5HL.js → chunk-4KRMZLQV.js} +91 -7
  8. package/dist/chunk-4KRMZLQV.js.map +7 -0
  9. package/dist/{chunk-DAJNO4OI.js → chunk-4LYCDS2N.js} +28 -16
  10. package/dist/chunk-4LYCDS2N.js.map +7 -0
  11. package/dist/{chunk-UPXIO7CG.js → chunk-4XAWK6S2.js} +8 -8
  12. package/dist/{chunk-N5A2IQAK.js → chunk-4YAP7RT7.js} +5 -5
  13. package/dist/{chunk-QD6X4L4L.js → chunk-5BAOGNUH.js} +4 -4
  14. package/dist/chunk-5EDMGK3W.js +39 -0
  15. package/dist/chunk-5EDMGK3W.js.map +7 -0
  16. package/dist/{chunk-5ADHO5QF.js → chunk-6NBS5XFS.js} +6 -6
  17. package/dist/chunk-7LVVKQMZ.js +98 -0
  18. package/dist/chunk-7LVVKQMZ.js.map +7 -0
  19. package/dist/{chunk-PXVQLD7S.js → chunk-7NNFYWKK.js} +48 -1
  20. package/dist/chunk-7NNFYWKK.js.map +7 -0
  21. package/dist/{chunk-BBLTN35F.js → chunk-7UDETV3P.js} +49 -20
  22. package/dist/chunk-7UDETV3P.js.map +7 -0
  23. package/dist/{chunk-DTFXCHHI.js → chunk-DNKSVWMD.js} +4 -4
  24. package/dist/{chunk-6EMZI4Y3.js → chunk-EI5BHWXA.js} +437 -401
  25. package/dist/chunk-EI5BHWXA.js.map +7 -0
  26. package/dist/{chunk-HNZLEEG2.js → chunk-EJ3YAFDP.js} +4 -4
  27. package/dist/{chunk-HNZLEEG2.js.map → chunk-EJ3YAFDP.js.map} +2 -2
  28. package/dist/{chunk-YSEQWCN4.js → chunk-EYPAAGN5.js} +2 -2
  29. package/dist/{chunk-JEJ3J5J6.js → chunk-GIUBARWS.js} +2 -2
  30. package/dist/chunk-GQNJO2P2.js +102 -0
  31. package/dist/chunk-GQNJO2P2.js.map +7 -0
  32. package/dist/{chunk-CNMWYYSV.js → chunk-HZK43UCF.js} +6 -6
  33. package/dist/chunk-ILYDELUE.js +46 -0
  34. package/dist/chunk-ILYDELUE.js.map +7 -0
  35. package/dist/chunk-J6QFW4LD.js +55 -0
  36. package/dist/chunk-J6QFW4LD.js.map +7 -0
  37. package/dist/{chunk-OTOWLUOJ.js → chunk-JULOLTZS.js} +2 -2
  38. package/dist/{chunk-DR5WLIOU.js → chunk-KJKBDQ4D.js} +2 -2
  39. package/dist/{chunk-AHDRN6NE.js → chunk-OO7JDFS4.js} +5 -5
  40. package/dist/{chunk-N2X35ITW.js → chunk-OQBBVTDG.js} +11 -1
  41. package/dist/{chunk-N2X35ITW.js.map → chunk-OQBBVTDG.js.map} +2 -2
  42. package/dist/{chunk-3QH73QOQ.js → chunk-PED7L5GX.js} +2 -2
  43. package/dist/{chunk-VBGUNFKY.js → chunk-PMI56ED5.js} +5 -5
  44. package/dist/{chunk-XNNOXGP6.js → chunk-POFTPB33.js} +38 -19
  45. package/dist/chunk-POFTPB33.js.map +7 -0
  46. package/dist/{chunk-W4MZXKZ2.js → chunk-UKMLICWS.js} +2 -2
  47. package/dist/{chunk-3POYC5NA.js → chunk-XK42ZBDE.js} +3 -3
  48. package/dist/{chunk-ZSGKRCKD.js → chunk-XUV6DDBF.js} +2 -2
  49. package/dist/{chunk-LAKZUE35.js → chunk-Y3WD5CSW.js} +2 -2
  50. package/dist/{chunk-3QVMIJUL.js → chunk-YOBA3NAM.js} +5 -5
  51. package/dist/{chunk-ZRLYHBPN.js → chunk-ZUJBM6HE.js} +20 -2
  52. package/dist/chunk-ZUJBM6HE.js.map +7 -0
  53. package/dist/commands/antigravity/backfill.js +5 -4
  54. package/dist/commands/antigravity/backfill.js.map +1 -1
  55. package/dist/commands/auth/create-key.js +4 -3
  56. package/dist/commands/auth/create-key.js.map +1 -1
  57. package/dist/commands/auth/login.js +13 -9
  58. package/dist/commands/auth/login.js.map +2 -2
  59. package/dist/commands/auth/logout.js +4 -3
  60. package/dist/commands/auth/logout.js.map +1 -1
  61. package/dist/commands/auth/revoke-key.js +4 -3
  62. package/dist/commands/auth/revoke-key.js.map +1 -1
  63. package/dist/commands/auth/signup.js +13 -9
  64. package/dist/commands/auth/signup.js.map +2 -2
  65. package/dist/commands/auth/status.js +4 -3
  66. package/dist/commands/auth/status.js.map +1 -1
  67. package/dist/commands/catalog/index.js +4 -3
  68. package/dist/commands/catalog/index.js.map +1 -1
  69. package/dist/commands/catalog/recommend.js +4 -3
  70. package/dist/commands/catalog/recommend.js.map +1 -1
  71. package/dist/commands/convert.js +4 -3
  72. package/dist/commands/convert.js.map +1 -1
  73. package/dist/commands/converters.js +4 -3
  74. package/dist/commands/converters.js.map +1 -1
  75. package/dist/commands/crons/list.js +4 -3
  76. package/dist/commands/crons/list.js.map +1 -1
  77. package/dist/commands/crons/run.js +4 -3
  78. package/dist/commands/crons/run.js.map +1 -1
  79. package/dist/commands/dashboard.js +4 -3
  80. package/dist/commands/dashboard.js.map +1 -1
  81. package/dist/commands/diagnostics.js +117 -0
  82. package/dist/commands/diagnostics.js.map +7 -0
  83. package/dist/commands/eval-targets/create.js +4 -3
  84. package/dist/commands/eval-targets/create.js.map +1 -1
  85. package/dist/commands/eval-targets/list.js +4 -3
  86. package/dist/commands/eval-targets/list.js.map +1 -1
  87. package/dist/commands/evals/agent.js +44 -23
  88. package/dist/commands/evals/agent.js.map +2 -2
  89. package/dist/commands/evals/benchmark.js +5 -4
  90. package/dist/commands/evals/benchmark.js.map +1 -1
  91. package/dist/commands/evals/compare.js +4 -3
  92. package/dist/commands/evals/compare.js.map +1 -1
  93. package/dist/commands/evals/create.js +4 -3
  94. package/dist/commands/evals/create.js.map +1 -1
  95. package/dist/commands/evals/optimize-description.js +4 -3
  96. package/dist/commands/evals/optimize-description.js.map +1 -1
  97. package/dist/commands/evals/optimize.js +4 -3
  98. package/dist/commands/evals/optimize.js.map +1 -1
  99. package/dist/commands/evals/run.js +4 -3
  100. package/dist/commands/evals/run.js.map +1 -1
  101. package/dist/commands/gateway/ensure.js +58 -5
  102. package/dist/commands/gateway/ensure.js.map +2 -2
  103. package/dist/commands/hooks/install.js +76 -23
  104. package/dist/commands/hooks/install.js.map +2 -2
  105. package/dist/commands/hooks/run.js +9 -5
  106. package/dist/commands/hooks/run.js.map +2 -2
  107. package/dist/commands/hooks/uninstall.js +31 -40
  108. package/dist/commands/hooks/uninstall.js.map +2 -2
  109. package/dist/commands/import.js +4 -3
  110. package/dist/commands/import.js.map +1 -1
  111. package/dist/commands/instructions/create.js +4 -3
  112. package/dist/commands/instructions/create.js.map +1 -1
  113. package/dist/commands/instructions/delete.js +4 -3
  114. package/dist/commands/instructions/delete.js.map +1 -1
  115. package/dist/commands/instructions/fork.js +4 -3
  116. package/dist/commands/instructions/fork.js.map +1 -1
  117. package/dist/commands/instructions/get.js +4 -3
  118. package/dist/commands/instructions/get.js.map +1 -1
  119. package/dist/commands/instructions/list.js +4 -3
  120. package/dist/commands/instructions/list.js.map +1 -1
  121. package/dist/commands/instructions/promote.js +4 -3
  122. package/dist/commands/instructions/promote.js.map +1 -1
  123. package/dist/commands/instructions/pull.js +4 -3
  124. package/dist/commands/instructions/pull.js.map +1 -1
  125. package/dist/commands/instructions/upstream.js +4 -3
  126. package/dist/commands/instructions/upstream.js.map +1 -1
  127. package/dist/commands/instructions/versions.js +4 -3
  128. package/dist/commands/instructions/versions.js.map +1 -1
  129. package/dist/commands/launcher.js +4 -3
  130. package/dist/commands/launcher.js.map +1 -1
  131. package/dist/commands/org/current.js +4 -3
  132. package/dist/commands/org/current.js.map +1 -1
  133. package/dist/commands/org/list.js +4 -3
  134. package/dist/commands/org/list.js.map +1 -1
  135. package/dist/commands/org/switch.js +4 -3
  136. package/dist/commands/org/switch.js.map +1 -1
  137. package/dist/commands/packs/add-instruction.js +4 -3
  138. package/dist/commands/packs/add-instruction.js.map +1 -1
  139. package/dist/commands/packs/apply.js +4 -3
  140. package/dist/commands/packs/apply.js.map +1 -1
  141. package/dist/commands/packs/create.js +4 -3
  142. package/dist/commands/packs/create.js.map +1 -1
  143. package/dist/commands/packs/fork.js +4 -3
  144. package/dist/commands/packs/fork.js.map +1 -1
  145. package/dist/commands/packs/get.js +4 -3
  146. package/dist/commands/packs/get.js.map +1 -1
  147. package/dist/commands/packs/list.js +4 -3
  148. package/dist/commands/packs/list.js.map +1 -1
  149. package/dist/commands/packs/remove-instruction.js +4 -3
  150. package/dist/commands/packs/remove-instruction.js.map +1 -1
  151. package/dist/commands/proxy/env.js +7 -4
  152. package/dist/commands/proxy/env.js.map +1 -1
  153. package/dist/commands/proxy/logs.js +4 -3
  154. package/dist/commands/proxy/logs.js.map +1 -1
  155. package/dist/commands/proxy/restart.js +4 -3
  156. package/dist/commands/proxy/restart.js.map +1 -1
  157. package/dist/commands/proxy/setup.js +20 -14
  158. package/dist/commands/proxy/setup.js.map +2 -2
  159. package/dist/commands/proxy/start.js +18 -14
  160. package/dist/commands/proxy/start.js.map +2 -2
  161. package/dist/commands/proxy/status.js +16 -13
  162. package/dist/commands/proxy/status.js.map +2 -2
  163. package/dist/commands/proxy/stop.js +21 -12
  164. package/dist/commands/proxy/stop.js.map +2 -2
  165. package/dist/commands/research/backfill.js +5 -4
  166. package/dist/commands/research/backfill.js.map +1 -1
  167. package/dist/commands/research/tail-transcript.js +5 -4
  168. package/dist/commands/research/tail-transcript.js.map +1 -1
  169. package/dist/commands/service/install.js +6 -6
  170. package/dist/commands/service/status.js +4 -3
  171. package/dist/commands/service/status.js.map +1 -1
  172. package/dist/commands/service/uninstall.js +4 -3
  173. package/dist/commands/service/uninstall.js.map +1 -1
  174. package/dist/commands/sessions/analyze.js +4 -3
  175. package/dist/commands/sessions/analyze.js.map +1 -1
  176. package/dist/commands/sessions/end.js +4 -3
  177. package/dist/commands/sessions/end.js.map +1 -1
  178. package/dist/commands/sessions/import.js +4 -3
  179. package/dist/commands/sessions/import.js.map +1 -1
  180. package/dist/commands/sessions/list.js +4 -3
  181. package/dist/commands/sessions/list.js.map +1 -1
  182. package/dist/commands/sessions/start.js +4 -3
  183. package/dist/commands/sessions/start.js.map +1 -1
  184. package/dist/commands/setup.js +10 -6
  185. package/dist/commands/setup.js.map +1 -1
  186. package/dist/commands/skills/export-approved.js +4 -3
  187. package/dist/commands/skills/export-approved.js.map +1 -1
  188. package/dist/commands/skills/install.js +4 -3
  189. package/dist/commands/skills/install.js.map +1 -1
  190. package/dist/commands/skills/list.js +4 -3
  191. package/dist/commands/skills/list.js.map +1 -1
  192. package/dist/commands/skills/publish.js +4 -3
  193. package/dist/commands/skills/publish.js.map +1 -1
  194. package/dist/commands/skills/search.js +4 -3
  195. package/dist/commands/skills/search.js.map +1 -1
  196. package/dist/commands/skills/update.js +4 -3
  197. package/dist/commands/skills/update.js.map +1 -1
  198. package/dist/commands/suggestions/accept.js +4 -3
  199. package/dist/commands/suggestions/accept.js.map +1 -1
  200. package/dist/commands/suggestions/dismiss.js +4 -3
  201. package/dist/commands/suggestions/dismiss.js.map +1 -1
  202. package/dist/commands/suggestions/list.js +4 -3
  203. package/dist/commands/suggestions/list.js.map +1 -1
  204. package/dist/commands/suggestions/refresh.js +4 -3
  205. package/dist/commands/suggestions/refresh.js.map +1 -1
  206. package/dist/dashboard/Dashboard.js +16 -16
  207. package/dist/dashboard/data.js +2 -2
  208. package/dist/dashboard/launcher/ActiveJobsList.js +2 -2
  209. package/dist/dashboard/launcher/LauncherOverlay.js +7 -7
  210. package/dist/dashboard/launcher/NewLaunchForm.js +2 -2
  211. package/dist/dashboard/launcher/api.js +2 -2
  212. package/dist/dashboard/launcher/useLaunchJobs.js +3 -3
  213. package/dist/lib/active-org-refresh.js +2 -2
  214. package/dist/lib/agent-loop.js +20 -18
  215. package/dist/lib/antigravity-transcript.js +2 -2
  216. package/dist/lib/api-client.js +1 -1
  217. package/dist/lib/diagnostics.js +12 -0
  218. package/dist/lib/diagnostics.js.map +7 -0
  219. package/dist/lib/ensure-api-key.js +3 -3
  220. package/dist/lib/eval-benchmark.js +2 -2
  221. package/dist/lib/eval-conversation-handler.js +2 -2
  222. package/dist/lib/gateway-entry.js +39 -1
  223. package/dist/lib/gateway-entry.js.map +2 -2
  224. package/dist/lib/gateway-identity.js +16 -0
  225. package/dist/lib/gateway-identity.js.map +7 -0
  226. package/dist/lib/gateway-lifecycle.js +9 -3
  227. package/dist/lib/gateway.js +3 -1
  228. package/dist/lib/handlers/cron-suggest-instructions.js +3 -3
  229. package/dist/lib/handlers/process-announcement.js +3 -3
  230. package/dist/lib/handlers/process-changelog.js +3 -3
  231. package/dist/lib/handlers/process-conversation.js +3 -3
  232. package/dist/lib/handlers/process-eval.js +3 -3
  233. package/dist/lib/handlers/process-insights.js +3 -3
  234. package/dist/lib/handlers/process-launch.js +2 -2
  235. package/dist/lib/handlers/process-run-cleanup.js +2 -2
  236. package/dist/lib/handlers/process-session-goal.js +2 -2
  237. package/dist/lib/hooks-config.js +14 -1
  238. package/dist/lib/manual-tasks.js +6 -6
  239. package/dist/lib/pid-identity.js +14 -0
  240. package/dist/lib/pid-identity.js.map +7 -0
  241. package/dist/lib/proxy-respawn.js +12 -0
  242. package/dist/lib/proxy-respawn.js.map +7 -0
  243. package/dist/lib/research-client.js +2 -2
  244. package/dist/lib/setup-steps.js +7 -4
  245. package/dist/lib/statusline-shim.js +3 -1
  246. package/dist/lib/telemetry.js +4 -2
  247. package/dist/lib/terminal-target-heartbeat.js +2 -2
  248. package/oclif.manifest.json +34 -1
  249. package/package.json +6 -6
  250. package/dist/chunk-6EMZI4Y3.js.map +0 -7
  251. package/dist/chunk-BBLTN35F.js.map +0 -7
  252. package/dist/chunk-DAJNO4OI.js.map +0 -7
  253. package/dist/chunk-PXVQLD7S.js.map +0 -7
  254. package/dist/chunk-SZ7VDCD6.js.map +0 -7
  255. package/dist/chunk-TX2HKJLA.js +0 -55
  256. package/dist/chunk-TX2HKJLA.js.map +0 -7
  257. package/dist/chunk-XN23W5HL.js.map +0 -7
  258. package/dist/chunk-XNNOXGP6.js.map +0 -7
  259. package/dist/chunk-ZRLYHBPN.js.map +0 -7
  260. /package/dist/{chunk-RUCSRN7F.js.map → chunk-2ORJWTNZ.js.map} +0 -0
  261. /package/dist/{chunk-SLL3OBKN.js.map → chunk-37LN5O7M.js.map} +0 -0
  262. /package/dist/{chunk-RCMXTLQF.js.map → chunk-3LKVS6W5.js.map} +0 -0
  263. /package/dist/{chunk-UPXIO7CG.js.map → chunk-4XAWK6S2.js.map} +0 -0
  264. /package/dist/{chunk-N5A2IQAK.js.map → chunk-4YAP7RT7.js.map} +0 -0
  265. /package/dist/{chunk-QD6X4L4L.js.map → chunk-5BAOGNUH.js.map} +0 -0
  266. /package/dist/{chunk-5ADHO5QF.js.map → chunk-6NBS5XFS.js.map} +0 -0
  267. /package/dist/{chunk-DTFXCHHI.js.map → chunk-DNKSVWMD.js.map} +0 -0
  268. /package/dist/{chunk-YSEQWCN4.js.map → chunk-EYPAAGN5.js.map} +0 -0
  269. /package/dist/{chunk-JEJ3J5J6.js.map → chunk-GIUBARWS.js.map} +0 -0
  270. /package/dist/{chunk-CNMWYYSV.js.map → chunk-HZK43UCF.js.map} +0 -0
  271. /package/dist/{chunk-OTOWLUOJ.js.map → chunk-JULOLTZS.js.map} +0 -0
  272. /package/dist/{chunk-DR5WLIOU.js.map → chunk-KJKBDQ4D.js.map} +0 -0
  273. /package/dist/{chunk-AHDRN6NE.js.map → chunk-OO7JDFS4.js.map} +0 -0
  274. /package/dist/{chunk-3QH73QOQ.js.map → chunk-PED7L5GX.js.map} +0 -0
  275. /package/dist/{chunk-VBGUNFKY.js.map → chunk-PMI56ED5.js.map} +0 -0
  276. /package/dist/{chunk-W4MZXKZ2.js.map → chunk-UKMLICWS.js.map} +0 -0
  277. /package/dist/{chunk-3POYC5NA.js.map → chunk-XK42ZBDE.js.map} +0 -0
  278. /package/dist/{chunk-ZSGKRCKD.js.map → chunk-XUV6DDBF.js.map} +0 -0
  279. /package/dist/{chunk-LAKZUE35.js.map → chunk-Y3WD5CSW.js.map} +0 -0
  280. /package/dist/{chunk-3QVMIJUL.js.map → chunk-YOBA3NAM.js.map} +0 -0
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  BaseCommand
3
- } from "../../chunk-SZ7VDCD6.js";
3
+ } from "../../chunk-2HK7RGZB.js";
4
4
  import "../../chunk-R56PH7YE.js";
5
- import "../../chunk-SLL3OBKN.js";
5
+ import "../../chunk-GQNJO2P2.js";
6
+ import "../../chunk-37LN5O7M.js";
6
7
  import "../../chunk-EKJ2CABV.js";
7
- import "../../chunk-ZRLYHBPN.js";
8
+ import "../../chunk-ZUJBM6HE.js";
8
9
  import "../../chunk-W2YERO7E.js";
9
10
  import "../../chunk-NSBPE2FW.js";
10
11
 
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/commands/proxy/logs.ts"],
4
4
  "sourcesContent": ["import { Flags } from '@oclif/core';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { BaseCommand } from '../../base-command.js';\n\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst LOG_FILE = join(CONFIG_DIR, 'proxy.log');\nconst PID_FILE = join(CONFIG_DIR, 'proxy.pid');\nconst DOCKER_CONTAINER = 'rulemetric-proxy';\n\nexport default class ProxyLogs extends BaseCommand {\n static override description = 'View context capture proxy logs';\n\n static override examples = [\n '<%= config.bin %> proxy logs',\n '<%= config.bin %> proxy logs --follow',\n '<%= config.bin %> proxy logs --lines 50',\n ];\n\n static override flags = {\n follow: Flags.boolean({\n char: 'f',\n default: false,\n description: 'Follow log output (like tail -f)',\n }),\n lines: Flags.integer({\n char: 'n',\n default: 30,\n description: 'Number of lines to show',\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(ProxyLogs);\n\n // Check if running in Docker mode\n const isDocker = existsSync(PID_FILE) && readFileSync(PID_FILE, 'utf-8').trim().startsWith('docker:');\n\n if (isDocker) {\n const args = ['logs'];\n if (flags.follow) args.push('-f');\n args.push('--tail', String(flags.lines), DOCKER_CONTAINER);\n\n const child = spawn('docker', args, { stdio: 'inherit' });\n\n process.on('SIGINT', () => {\n child.kill();\n process.exit(0);\n });\n\n await new Promise<void>((resolve) => {\n child.on('exit', () => resolve());\n });\n return;\n }\n\n // Local mode \u2014 read log file\n if (!existsSync(LOG_FILE)) {\n this.log(`No proxy log file found at ${LOG_FILE}`);\n this.log('Start the proxy first: rulemetric proxy start');\n return;\n }\n\n if (flags.follow) {\n const tail = spawn('tail', ['-f', '-n', String(flags.lines), LOG_FILE], {\n stdio: 'inherit',\n });\n\n process.on('SIGINT', () => {\n tail.kill();\n process.exit(0);\n });\n\n await new Promise<void>((resolve) => {\n tail.on('exit', () => resolve());\n });\n } else {\n const content = readFileSync(LOG_FILE, 'utf-8');\n const lines = content.split('\\n');\n const lastN = lines.slice(-flags.lines).join('\\n');\n this.log(lastN);\n }\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;AAAA,SAAS,aAAa;AACtB,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,aAAa;AAGtB,IAAM,aAAa,KAAK,QAAQ,GAAG,WAAW,YAAY;AAC1D,IAAM,WAAW,KAAK,YAAY,WAAW;AAC7C,IAAM,WAAW,KAAK,YAAY,WAAW;AAC7C,IAAM,mBAAmB;AAEzB,IAAqB,YAArB,MAAqB,mBAAkB,YAAY;AAAA,EACjD,OAAgB,cAAc;AAAA,EAE9B,OAAgB,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EAEA,OAAgB,QAAQ;AAAA,IACtB,QAAQ,MAAM,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AAAA,IACD,OAAO,MAAM,QAAQ;AAAA,MACnB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,UAAS;AAG5C,UAAM,WAAW,WAAW,QAAQ,KAAK,aAAa,UAAU,OAAO,EAAE,KAAK,EAAE,WAAW,SAAS;AAEpG,QAAI,UAAU;AACZ,YAAM,OAAO,CAAC,MAAM;AACpB,UAAI,MAAM,OAAQ,MAAK,KAAK,IAAI;AAChC,WAAK,KAAK,UAAU,OAAO,MAAM,KAAK,GAAG,gBAAgB;AAEzD,YAAM,QAAQ,MAAM,UAAU,MAAM,EAAE,OAAO,UAAU,CAAC;AAExD,cAAQ,GAAG,UAAU,MAAM;AACzB,cAAM,KAAK;AACX,gBAAQ,KAAK,CAAC;AAAA,MAChB,CAAC;AAED,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,cAAM,GAAG,QAAQ,MAAM,QAAQ,CAAC;AAAA,MAClC,CAAC;AACD;AAAA,IACF;AAGA,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAK,IAAI,8BAA8B,QAAQ,EAAE;AACjD,WAAK,IAAI,+CAA+C;AACxD;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ;AAChB,YAAM,OAAO,MAAM,QAAQ,CAAC,MAAM,MAAM,OAAO,MAAM,KAAK,GAAG,QAAQ,GAAG;AAAA,QACtE,OAAO;AAAA,MACT,CAAC;AAED,cAAQ,GAAG,UAAU,MAAM;AACzB,aAAK,KAAK;AACV,gBAAQ,KAAK,CAAC;AAAA,MAChB,CAAC;AAED,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,aAAK,GAAG,QAAQ,MAAM,QAAQ,CAAC;AAAA,MACjC,CAAC;AAAA,IACH,OAAO;AACL,YAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,YAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,YAAM,QAAQ,MAAM,MAAM,CAAC,MAAM,KAAK,EAAE,KAAK,IAAI;AACjD,WAAK,IAAI,KAAK;AAAA,IAChB;AAAA,EACF;AACF;",
5
+ "mappings": ";;;;;;;;;;;;AAAA,SAAS,aAAa;AACtB,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,aAAa;AAGtB,IAAM,aAAa,KAAK,QAAQ,GAAG,WAAW,YAAY;AAC1D,IAAM,WAAW,KAAK,YAAY,WAAW;AAC7C,IAAM,WAAW,KAAK,YAAY,WAAW;AAC7C,IAAM,mBAAmB;AAEzB,IAAqB,YAArB,MAAqB,mBAAkB,YAAY;AAAA,EACjD,OAAgB,cAAc;AAAA,EAE9B,OAAgB,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EAEA,OAAgB,QAAQ;AAAA,IACtB,QAAQ,MAAM,QAAQ;AAAA,MACpB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AAAA,IACD,OAAO,MAAM,QAAQ;AAAA,MACnB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,UAAS;AAG5C,UAAM,WAAW,WAAW,QAAQ,KAAK,aAAa,UAAU,OAAO,EAAE,KAAK,EAAE,WAAW,SAAS;AAEpG,QAAI,UAAU;AACZ,YAAM,OAAO,CAAC,MAAM;AACpB,UAAI,MAAM,OAAQ,MAAK,KAAK,IAAI;AAChC,WAAK,KAAK,UAAU,OAAO,MAAM,KAAK,GAAG,gBAAgB;AAEzD,YAAM,QAAQ,MAAM,UAAU,MAAM,EAAE,OAAO,UAAU,CAAC;AAExD,cAAQ,GAAG,UAAU,MAAM;AACzB,cAAM,KAAK;AACX,gBAAQ,KAAK,CAAC;AAAA,MAChB,CAAC;AAED,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,cAAM,GAAG,QAAQ,MAAM,QAAQ,CAAC;AAAA,MAClC,CAAC;AACD;AAAA,IACF;AAGA,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAK,IAAI,8BAA8B,QAAQ,EAAE;AACjD,WAAK,IAAI,+CAA+C;AACxD;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ;AAChB,YAAM,OAAO,MAAM,QAAQ,CAAC,MAAM,MAAM,OAAO,MAAM,KAAK,GAAG,QAAQ,GAAG;AAAA,QACtE,OAAO;AAAA,MACT,CAAC;AAED,cAAQ,GAAG,UAAU,MAAM;AACzB,aAAK,KAAK;AACV,gBAAQ,KAAK,CAAC;AAAA,MAChB,CAAC;AAED,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,aAAK,GAAG,QAAQ,MAAM,QAAQ,CAAC;AAAA,MACjC,CAAC;AAAA,IACH,OAAO;AACL,YAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,YAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,YAAM,QAAQ,MAAM,MAAM,CAAC,MAAM,KAAK,EAAE,KAAK,IAAI;AACjD,WAAK,IAAI,KAAK;AAAA,IAChB;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  BaseCommand
3
- } from "../../chunk-SZ7VDCD6.js";
3
+ } from "../../chunk-2HK7RGZB.js";
4
4
  import "../../chunk-R56PH7YE.js";
5
- import "../../chunk-SLL3OBKN.js";
5
+ import "../../chunk-GQNJO2P2.js";
6
+ import "../../chunk-37LN5O7M.js";
6
7
  import "../../chunk-EKJ2CABV.js";
7
- import "../../chunk-ZRLYHBPN.js";
8
+ import "../../chunk-ZUJBM6HE.js";
8
9
  import "../../chunk-W2YERO7E.js";
9
10
  import "../../chunk-NSBPE2FW.js";
10
11
 
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/commands/proxy/restart.ts"],
4
4
  "sourcesContent": ["// `rulemetric proxy restart` \u2014 stop + start in one command. Used by the\n// gateway when it detects an addon version drift (the proxy is loading\n// stale code from a previous CLI version), and by humans who just want\n// the obvious one-liner.\n//\n// We invoke the existing stop and start commands via oclif's runCommand\n// rather than re-implementing their logic. This keeps the addon-path\n// resolution, auth-env loading, and PID file management in exactly one\n// place.\nimport { Flags } from '@oclif/core';\nimport { setTimeout as sleep } from 'node:timers/promises';\nimport { BaseCommand } from '../../base-command.js';\n\nexport default class ProxyRestart extends BaseCommand {\n static override description = 'Restart the context capture proxy (stop + start)';\n static override examples = ['<%= config.bin %> proxy restart'];\n static override flags = {\n port: Flags.integer({ char: 'p', description: 'Proxy listen port' }),\n docker: Flags.boolean({ char: 'd', default: false, description: 'Run in Docker mode' }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(ProxyRestart);\n // Stop is idempotent \u2014 exits cleanly even if nothing is running.\n await this.config.runCommand('proxy:stop', []);\n // Brief gap so the OS releases the port before we re-bind. Without this,\n // the new mitmdump can race with the dying process and fail with\n // \"address already in use\".\n await sleep(500);\n const args: string[] = ['--skip-checks'];\n if (flags.docker) args.push('--docker');\n if (flags.port) args.push('--port', String(flags.port));\n await this.config.runCommand('proxy:start', args);\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;AASA,SAAS,aAAa;AACtB,SAAS,cAAc,aAAa;AAGpC,IAAqB,eAArB,MAAqB,sBAAqB,YAAY;AAAA,EACpD,OAAgB,cAAc;AAAA,EAC9B,OAAgB,WAAW,CAAC,iCAAiC;AAAA,EAC7D,OAAgB,QAAQ;AAAA,IACtB,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,aAAa,oBAAoB,CAAC;AAAA,IACnE,QAAQ,MAAM,QAAQ,EAAE,MAAM,KAAK,SAAS,OAAO,aAAa,qBAAqB,CAAC;AAAA,EACxF;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,aAAY;AAE/C,UAAM,KAAK,OAAO,WAAW,cAAc,CAAC,CAAC;AAI7C,UAAM,MAAM,GAAG;AACf,UAAM,OAAiB,CAAC,eAAe;AACvC,QAAI,MAAM,OAAQ,MAAK,KAAK,UAAU;AACtC,QAAI,MAAM,KAAM,MAAK,KAAK,UAAU,OAAO,MAAM,IAAI,CAAC;AACtD,UAAM,KAAK,OAAO,WAAW,eAAe,IAAI;AAAA,EAClD;AACF;",
5
+ "mappings": ";;;;;;;;;;;;AASA,SAAS,aAAa;AACtB,SAAS,cAAc,aAAa;AAGpC,IAAqB,eAArB,MAAqB,sBAAqB,YAAY;AAAA,EACpD,OAAgB,cAAc;AAAA,EAC9B,OAAgB,WAAW,CAAC,iCAAiC;AAAA,EAC7D,OAAgB,QAAQ;AAAA,IACtB,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,aAAa,oBAAoB,CAAC;AAAA,IACnE,QAAQ,MAAM,QAAQ,EAAE,MAAM,KAAK,SAAS,OAAO,aAAa,qBAAqB,CAAC;AAAA,EACxF;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,aAAY;AAE/C,UAAM,KAAK,OAAO,WAAW,cAAc,CAAC,CAAC;AAI7C,UAAM,MAAM,GAAG;AACf,UAAM,OAAiB,CAAC,eAAe;AACvC,QAAI,MAAM,OAAQ,MAAK,KAAK,UAAU;AACtC,QAAI,MAAM,KAAM,MAAK,KAAK,UAAU,OAAO,MAAM,IAAI,CAAC;AACtD,UAAM,KAAK,OAAO,WAAW,eAAe,IAAI;AAAA,EAClD;AACF;",
6
6
  "names": []
7
7
  }
@@ -3,11 +3,12 @@ import {
3
3
  } from "../../chunk-42GFSAJP.js";
4
4
  import {
5
5
  BaseCommand
6
- } from "../../chunk-SZ7VDCD6.js";
6
+ } from "../../chunk-2HK7RGZB.js";
7
7
  import "../../chunk-R56PH7YE.js";
8
- import "../../chunk-SLL3OBKN.js";
8
+ import "../../chunk-GQNJO2P2.js";
9
+ import "../../chunk-37LN5O7M.js";
9
10
  import "../../chunk-EKJ2CABV.js";
10
- import "../../chunk-ZRLYHBPN.js";
11
+ import "../../chunk-ZUJBM6HE.js";
11
12
  import {
12
13
  isAuthenticated
13
14
  } from "../../chunk-W2YERO7E.js";
@@ -227,8 +228,21 @@ var ProxySetup = class _ProxySetup extends BaseCommand {
227
228
  return false;
228
229
  }
229
230
  async checkHooks() {
230
- const settingsPath = join(process.cwd(), ".claude", "settings.json");
231
- if (!existsSync(settingsPath)) {
231
+ let sawSettingsFile = false;
232
+ for (const fileName of ["settings.local.json", "settings.json"]) {
233
+ const settingsPath = join(process.cwd(), ".claude", fileName);
234
+ if (!existsSync(settingsPath)) continue;
235
+ sawSettingsFile = true;
236
+ try {
237
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
238
+ const hasHooks = settings.hooks && Object.keys(settings.hooks).length > 0;
239
+ if (hasHooks) {
240
+ return { name: "Session Hooks", ok: true, message: "Installed in current project" };
241
+ }
242
+ } catch {
243
+ }
244
+ }
245
+ if (!sawSettingsFile) {
232
246
  return {
233
247
  name: "Session Hooks",
234
248
  ok: false,
@@ -239,18 +253,10 @@ var ProxySetup = class _ProxySetup extends BaseCommand {
239
253
  }
240
254
  };
241
255
  }
242
- try {
243
- const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
244
- const hasHooks = settings.hooks && Object.keys(settings.hooks).length > 0;
245
- if (hasHooks) {
246
- return { name: "Session Hooks", ok: true, message: "Installed in current project" };
247
- }
248
- } catch {
249
- }
250
256
  return {
251
257
  name: "Session Hooks",
252
258
  ok: false,
253
- message: "settings.json exists but hooks not configured",
259
+ message: "settings file exists but hooks not configured",
254
260
  fix: async () => {
255
261
  this.log(" Run `rulemetric hooks install` to configure hooks.");
256
262
  return false;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/commands/proxy/setup.ts"],
4
- "sourcesContent": ["import { Flags } from '@oclif/core';\nimport { execSync, spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync, appendFileSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { BaseCommand } from '../../base-command.js';\nimport { isAuthenticated } from '../../lib/auth.js';\nimport { findBinary } from '../../lib/which.js';\n\nconst CERT_PATH = join(homedir(), '.mitmproxy', 'mitmproxy-ca-cert.pem');\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst DEFAULT_PORT = 8787;\n\ninterface CheckResult {\n name: string;\n ok: boolean;\n message: string;\n fix?: () => Promise<boolean>;\n}\n\nexport default class ProxySetup extends BaseCommand {\n static override description = 'Set up context capture proxy (installs mitmproxy, configures shell)';\n\n static override examples = [\n '<%= config.bin %> proxy setup',\n '<%= config.bin %> proxy setup --shell zsh',\n '<%= config.bin %> proxy setup --check',\n ];\n\n static override flags = {\n shell: Flags.string({\n description: 'Shell to configure (auto-detected if omitted)',\n options: ['zsh', 'bash', 'fish', 'powershell'],\n }),\n port: Flags.integer({\n char: 'p',\n default: DEFAULT_PORT,\n description: 'Proxy listen port',\n }),\n check: Flags.boolean({\n description: 'Only check prerequisites, do not install anything',\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(ProxySetup);\n const checkOnly = flags.check;\n const port = flags.port;\n\n this.log('RuleMetric Proxy Setup');\n this.log('=====================\\n');\n\n const checks: CheckResult[] = [\n await this.checkAuth(),\n await this.checkMitmproxy(),\n await this.checkCACert(),\n await this.checkHooks(),\n this.checkShellEnv(port),\n ];\n\n // Display results\n let allPassed = true;\n for (const check of checks) {\n const icon = check.ok ? '[OK]' : '[!!]';\n this.log(`${icon} ${check.name}: ${check.message}`);\n if (!check.ok) allPassed = false;\n }\n\n if (allPassed) {\n this.log('\\nAll checks passed. Run `rulemetric proxy start` to begin capturing.');\n return;\n }\n\n if (checkOnly) {\n this.log('\\nSome checks failed. Run `rulemetric proxy setup` (without --check) to fix.');\n return;\n }\n\n // Fix failures\n this.log('\\nFixing issues...\\n');\n\n for (const check of checks) {\n if (check.ok || !check.fix) continue;\n this.log(`Fixing: ${check.name}...`);\n const fixed = await check.fix();\n if (fixed) {\n this.log(` Fixed.\\n`);\n } else {\n this.log(` Could not auto-fix. See instructions above.\\n`);\n }\n }\n\n // Re-check\n this.log('---\\nVerifying...\\n');\n const reChecks = [\n await this.checkAuth(),\n await this.checkMitmproxy(),\n await this.checkCACert(),\n await this.checkHooks(),\n this.checkShellEnv(port),\n ];\n\n let finalOk = true;\n for (const check of reChecks) {\n const icon = check.ok ? '[OK]' : '[!!]';\n this.log(`${icon} ${check.name}: ${check.message}`);\n if (!check.ok) finalOk = false;\n }\n\n if (finalOk) {\n this.log('\\nSetup complete! Next steps:');\n this.log(' 1. Restart your shell (or run `source ~/.zshrc`)');\n this.log(' 2. Run `rulemetric proxy start`');\n this.log(' 3. Start Claude Code \u2014 context will be captured automatically');\n } else {\n this.log('\\nSome issues remain. Fix manually and re-run `rulemetric proxy setup --check`.');\n }\n }\n\n private async checkAuth(): Promise<CheckResult> {\n // Check JWT auth (auth.json)\n if (isAuthenticated()) {\n return { name: 'Authentication', ok: true, message: 'Logged in (JWT)' };\n }\n\n // Check API key auth (env vars or env file)\n const apiKey = process.env.RULEMETRIC_API_KEY;\n if (apiKey) {\n return { name: 'Authentication', ok: true, message: `API key (RULEMETRIC_API_KEY=${apiKey.slice(0, 8)}...)` };\n }\n\n // Check env file\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n if (existsSync(envFile)) {\n const content = readFileSync(envFile, 'utf-8');\n if (content.includes('RULEMETRIC_API_KEY') || content.includes('RULEMETRIC_ACCESS_TOKEN')) {\n return { name: 'Authentication', ok: true, message: 'Configured via ~/.config/rulemetric/env' };\n }\n }\n\n return {\n name: 'Authentication',\n ok: false,\n message: 'Not authenticated',\n fix: async () => {\n this.log(' Run `rulemetric auth login` to authenticate.');\n this.log(' Or set RULEMETRIC_API_KEY in ~/.config/rulemetric/env.');\n return false;\n },\n };\n }\n\n private async checkMitmproxy(): Promise<CheckResult> {\n const binary = this.findBinary('mitmdump');\n if (binary) {\n // Get version\n try {\n const output = execSync(`${binary} --version 2>&1`, { encoding: 'utf-8' });\n const version = output.match(/Mitmproxy:\\s*([\\d.]+)/)?.[1] ?? 'unknown';\n return { name: 'mitmproxy', ok: true, message: `Installed (v${version})` };\n } catch {\n return { name: 'mitmproxy', ok: true, message: `Found at ${binary}` };\n }\n }\n\n return {\n name: 'mitmproxy',\n ok: false,\n message: 'Not installed',\n fix: async () => this.installMitmproxy(),\n };\n }\n\n private async installMitmproxy(): Promise<boolean> {\n // Try pipx first (cleanest isolation)\n if (this.findBinary('pipx')) {\n this.log(' Installing via pipx...');\n const result = spawnSync('pipx', ['install', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n // Try uv tool install\n if (this.findBinary('uv')) {\n this.log(' Installing via uv...');\n const result = spawnSync('uv', ['tool', 'install', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n // Try pip with --user\n if (this.findBinary('pip3') || this.findBinary('pip')) {\n const pip = this.findBinary('pip3') || this.findBinary('pip')!;\n this.log(` Installing via ${pip} --user...`);\n const result = spawnSync(pip, ['install', '--user', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n // Try brew\n if (this.findBinary('brew')) {\n this.log(' Installing via brew...');\n const result = spawnSync('brew', ['install', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n this.log(' Could not auto-install mitmproxy. Install manually:');\n this.log(' pipx install mitmproxy # recommended');\n this.log(' brew install mitmproxy # macOS');\n this.log(' pip install --user mitmproxy');\n return false;\n }\n\n private async checkCACert(): Promise<CheckResult> {\n if (existsSync(CERT_PATH)) {\n return { name: 'CA Certificate', ok: true, message: `Found at ${CERT_PATH}` };\n }\n\n return {\n name: 'CA Certificate',\n ok: false,\n message: 'Not generated yet',\n fix: async () => this.generateCACert(),\n };\n }\n\n private async generateCACert(): Promise<boolean> {\n const mitmdump = this.findBinary('mitmdump');\n if (!mitmdump) {\n this.log(' Cannot generate cert \u2014 mitmproxy not installed.');\n return false;\n }\n\n // Run mitmdump briefly to generate certs\n this.log(' Generating CA certificate...');\n const result = spawnSync(mitmdump, ['--set', 'listen_port=0', '-q'], {\n timeout: 5000,\n stdio: 'ignore',\n });\n\n // mitmdump will timeout (expected) \u2014 certs should be generated\n if (existsSync(CERT_PATH)) {\n this.log(` Certificate generated at ${CERT_PATH}`);\n\n // On macOS, offer to trust the cert\n if (process.platform === 'darwin') {\n this.log(' Adding CA cert to macOS keychain (may require sudo)...');\n const trustResult = spawnSync('sudo', [\n 'security', 'add-trusted-cert', '-d',\n '-r', 'trustRoot',\n '-k', '/Library/Keychains/System.keychain',\n CERT_PATH,\n ], { stdio: 'inherit' });\n if (trustResult.status === 0) {\n this.log(' CA cert trusted system-wide.');\n } else {\n this.log(' Could not auto-trust cert. You may need NODE_EXTRA_CA_CERTS env var.');\n }\n }\n\n return true;\n }\n\n this.log(' Failed to generate cert. Try running: mitmdump --help');\n return false;\n }\n\n private async checkHooks(): Promise<CheckResult> {\n const settingsPath = join(process.cwd(), '.claude', 'settings.json');\n if (!existsSync(settingsPath)) {\n return {\n name: 'Session Hooks',\n ok: false,\n message: 'Not installed in current project',\n fix: async () => {\n this.log(' Run `rulemetric hooks install` in your project directory.');\n return false; // User needs to run in the right directory\n },\n };\n }\n\n try {\n const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n const hasHooks = settings.hooks && Object.keys(settings.hooks).length > 0;\n if (hasHooks) {\n return { name: 'Session Hooks', ok: true, message: 'Installed in current project' };\n }\n } catch { /* fall through */ }\n\n return {\n name: 'Session Hooks',\n ok: false,\n message: 'settings.json exists but hooks not configured',\n fix: async () => {\n this.log(' Run `rulemetric hooks install` to configure hooks.');\n return false;\n },\n };\n }\n\n private checkShellEnv(port: number): CheckResult {\n const proxySet = process.env.HTTPS_PROXY?.includes(String(port));\n const certSet = !!process.env.NODE_EXTRA_CA_CERTS;\n\n if (proxySet && certSet) {\n return { name: 'Shell Environment', ok: true, message: 'HTTPS_PROXY and NODE_EXTRA_CA_CERTS set' };\n }\n\n const missing: string[] = [];\n if (!proxySet) missing.push('HTTPS_PROXY');\n if (!certSet) missing.push('NODE_EXTRA_CA_CERTS');\n\n return {\n name: 'Shell Environment',\n ok: false,\n message: `Missing: ${missing.join(', ')}`,\n fix: async () => this.writeShellEnv(port),\n };\n }\n\n private async writeShellEnv(port: number): Promise<boolean> {\n const shell = this.detectShell();\n const rcFile = this.getShellRcFile(shell);\n\n if (!rcFile) {\n this.log(` Could not detect shell RC file. Add these to your shell profile:`);\n this.log(` export HTTPS_PROXY=http://localhost:${port}`);\n this.log(` export NODE_EXTRA_CA_CERTS=${CERT_PATH}`);\n return false;\n }\n\n const oldMarker = '# RuleMetric proxy';\n const marker = '# RuleMetric proxy (auto-detect)';\n const envFile = join(CONFIG_DIR, 'proxy.env');\n const pidFile = join(CONFIG_DIR, 'proxy.pid');\n\n // The sentinel proves the block is already installed (idempotency). POSIX\n // shells share one function name; PowerShell uses its own.\n const sentinel = shell === 'powershell' ? '_RuleMetricProxyCheck' : '_rulemetric_proxy_check';\n\n // Dynamic proxy env: re-evaluates on every prompt so stopping the proxy\n // immediately unsets HTTPS_PROXY without needing a new shell.\n const block = shell === 'powershell'\n ? this.buildPowerShellBlock(marker, pidFile, port)\n : shell === 'fish'\n ? [\n '',\n marker,\n 'function _rulemetric_proxy_check',\n ` if test -f ${pidFile}; and kill -0 (cat ${pidFile}) 2>/dev/null`,\n ` source ${envFile} 2>/dev/null`,\n ' else',\n ' set -e HTTPS_PROXY 2>/dev/null',\n ' set -e NODE_EXTRA_CA_CERTS 2>/dev/null',\n ' end',\n 'end',\n '',\n ].join('\\n')\n : shell === 'zsh'\n ? [\n '',\n marker,\n '_rulemetric_proxy_check() {',\n ` if [ -f \"${pidFile}\" ] && kill -0 \"$(cat \"${pidFile}\" 2>/dev/null)\" 2>/dev/null; then`,\n ` [ -z \"\\${HTTPS_PROXY:-}\" ] && source \"${envFile}\" 2>/dev/null`,\n ' else',\n ` [ -n \"\\${HTTPS_PROXY:-}\" ] && unset HTTPS_PROXY NODE_EXTRA_CA_CERTS`,\n ' fi',\n '}',\n 'precmd_functions+=(_rulemetric_proxy_check)',\n '',\n ].join('\\n')\n : [\n '',\n marker,\n '_rulemetric_proxy_check() {',\n ` if [ -f \"${pidFile}\" ] && kill -0 \"$(cat \"${pidFile}\" 2>/dev/null)\" 2>/dev/null; then`,\n ` [ -z \"\\${HTTPS_PROXY:-}\" ] && source \"${envFile}\" 2>/dev/null`,\n ' else',\n ` [ -n \"\\${HTTPS_PROXY:-}\" ] && unset HTTPS_PROXY NODE_EXTRA_CA_CERTS`,\n ' fi',\n '}',\n 'PROMPT_COMMAND=\"_rulemetric_proxy_check${PROMPT_COMMAND:+;$PROMPT_COMMAND}\"',\n '',\n ].join('\\n');\n\n // The PowerShell `$PROFILE` directory frequently does not exist yet; create\n // it (and any other missing rc dir, e.g. fish) before appending.\n mkdirSync(dirname(rcFile), { recursive: true });\n\n if (existsSync(rcFile)) {\n let content = readFileSync(rcFile, 'utf-8');\n\n // Remove old static block if present\n if (content.includes(oldMarker) && !content.includes(marker)) {\n content = content.replace(\n /\\n# RuleMetric proxy\\nexport HTTPS_PROXY=[^\\n]*\\nexport NODE_EXTRA_CA_CERTS=[^\\n]*\\n/,\n '\\n',\n );\n writeFileSync(rcFile, content);\n this.log(` Removed old static env vars from ${rcFile}`);\n }\n\n // Remove old auto-detect block (the one without precmd that doesn't unset on stop)\n if (content.includes('# RuleMetric proxy (auto-detect') && !content.includes('_rulemetric_proxy_check')) {\n content = content.replace(\n /\\n# RuleMetric proxy \\(auto-detect[^\\n]*\\)\\nif \\[.*?\\nfi\\n/s,\n '\\n',\n );\n writeFileSync(rcFile, content);\n this.log(` Upgraded old auto-detect block in ${rcFile}`);\n }\n\n if (content.includes(sentinel)) {\n this.log(` Shell env already configured in ${rcFile}`);\n return true;\n }\n }\n\n this.log(` Appending proxy auto-detect hook to ${rcFile}`);\n this.log(` (HTTPS_PROXY is set/unset automatically when proxy starts/stops)`);\n appendFileSync(rcFile, block);\n return true;\n }\n\n private detectShell(): string {\n // On Windows there is no $SHELL and PowerShell is the de-facto shell.\n if (process.platform === 'win32') return 'powershell';\n const shell = process.env.SHELL || '';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('bash')) return 'bash';\n if (shell.includes('fish')) return 'fish';\n return 'zsh'; // default on macOS\n }\n\n private getShellRcFile(shell: string): string | null {\n const home = homedir();\n switch (shell) {\n case 'zsh': return join(home, '.zshrc');\n case 'bash': return join(home, '.bashrc');\n case 'fish': return join(home, '.config', 'fish', 'config.fish');\n case 'powershell': return this.getPowerShellProfilePath();\n default: return null;\n }\n }\n\n /**\n * Resolve the PowerShell profile that loads for every host (console, VS Code\n * integrated terminal, etc.). We ask PowerShell itself for the canonical path\n * \u2014 guessing `~/Documents/...` is wrong when Documents is OneDrive-redirected.\n * Falls back to the PowerShell 7 default only if no PS binary is reachable.\n */\n private getPowerShellProfilePath(): string {\n const psBin = findBinary('pwsh') || findBinary('powershell');\n if (psBin) {\n try {\n const out = execSync(`\"${psBin}\" -NoProfile -Command \"$PROFILE.CurrentUserAllHosts\"`, {\n encoding: 'utf-8',\n }).trim();\n if (out) return out;\n } catch {\n /* fall through to constructed default */\n }\n }\n return join(homedir(), 'Documents', 'PowerShell', 'profile.ps1');\n }\n\n /**\n * Self-contained PowerShell prompt hook. Unlike the POSIX blocks it does NOT\n * source `proxy.env` (that file is `export KEY=val` syntax PowerShell can't\n * read) \u2014 it embeds the values directly. Each prompt it sets HTTPS_PROXY while\n * the proxy PID is alive and removes the vars once it stops, so a dead proxy\n * never leaves a dangling HTTPS_PROXY that would break Claude Code.\n */\n private buildPowerShellBlock(marker: string, pidFile: string, port: number): string {\n const proxyUrl = `http://localhost:${port}`;\n const psPid = pidFile.replace(/'/g, \"''\");\n const psCert = CERT_PATH.replace(/'/g, \"''\");\n return [\n '',\n marker,\n 'function _RuleMetricProxyCheck {',\n ` $pidFile = '${psPid}'`,\n ' $alive = $false',\n ' if (Test-Path $pidFile) {',\n ' $procId = (Get-Content $pidFile -ErrorAction SilentlyContinue | Select-Object -First 1)',\n ' if ($procId -match \\'^\\\\d+$\\' -and (Get-Process -Id ([int]$procId) -ErrorAction SilentlyContinue)) {',\n ' $alive = $true',\n ' }',\n ' }',\n ' if ($alive) {',\n ` $env:HTTPS_PROXY = '${proxyUrl}'`,\n ` $env:HTTP_PROXY = '${proxyUrl}'`,\n ` $env:NODE_EXTRA_CA_CERTS = '${psCert}'`,\n ' } else {',\n ' Remove-Item Env:HTTPS_PROXY, Env:HTTP_PROXY, Env:NODE_EXTRA_CA_CERTS -ErrorAction SilentlyContinue',\n ' }',\n '}',\n '# Wrap the existing prompt once so the check runs every prompt.',\n 'if (-not (Test-Path Function:\\\\_RuleMetricOriginalPrompt)) {',\n ' $existing = Get-Command prompt -ErrorAction SilentlyContinue',\n ' if ($existing) { Set-Item Function:\\\\_RuleMetricOriginalPrompt $existing.ScriptBlock }',\n '}',\n 'function prompt {',\n ' _RuleMetricProxyCheck',\n ' if (Test-Path Function:\\\\_RuleMetricOriginalPrompt) { & _RuleMetricOriginalPrompt } else { \"PS $($PWD.Path)> \" }',\n '}',\n '',\n ].join('\\n');\n }\n\n private findBinary(name: string): string | null {\n // Portable PATH scan \u2014 `which` does not exist on Windows.\n return findBinary(name);\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Flags } from '@oclif/core';\nimport { execSync, spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync, appendFileSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { BaseCommand } from '../../base-command.js';\nimport { isAuthenticated } from '../../lib/auth.js';\nimport { findBinary } from '../../lib/which.js';\n\nconst CERT_PATH = join(homedir(), '.mitmproxy', 'mitmproxy-ca-cert.pem');\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst DEFAULT_PORT = 8787;\n\ninterface CheckResult {\n name: string;\n ok: boolean;\n message: string;\n fix?: () => Promise<boolean>;\n}\n\nexport default class ProxySetup extends BaseCommand {\n static override description = 'Set up context capture proxy (installs mitmproxy, configures shell)';\n\n static override examples = [\n '<%= config.bin %> proxy setup',\n '<%= config.bin %> proxy setup --shell zsh',\n '<%= config.bin %> proxy setup --check',\n ];\n\n static override flags = {\n shell: Flags.string({\n description: 'Shell to configure (auto-detected if omitted)',\n options: ['zsh', 'bash', 'fish', 'powershell'],\n }),\n port: Flags.integer({\n char: 'p',\n default: DEFAULT_PORT,\n description: 'Proxy listen port',\n }),\n check: Flags.boolean({\n description: 'Only check prerequisites, do not install anything',\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(ProxySetup);\n const checkOnly = flags.check;\n const port = flags.port;\n\n this.log('RuleMetric Proxy Setup');\n this.log('=====================\\n');\n\n const checks: CheckResult[] = [\n await this.checkAuth(),\n await this.checkMitmproxy(),\n await this.checkCACert(),\n await this.checkHooks(),\n this.checkShellEnv(port),\n ];\n\n // Display results\n let allPassed = true;\n for (const check of checks) {\n const icon = check.ok ? '[OK]' : '[!!]';\n this.log(`${icon} ${check.name}: ${check.message}`);\n if (!check.ok) allPassed = false;\n }\n\n if (allPassed) {\n this.log('\\nAll checks passed. Run `rulemetric proxy start` to begin capturing.');\n return;\n }\n\n if (checkOnly) {\n this.log('\\nSome checks failed. Run `rulemetric proxy setup` (without --check) to fix.');\n return;\n }\n\n // Fix failures\n this.log('\\nFixing issues...\\n');\n\n for (const check of checks) {\n if (check.ok || !check.fix) continue;\n this.log(`Fixing: ${check.name}...`);\n const fixed = await check.fix();\n if (fixed) {\n this.log(` Fixed.\\n`);\n } else {\n this.log(` Could not auto-fix. See instructions above.\\n`);\n }\n }\n\n // Re-check\n this.log('---\\nVerifying...\\n');\n const reChecks = [\n await this.checkAuth(),\n await this.checkMitmproxy(),\n await this.checkCACert(),\n await this.checkHooks(),\n this.checkShellEnv(port),\n ];\n\n let finalOk = true;\n for (const check of reChecks) {\n const icon = check.ok ? '[OK]' : '[!!]';\n this.log(`${icon} ${check.name}: ${check.message}`);\n if (!check.ok) finalOk = false;\n }\n\n if (finalOk) {\n this.log('\\nSetup complete! Next steps:');\n this.log(' 1. Restart your shell (or run `source ~/.zshrc`)');\n this.log(' 2. Run `rulemetric proxy start`');\n this.log(' 3. Start Claude Code \u2014 context will be captured automatically');\n } else {\n this.log('\\nSome issues remain. Fix manually and re-run `rulemetric proxy setup --check`.');\n }\n }\n\n private async checkAuth(): Promise<CheckResult> {\n // Check JWT auth (auth.json)\n if (isAuthenticated()) {\n return { name: 'Authentication', ok: true, message: 'Logged in (JWT)' };\n }\n\n // Check API key auth (env vars or env file)\n const apiKey = process.env.RULEMETRIC_API_KEY;\n if (apiKey) {\n return { name: 'Authentication', ok: true, message: `API key (RULEMETRIC_API_KEY=${apiKey.slice(0, 8)}...)` };\n }\n\n // Check env file\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n if (existsSync(envFile)) {\n const content = readFileSync(envFile, 'utf-8');\n if (content.includes('RULEMETRIC_API_KEY') || content.includes('RULEMETRIC_ACCESS_TOKEN')) {\n return { name: 'Authentication', ok: true, message: 'Configured via ~/.config/rulemetric/env' };\n }\n }\n\n return {\n name: 'Authentication',\n ok: false,\n message: 'Not authenticated',\n fix: async () => {\n this.log(' Run `rulemetric auth login` to authenticate.');\n this.log(' Or set RULEMETRIC_API_KEY in ~/.config/rulemetric/env.');\n return false;\n },\n };\n }\n\n private async checkMitmproxy(): Promise<CheckResult> {\n const binary = this.findBinary('mitmdump');\n if (binary) {\n // Get version\n try {\n const output = execSync(`${binary} --version 2>&1`, { encoding: 'utf-8' });\n const version = output.match(/Mitmproxy:\\s*([\\d.]+)/)?.[1] ?? 'unknown';\n return { name: 'mitmproxy', ok: true, message: `Installed (v${version})` };\n } catch {\n return { name: 'mitmproxy', ok: true, message: `Found at ${binary}` };\n }\n }\n\n return {\n name: 'mitmproxy',\n ok: false,\n message: 'Not installed',\n fix: async () => this.installMitmproxy(),\n };\n }\n\n private async installMitmproxy(): Promise<boolean> {\n // Try pipx first (cleanest isolation)\n if (this.findBinary('pipx')) {\n this.log(' Installing via pipx...');\n const result = spawnSync('pipx', ['install', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n // Try uv tool install\n if (this.findBinary('uv')) {\n this.log(' Installing via uv...');\n const result = spawnSync('uv', ['tool', 'install', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n // Try pip with --user\n if (this.findBinary('pip3') || this.findBinary('pip')) {\n const pip = this.findBinary('pip3') || this.findBinary('pip')!;\n this.log(` Installing via ${pip} --user...`);\n const result = spawnSync(pip, ['install', '--user', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n // Try brew\n if (this.findBinary('brew')) {\n this.log(' Installing via brew...');\n const result = spawnSync('brew', ['install', 'mitmproxy'], { stdio: 'inherit' });\n if (result.status === 0) return true;\n }\n\n this.log(' Could not auto-install mitmproxy. Install manually:');\n this.log(' pipx install mitmproxy # recommended');\n this.log(' brew install mitmproxy # macOS');\n this.log(' pip install --user mitmproxy');\n return false;\n }\n\n private async checkCACert(): Promise<CheckResult> {\n if (existsSync(CERT_PATH)) {\n return { name: 'CA Certificate', ok: true, message: `Found at ${CERT_PATH}` };\n }\n\n return {\n name: 'CA Certificate',\n ok: false,\n message: 'Not generated yet',\n fix: async () => this.generateCACert(),\n };\n }\n\n private async generateCACert(): Promise<boolean> {\n const mitmdump = this.findBinary('mitmdump');\n if (!mitmdump) {\n this.log(' Cannot generate cert \u2014 mitmproxy not installed.');\n return false;\n }\n\n // Run mitmdump briefly to generate certs\n this.log(' Generating CA certificate...');\n const result = spawnSync(mitmdump, ['--set', 'listen_port=0', '-q'], {\n timeout: 5000,\n stdio: 'ignore',\n });\n\n // mitmdump will timeout (expected) \u2014 certs should be generated\n if (existsSync(CERT_PATH)) {\n this.log(` Certificate generated at ${CERT_PATH}`);\n\n // On macOS, offer to trust the cert\n if (process.platform === 'darwin') {\n this.log(' Adding CA cert to macOS keychain (may require sudo)...');\n const trustResult = spawnSync('sudo', [\n 'security', 'add-trusted-cert', '-d',\n '-r', 'trustRoot',\n '-k', '/Library/Keychains/System.keychain',\n CERT_PATH,\n ], { stdio: 'inherit' });\n if (trustResult.status === 0) {\n this.log(' CA cert trusted system-wide.');\n } else {\n this.log(' Could not auto-trust cert. You may need NODE_EXTRA_CA_CERTS env var.');\n }\n }\n\n return true;\n }\n\n this.log(' Failed to generate cert. Try running: mitmdump --help');\n return false;\n }\n\n private async checkHooks(): Promise<CheckResult> {\n // Hooks may live in settings.local.json (current installs write\n // machine-local state there) or the shared settings.json (legacy\n // installs) \u2014 either file counts.\n let sawSettingsFile = false;\n for (const fileName of ['settings.local.json', 'settings.json']) {\n const settingsPath = join(process.cwd(), '.claude', fileName);\n if (!existsSync(settingsPath)) continue;\n sawSettingsFile = true;\n try {\n const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n const hasHooks = settings.hooks && Object.keys(settings.hooks).length > 0;\n if (hasHooks) {\n return { name: 'Session Hooks', ok: true, message: 'Installed in current project' };\n }\n } catch { /* fall through */ }\n }\n\n if (!sawSettingsFile) {\n return {\n name: 'Session Hooks',\n ok: false,\n message: 'Not installed in current project',\n fix: async () => {\n this.log(' Run `rulemetric hooks install` in your project directory.');\n return false; // User needs to run in the right directory\n },\n };\n }\n\n return {\n name: 'Session Hooks',\n ok: false,\n message: 'settings file exists but hooks not configured',\n fix: async () => {\n this.log(' Run `rulemetric hooks install` to configure hooks.');\n return false;\n },\n };\n }\n\n private checkShellEnv(port: number): CheckResult {\n const proxySet = process.env.HTTPS_PROXY?.includes(String(port));\n const certSet = !!process.env.NODE_EXTRA_CA_CERTS;\n\n if (proxySet && certSet) {\n return { name: 'Shell Environment', ok: true, message: 'HTTPS_PROXY and NODE_EXTRA_CA_CERTS set' };\n }\n\n const missing: string[] = [];\n if (!proxySet) missing.push('HTTPS_PROXY');\n if (!certSet) missing.push('NODE_EXTRA_CA_CERTS');\n\n return {\n name: 'Shell Environment',\n ok: false,\n message: `Missing: ${missing.join(', ')}`,\n fix: async () => this.writeShellEnv(port),\n };\n }\n\n private async writeShellEnv(port: number): Promise<boolean> {\n const shell = this.detectShell();\n const rcFile = this.getShellRcFile(shell);\n\n if (!rcFile) {\n this.log(` Could not detect shell RC file. Add these to your shell profile:`);\n this.log(` export HTTPS_PROXY=http://localhost:${port}`);\n this.log(` export NODE_EXTRA_CA_CERTS=${CERT_PATH}`);\n return false;\n }\n\n const oldMarker = '# RuleMetric proxy';\n const marker = '# RuleMetric proxy (auto-detect)';\n const envFile = join(CONFIG_DIR, 'proxy.env');\n const pidFile = join(CONFIG_DIR, 'proxy.pid');\n\n // The sentinel proves the block is already installed (idempotency). POSIX\n // shells share one function name; PowerShell uses its own.\n const sentinel = shell === 'powershell' ? '_RuleMetricProxyCheck' : '_rulemetric_proxy_check';\n\n // Dynamic proxy env: re-evaluates on every prompt so stopping the proxy\n // immediately unsets HTTPS_PROXY without needing a new shell.\n const block = shell === 'powershell'\n ? this.buildPowerShellBlock(marker, pidFile, port)\n : shell === 'fish'\n ? [\n '',\n marker,\n 'function _rulemetric_proxy_check',\n ` if test -f ${pidFile}; and kill -0 (cat ${pidFile}) 2>/dev/null`,\n ` source ${envFile} 2>/dev/null`,\n ' else',\n ' set -e HTTPS_PROXY 2>/dev/null',\n ' set -e NODE_EXTRA_CA_CERTS 2>/dev/null',\n ' end',\n 'end',\n '',\n ].join('\\n')\n : shell === 'zsh'\n ? [\n '',\n marker,\n '_rulemetric_proxy_check() {',\n ` if [ -f \"${pidFile}\" ] && kill -0 \"$(cat \"${pidFile}\" 2>/dev/null)\" 2>/dev/null; then`,\n ` [ -z \"\\${HTTPS_PROXY:-}\" ] && source \"${envFile}\" 2>/dev/null`,\n ' else',\n ` [ -n \"\\${HTTPS_PROXY:-}\" ] && unset HTTPS_PROXY NODE_EXTRA_CA_CERTS`,\n ' fi',\n '}',\n 'precmd_functions+=(_rulemetric_proxy_check)',\n '',\n ].join('\\n')\n : [\n '',\n marker,\n '_rulemetric_proxy_check() {',\n ` if [ -f \"${pidFile}\" ] && kill -0 \"$(cat \"${pidFile}\" 2>/dev/null)\" 2>/dev/null; then`,\n ` [ -z \"\\${HTTPS_PROXY:-}\" ] && source \"${envFile}\" 2>/dev/null`,\n ' else',\n ` [ -n \"\\${HTTPS_PROXY:-}\" ] && unset HTTPS_PROXY NODE_EXTRA_CA_CERTS`,\n ' fi',\n '}',\n 'PROMPT_COMMAND=\"_rulemetric_proxy_check${PROMPT_COMMAND:+;$PROMPT_COMMAND}\"',\n '',\n ].join('\\n');\n\n // The PowerShell `$PROFILE` directory frequently does not exist yet; create\n // it (and any other missing rc dir, e.g. fish) before appending.\n mkdirSync(dirname(rcFile), { recursive: true });\n\n if (existsSync(rcFile)) {\n let content = readFileSync(rcFile, 'utf-8');\n\n // Remove old static block if present\n if (content.includes(oldMarker) && !content.includes(marker)) {\n content = content.replace(\n /\\n# RuleMetric proxy\\nexport HTTPS_PROXY=[^\\n]*\\nexport NODE_EXTRA_CA_CERTS=[^\\n]*\\n/,\n '\\n',\n );\n writeFileSync(rcFile, content);\n this.log(` Removed old static env vars from ${rcFile}`);\n }\n\n // Remove old auto-detect block (the one without precmd that doesn't unset on stop)\n if (content.includes('# RuleMetric proxy (auto-detect') && !content.includes('_rulemetric_proxy_check')) {\n content = content.replace(\n /\\n# RuleMetric proxy \\(auto-detect[^\\n]*\\)\\nif \\[.*?\\nfi\\n/s,\n '\\n',\n );\n writeFileSync(rcFile, content);\n this.log(` Upgraded old auto-detect block in ${rcFile}`);\n }\n\n if (content.includes(sentinel)) {\n this.log(` Shell env already configured in ${rcFile}`);\n return true;\n }\n }\n\n this.log(` Appending proxy auto-detect hook to ${rcFile}`);\n this.log(` (HTTPS_PROXY is set/unset automatically when proxy starts/stops)`);\n appendFileSync(rcFile, block);\n return true;\n }\n\n private detectShell(): string {\n // On Windows there is no $SHELL and PowerShell is the de-facto shell.\n if (process.platform === 'win32') return 'powershell';\n const shell = process.env.SHELL || '';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('bash')) return 'bash';\n if (shell.includes('fish')) return 'fish';\n return 'zsh'; // default on macOS\n }\n\n private getShellRcFile(shell: string): string | null {\n const home = homedir();\n switch (shell) {\n case 'zsh': return join(home, '.zshrc');\n case 'bash': return join(home, '.bashrc');\n case 'fish': return join(home, '.config', 'fish', 'config.fish');\n case 'powershell': return this.getPowerShellProfilePath();\n default: return null;\n }\n }\n\n /**\n * Resolve the PowerShell profile that loads for every host (console, VS Code\n * integrated terminal, etc.). We ask PowerShell itself for the canonical path\n * \u2014 guessing `~/Documents/...` is wrong when Documents is OneDrive-redirected.\n * Falls back to the PowerShell 7 default only if no PS binary is reachable.\n */\n private getPowerShellProfilePath(): string {\n const psBin = findBinary('pwsh') || findBinary('powershell');\n if (psBin) {\n try {\n const out = execSync(`\"${psBin}\" -NoProfile -Command \"$PROFILE.CurrentUserAllHosts\"`, {\n encoding: 'utf-8',\n }).trim();\n if (out) return out;\n } catch {\n /* fall through to constructed default */\n }\n }\n return join(homedir(), 'Documents', 'PowerShell', 'profile.ps1');\n }\n\n /**\n * Self-contained PowerShell prompt hook. Unlike the POSIX blocks it does NOT\n * source `proxy.env` (that file is `export KEY=val` syntax PowerShell can't\n * read) \u2014 it embeds the values directly. Each prompt it sets HTTPS_PROXY while\n * the proxy PID is alive and removes the vars once it stops, so a dead proxy\n * never leaves a dangling HTTPS_PROXY that would break Claude Code.\n */\n private buildPowerShellBlock(marker: string, pidFile: string, port: number): string {\n const proxyUrl = `http://localhost:${port}`;\n const psPid = pidFile.replace(/'/g, \"''\");\n const psCert = CERT_PATH.replace(/'/g, \"''\");\n return [\n '',\n marker,\n 'function _RuleMetricProxyCheck {',\n ` $pidFile = '${psPid}'`,\n ' $alive = $false',\n ' if (Test-Path $pidFile) {',\n ' $procId = (Get-Content $pidFile -ErrorAction SilentlyContinue | Select-Object -First 1)',\n ' if ($procId -match \\'^\\\\d+$\\' -and (Get-Process -Id ([int]$procId) -ErrorAction SilentlyContinue)) {',\n ' $alive = $true',\n ' }',\n ' }',\n ' if ($alive) {',\n ` $env:HTTPS_PROXY = '${proxyUrl}'`,\n ` $env:HTTP_PROXY = '${proxyUrl}'`,\n ` $env:NODE_EXTRA_CA_CERTS = '${psCert}'`,\n ' } else {',\n ' Remove-Item Env:HTTPS_PROXY, Env:HTTP_PROXY, Env:NODE_EXTRA_CA_CERTS -ErrorAction SilentlyContinue',\n ' }',\n '}',\n '# Wrap the existing prompt once so the check runs every prompt.',\n 'if (-not (Test-Path Function:\\\\_RuleMetricOriginalPrompt)) {',\n ' $existing = Get-Command prompt -ErrorAction SilentlyContinue',\n ' if ($existing) { Set-Item Function:\\\\_RuleMetricOriginalPrompt $existing.ScriptBlock }',\n '}',\n 'function prompt {',\n ' _RuleMetricProxyCheck',\n ' if (Test-Path Function:\\\\_RuleMetricOriginalPrompt) { & _RuleMetricOriginalPrompt } else { \"PS $($PWD.Path)> \" }',\n '}',\n '',\n ].join('\\n');\n }\n\n private findBinary(name: string): string | null {\n // Portable PATH scan \u2014 `which` does not exist on Windows.\n return findBinary(name);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,13 +1,18 @@
1
1
  import {
2
2
  findBinary
3
3
  } from "../../chunk-42GFSAJP.js";
4
+ import {
5
+ MITMPROXY_COMMAND_PATTERN,
6
+ isPidLiveAndMatching
7
+ } from "../../chunk-5EDMGK3W.js";
4
8
  import {
5
9
  BaseCommand
6
- } from "../../chunk-SZ7VDCD6.js";
10
+ } from "../../chunk-2HK7RGZB.js";
7
11
  import "../../chunk-R56PH7YE.js";
8
- import "../../chunk-SLL3OBKN.js";
12
+ import "../../chunk-GQNJO2P2.js";
13
+ import "../../chunk-37LN5O7M.js";
9
14
  import "../../chunk-EKJ2CABV.js";
10
- import "../../chunk-ZRLYHBPN.js";
15
+ import "../../chunk-ZUJBM6HE.js";
11
16
  import {
12
17
  isAuthenticated
13
18
  } from "../../chunk-W2YERO7E.js";
@@ -194,18 +199,15 @@ var ProxyStart = class _ProxyStart extends BaseCommand {
194
199
  this.error("Proxy is running in Docker. Stop it first: rulemetric proxy stop");
195
200
  }
196
201
  const pid = Number.parseInt(content, 10);
197
- if (!Number.isNaN(pid)) {
198
- try {
199
- process.kill(pid, 0);
200
- this.error(`Proxy already running (PID ${pid}). Stop it first: rulemetric proxy stop`);
201
- } catch {
202
- }
202
+ if (!Number.isNaN(pid) && isPidLiveAndMatching(pid, MITMPROXY_COMMAND_PATTERN)) {
203
+ this.error(`Proxy already running (PID ${pid}). Stop it first: rulemetric proxy stop`);
203
204
  }
204
205
  }
205
- const binary = useWeb ? "mitmweb" : "mitmdump";
206
- if (!findBinary(binary)) {
206
+ const binaryName = useWeb ? "mitmweb" : "mitmdump";
207
+ const binary = findBinary(binaryName);
208
+ if (!binary) {
207
209
  this.error(
208
- `${binary} not found. Use Docker mode instead:
210
+ `${binaryName} not found. Use Docker mode instead:
209
211
  rulemetric proxy start --docker
210
212
 
211
213
  Or install mitmproxy locally:
@@ -230,8 +232,10 @@ Or install mitmproxy locally:
230
232
  if (!existsSync(certPath)) {
231
233
  warnings.push("CA cert not found \u2014 HTTPS interception may fail. Run `rulemetric proxy setup`.");
232
234
  }
233
- const settingsPath = join(process.cwd(), ".claude", "settings.json");
234
- if (!existsSync(settingsPath)) {
235
+ const hasClaudeSettings = ["settings.local.json", "settings.json"].some(
236
+ (fileName) => existsSync(join(process.cwd(), ".claude", fileName))
237
+ );
238
+ if (!hasClaudeSettings) {
235
239
  warnings.push("Session hooks not installed \u2014 snapshots won't link to sessions. Run `rulemetric hooks install`.");
236
240
  }
237
241
  if (warnings.length > 0) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/commands/proxy/start.ts"],
4
- "sourcesContent": ["import { Flags } from '@oclif/core';\nimport { execSync, spawn, spawnSync } from 'node:child_process';\nimport { appendFileSync, existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { BaseCommand } from '../../base-command.js';\nimport { isAuthenticated } from '../../lib/auth.js';\nimport { findBinary } from '../../lib/which.js';\n\n// import.meta.dirname is undefined on Node < 20.11 (breaks resolve()); derive\n// portably. See onboarding field report 2026-07-07 F1.\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\n\nconst DEFAULT_PORT = 8788;\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst PID_FILE = join(CONFIG_DIR, 'proxy.pid');\nconst LOG_FILE = join(CONFIG_DIR, 'proxy.log');\nconst DOCKER_IMAGE = 'rulemetric/proxy';\nconst DOCKER_CONTAINER = 'rulemetric-proxy';\n\nfunction findAddonPath(): string {\n const candidates = [\n resolve(MODULE_DIR, '../../../../../packages/proxy/addon/rulemetric_addon.py'),\n resolve(MODULE_DIR, '../../../node_modules/@rulemetric/proxy/addon/rulemetric_addon.py'),\n resolve(MODULE_DIR, '../../../../../node_modules/@rulemetric/proxy/addon/rulemetric_addon.py'),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n throw new Error(\n 'Could not find rulemetric_addon.py. Is @rulemetric/proxy installed?\\n' +\n 'Searched:\\n' + candidates.map(c => ` ${c}`).join('\\n'),\n );\n}\n\nfunction findDockerfilePath(): string {\n const candidates = [\n resolve(MODULE_DIR, '../../../../../packages/proxy'),\n resolve(MODULE_DIR, '../../../node_modules/@rulemetric/proxy'),\n resolve(MODULE_DIR, '../../../../../node_modules/@rulemetric/proxy'),\n ];\n for (const p of candidates) {\n if (existsSync(join(p, 'Dockerfile'))) return p;\n }\n throw new Error('Could not find proxy Dockerfile. Is @rulemetric/proxy installed?');\n}\n\nfunction dockerImageExists(): boolean {\n const result = spawnSync('docker', ['image', 'inspect', DOCKER_IMAGE], { stdio: 'ignore' });\n return result.status === 0;\n}\n\nfunction dockerContainerRunning(): boolean {\n const result = spawnSync('docker', ['container', 'inspect', '-f', '{{.State.Running}}', DOCKER_CONTAINER], {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n return result.status === 0 && result.stdout?.trim() === 'true';\n}\n\nexport default class ProxyStart extends BaseCommand {\n static override description = 'Start context capture proxy';\n\n static override examples = [\n '<%= config.bin %> proxy start',\n '<%= config.bin %> proxy start --docker',\n '<%= config.bin %> proxy start --port 9090',\n '<%= config.bin %> proxy start --web',\n ];\n\n static override flags = {\n port: Flags.integer({ char: 'p', default: DEFAULT_PORT, description: 'Proxy listen port' }),\n docker: Flags.boolean({ char: 'd', default: false, description: 'Run proxy in Docker (no local mitmproxy needed)' }),\n web: Flags.boolean({ default: false, description: 'Launch mitmweb debug UI instead of mitmdump (local mode only)' }),\n 'skip-checks': Flags.boolean({ default: false, description: 'Skip prerequisite checks' }),\n build: Flags.boolean({ default: false, description: 'Force rebuild Docker image' }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(ProxyStart);\n const port = flags.port;\n\n if (flags.docker) {\n await this.startDocker(port, flags.build);\n } else {\n await this.startLocal(port, flags.web, flags['skip-checks']);\n }\n }\n\n private async startDocker(port: number, forceBuild: boolean): Promise<void> {\n // Check Docker is available\n try {\n execSync('docker info', { stdio: 'ignore' });\n } catch {\n this.error('Docker is not running. Start Docker Desktop and try again.');\n }\n\n // Check if already running\n if (dockerContainerRunning()) {\n this.error(`Proxy container already running. Stop it first: rulemetric proxy stop`);\n }\n\n // Find the compose file (monorepo root or project root)\n const composeFile = this.findComposeFile();\n\n // Ensure mount dirs exist\n const certDir = join(homedir(), '.mitmproxy');\n mkdirSync(certDir, { recursive: true });\n const tmpDir = process.env.TMPDIR || '/tmp';\n mkdirSync(join(tmpDir, 'rulemetric'), { recursive: true });\n\n // Load auth from env file if not in environment\n const envOverrides: Record<string, string> = {\n PROXY_PORT: String(port),\n RULEMETRIC_PROJECT_PATH: process.cwd(),\n };\n\n if (!process.env.RULEMETRIC_API_KEY && !process.env.RULEMETRIC_ACCESS_TOKEN) {\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n if (existsSync(envFile)) {\n for (const line of readFileSync(envFile, 'utf-8').split('\\n')) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith('#') && trimmed.includes('=')) {\n const [key, ...rest] = trimmed.split('=');\n envOverrides[key] = rest.join('=');\n }\n }\n }\n }\n\n if (composeFile) {\n // Use docker compose\n const composeEnv = { ...process.env, ...envOverrides };\n const buildFlag = forceBuild ? '--build' : '';\n const args = ['compose', '-f', composeFile, 'up', '-d', 'proxy'];\n if (forceBuild) args.splice(4, 0, '--build');\n\n this.log(forceBuild ? 'Building and starting proxy via Docker Compose...' : 'Starting proxy via Docker Compose...');\n const result = spawnSync('docker', args, {\n env: composeEnv,\n stdio: 'inherit',\n });\n\n if (result.status !== 0) {\n this.error('Docker Compose failed. Try: docker compose -f docker-compose.yml up proxy');\n }\n } else {\n // Fallback: raw docker run\n if (forceBuild || !dockerImageExists()) {\n const proxyDir = findDockerfilePath();\n this.log('Building proxy Docker image...');\n const build = spawnSync('docker', ['build', '-t', DOCKER_IMAGE, proxyDir], { stdio: 'inherit' });\n if (build.status !== 0) {\n this.error('Docker build failed');\n }\n }\n\n spawnSync('docker', ['rm', '-f', DOCKER_CONTAINER], { stdio: 'ignore' });\n\n const envArgs: string[] = [];\n for (const [key, val] of Object.entries(envOverrides)) {\n envArgs.push('-e', `${key}=${val}`);\n }\n // Pass through from current env\n for (const key of ['RULEMETRIC_API_URL', 'RULEMETRIC_API_KEY', 'RULEMETRIC_ACCESS_TOKEN']) {\n if (process.env[key]) envArgs.push('-e', `${key}=${process.env[key]}`);\n }\n\n const dockerArgs = [\n 'run', '-d',\n '--name', DOCKER_CONTAINER,\n '-p', `${port}:8787`,\n '-v', `${certDir}:/root/.mitmproxy`,\n '-v', `${join(tmpDir, 'rulemetric')}:/tmp/rulemetric:ro`,\n ...envArgs,\n DOCKER_IMAGE,\n ];\n\n const result = spawnSync('docker', dockerArgs, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });\n if (result.status !== 0) {\n this.error(`Failed to start container: ${result.stderr}`);\n }\n }\n\n // Write marker so proxy stop knows it's Docker\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(PID_FILE, `docker:${DOCKER_CONTAINER}`);\n\n // Wait for container to be ready\n await new Promise(resolve => setTimeout(resolve, 2000));\n\n const inspectResult = spawnSync('docker', ['container', 'inspect', '-f', '{{.Id}}', DOCKER_CONTAINER], {\n encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'],\n });\n const containerId = inspectResult.stdout?.trim().slice(0, 12) || 'unknown';\n\n this.log(`Proxy running in Docker on localhost:${port} (container: ${containerId})`);\n\n this.log('');\n this.log('View logs: rulemetric proxy logs -f');\n }\n\n private findComposeFile(): string | null {\n const candidates = [\n join(process.cwd(), 'docker-compose.yml'),\n resolve(MODULE_DIR, '../../../../../docker-compose.yml'),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return null;\n }\n\n private async startLocal(port: number, useWeb: boolean, skipChecks: boolean): Promise<void> {\n // Check if already running\n if (existsSync(PID_FILE)) {\n const content = readFileSync(PID_FILE, 'utf-8').trim();\n if (content.startsWith('docker:')) {\n this.error('Proxy is running in Docker. Stop it first: rulemetric proxy stop');\n }\n const pid = Number.parseInt(content, 10);\n if (!Number.isNaN(pid)) {\n try {\n process.kill(pid, 0);\n this.error(`Proxy already running (PID ${pid}). Stop it first: rulemetric proxy stop`);\n } catch { /* stale PID, continue */ }\n }\n }\n\n // Check mitmproxy is installed (portable PATH scan \u2014 Windows has no `which`)\n const binary = useWeb ? 'mitmweb' : 'mitmdump';\n if (!findBinary(binary)) {\n this.error(\n `${binary} not found. Use Docker mode instead:\\n` +\n ' rulemetric proxy start --docker\\n\\n' +\n 'Or install mitmproxy locally:\\n' +\n ' pipx install mitmproxy\\n' +\n ' brew install mitmproxy',\n );\n }\n\n // Prerequisite warnings (non-blocking)\n if (!skipChecks) {\n const warnings: string[] = [];\n\n if (!isAuthenticated() && !process.env.RULEMETRIC_API_KEY) {\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n let hasEnvAuth = false;\n if (existsSync(envFile)) {\n const content = readFileSync(envFile, 'utf-8');\n hasEnvAuth = content.includes('RULEMETRIC_API_KEY') || content.includes('RULEMETRIC_ACCESS_TOKEN');\n }\n if (!hasEnvAuth) {\n warnings.push('Not authenticated \u2014 snapshots cannot be stored. Run `rulemetric auth login`.');\n }\n }\n\n const certPath = join(homedir(), '.mitmproxy', 'mitmproxy-ca-cert.pem');\n if (!existsSync(certPath)) {\n warnings.push('CA cert not found \u2014 HTTPS interception may fail. Run `rulemetric proxy setup`.');\n }\n\n const settingsPath = join(process.cwd(), '.claude', 'settings.json');\n if (!existsSync(settingsPath)) {\n warnings.push('Session hooks not installed \u2014 snapshots won\\'t link to sessions. Run `rulemetric hooks install`.');\n }\n\n if (warnings.length > 0) {\n for (const w of warnings) {\n this.log(` Warning: ${w}`);\n }\n this.log('');\n }\n }\n\n // Find addon\n const addonPath = findAddonPath();\n\n // Build env \u2014 pass through auth credentials for the reporter\n const env: Record<string, string | undefined> = {\n ...process.env,\n RULEMETRIC_PROJECT_PATH: process.cwd(),\n // Bound to this CLI binary's version. The addon writes this to a\n // version file the gateway watches; on drift the gateway restarts\n // mitmproxy so an upgraded CLI doesn't sit next to a stale proxy.\n RULEMETRIC_CLI_VERSION: this.config.version,\n };\n\n // Load auth from env file if not already in environment\n if (!env.RULEMETRIC_API_KEY && !env.RULEMETRIC_ACCESS_TOKEN) {\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n if (existsSync(envFile)) {\n for (const line of readFileSync(envFile, 'utf-8').split('\\n')) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith('#') && trimmed.includes('=')) {\n const [key, ...rest] = trimmed.split('=');\n env[key] = rest.join('=');\n }\n }\n }\n }\n\n // Ensure config dir exists\n mkdirSync(CONFIG_DIR, { recursive: true });\n\n // Open log file for proxy output (fd for spawn stdio)\n appendFileSync(LOG_FILE, `\\n--- Proxy started at ${new Date().toISOString()} (port ${port}) ---\\n`);\n const logFd = openSync(LOG_FILE, 'a');\n\n // Spawn mitmproxy with output redirected to log file\n const args = [\n '--listen-port', String(port),\n '-s', addonPath,\n '--set', 'console_eventlog_verbosity=info',\n ];\n const child = spawn(binary, args, {\n env,\n stdio: ['ignore', logFd, logFd],\n detached: true,\n });\n\n child.unref();\n\n if (!child.pid) {\n this.error('Failed to start proxy process');\n }\n\n // Brief wait to check if process crashes immediately\n await new Promise<void>((resolve) => {\n let exited = false;\n child.once('exit', (code) => {\n exited = true;\n this.error(`Proxy exited immediately with code ${code}. Check logs:\\n ${LOG_FILE}`);\n });\n setTimeout(() => {\n if (!exited) resolve();\n }, 500);\n });\n\n // Write PID file\n writeFileSync(PID_FILE, String(child.pid));\n\n this.log(`Proxy running on localhost:${port} (PID ${child.pid})`);\n this.log(`Log file: ${LOG_FILE}`);\n\n if (useWeb) {\n this.log('');\n this.log('Debug UI: http://localhost:8081');\n }\n\n this.log('');\n this.log('View logs: rulemetric proxy logs -f');\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Flags } from '@oclif/core';\nimport { execSync, spawn, spawnSync } from 'node:child_process';\nimport { appendFileSync, existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { BaseCommand } from '../../base-command.js';\nimport { isAuthenticated } from '../../lib/auth.js';\nimport { isPidLiveAndMatching, MITMPROXY_COMMAND_PATTERN } from '../../lib/pid-identity.js';\nimport { findBinary } from '../../lib/which.js';\n\n// import.meta.dirname is undefined on Node < 20.11 (breaks resolve()); derive\n// portably. See onboarding field report 2026-07-07 F1.\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\n\nconst DEFAULT_PORT = 8788;\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst PID_FILE = join(CONFIG_DIR, 'proxy.pid');\nconst LOG_FILE = join(CONFIG_DIR, 'proxy.log');\nconst DOCKER_IMAGE = 'rulemetric/proxy';\nconst DOCKER_CONTAINER = 'rulemetric-proxy';\n\nfunction findAddonPath(): string {\n const candidates = [\n resolve(MODULE_DIR, '../../../../../packages/proxy/addon/rulemetric_addon.py'),\n resolve(MODULE_DIR, '../../../node_modules/@rulemetric/proxy/addon/rulemetric_addon.py'),\n resolve(MODULE_DIR, '../../../../../node_modules/@rulemetric/proxy/addon/rulemetric_addon.py'),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n throw new Error(\n 'Could not find rulemetric_addon.py. Is @rulemetric/proxy installed?\\n' +\n 'Searched:\\n' + candidates.map(c => ` ${c}`).join('\\n'),\n );\n}\n\nfunction findDockerfilePath(): string {\n const candidates = [\n resolve(MODULE_DIR, '../../../../../packages/proxy'),\n resolve(MODULE_DIR, '../../../node_modules/@rulemetric/proxy'),\n resolve(MODULE_DIR, '../../../../../node_modules/@rulemetric/proxy'),\n ];\n for (const p of candidates) {\n if (existsSync(join(p, 'Dockerfile'))) return p;\n }\n throw new Error('Could not find proxy Dockerfile. Is @rulemetric/proxy installed?');\n}\n\nfunction dockerImageExists(): boolean {\n const result = spawnSync('docker', ['image', 'inspect', DOCKER_IMAGE], { stdio: 'ignore' });\n return result.status === 0;\n}\n\nfunction dockerContainerRunning(): boolean {\n const result = spawnSync('docker', ['container', 'inspect', '-f', '{{.State.Running}}', DOCKER_CONTAINER], {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n return result.status === 0 && result.stdout?.trim() === 'true';\n}\n\nexport default class ProxyStart extends BaseCommand {\n static override description = 'Start context capture proxy';\n\n static override examples = [\n '<%= config.bin %> proxy start',\n '<%= config.bin %> proxy start --docker',\n '<%= config.bin %> proxy start --port 9090',\n '<%= config.bin %> proxy start --web',\n ];\n\n static override flags = {\n port: Flags.integer({ char: 'p', default: DEFAULT_PORT, description: 'Proxy listen port' }),\n docker: Flags.boolean({ char: 'd', default: false, description: 'Run proxy in Docker (no local mitmproxy needed)' }),\n web: Flags.boolean({ default: false, description: 'Launch mitmweb debug UI instead of mitmdump (local mode only)' }),\n 'skip-checks': Flags.boolean({ default: false, description: 'Skip prerequisite checks' }),\n build: Flags.boolean({ default: false, description: 'Force rebuild Docker image' }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(ProxyStart);\n const port = flags.port;\n\n if (flags.docker) {\n await this.startDocker(port, flags.build);\n } else {\n await this.startLocal(port, flags.web, flags['skip-checks']);\n }\n }\n\n private async startDocker(port: number, forceBuild: boolean): Promise<void> {\n // Check Docker is available\n try {\n execSync('docker info', { stdio: 'ignore' });\n } catch {\n this.error('Docker is not running. Start Docker Desktop and try again.');\n }\n\n // Check if already running\n if (dockerContainerRunning()) {\n this.error(`Proxy container already running. Stop it first: rulemetric proxy stop`);\n }\n\n // Find the compose file (monorepo root or project root)\n const composeFile = this.findComposeFile();\n\n // Ensure mount dirs exist\n const certDir = join(homedir(), '.mitmproxy');\n mkdirSync(certDir, { recursive: true });\n const tmpDir = process.env.TMPDIR || '/tmp';\n mkdirSync(join(tmpDir, 'rulemetric'), { recursive: true });\n\n // Load auth from env file if not in environment\n const envOverrides: Record<string, string> = {\n PROXY_PORT: String(port),\n RULEMETRIC_PROJECT_PATH: process.cwd(),\n };\n\n if (!process.env.RULEMETRIC_API_KEY && !process.env.RULEMETRIC_ACCESS_TOKEN) {\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n if (existsSync(envFile)) {\n for (const line of readFileSync(envFile, 'utf-8').split('\\n')) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith('#') && trimmed.includes('=')) {\n const [key, ...rest] = trimmed.split('=');\n envOverrides[key] = rest.join('=');\n }\n }\n }\n }\n\n if (composeFile) {\n // Use docker compose\n const composeEnv = { ...process.env, ...envOverrides };\n const buildFlag = forceBuild ? '--build' : '';\n const args = ['compose', '-f', composeFile, 'up', '-d', 'proxy'];\n if (forceBuild) args.splice(4, 0, '--build');\n\n this.log(forceBuild ? 'Building and starting proxy via Docker Compose...' : 'Starting proxy via Docker Compose...');\n const result = spawnSync('docker', args, {\n env: composeEnv,\n stdio: 'inherit',\n });\n\n if (result.status !== 0) {\n this.error('Docker Compose failed. Try: docker compose -f docker-compose.yml up proxy');\n }\n } else {\n // Fallback: raw docker run\n if (forceBuild || !dockerImageExists()) {\n const proxyDir = findDockerfilePath();\n this.log('Building proxy Docker image...');\n const build = spawnSync('docker', ['build', '-t', DOCKER_IMAGE, proxyDir], { stdio: 'inherit' });\n if (build.status !== 0) {\n this.error('Docker build failed');\n }\n }\n\n spawnSync('docker', ['rm', '-f', DOCKER_CONTAINER], { stdio: 'ignore' });\n\n const envArgs: string[] = [];\n for (const [key, val] of Object.entries(envOverrides)) {\n envArgs.push('-e', `${key}=${val}`);\n }\n // Pass through from current env\n for (const key of ['RULEMETRIC_API_URL', 'RULEMETRIC_API_KEY', 'RULEMETRIC_ACCESS_TOKEN']) {\n if (process.env[key]) envArgs.push('-e', `${key}=${process.env[key]}`);\n }\n\n const dockerArgs = [\n 'run', '-d',\n '--name', DOCKER_CONTAINER,\n '-p', `${port}:8787`,\n '-v', `${certDir}:/root/.mitmproxy`,\n '-v', `${join(tmpDir, 'rulemetric')}:/tmp/rulemetric:ro`,\n ...envArgs,\n DOCKER_IMAGE,\n ];\n\n const result = spawnSync('docker', dockerArgs, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });\n if (result.status !== 0) {\n this.error(`Failed to start container: ${result.stderr}`);\n }\n }\n\n // Write marker so proxy stop knows it's Docker\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(PID_FILE, `docker:${DOCKER_CONTAINER}`);\n\n // Wait for container to be ready\n await new Promise(resolve => setTimeout(resolve, 2000));\n\n const inspectResult = spawnSync('docker', ['container', 'inspect', '-f', '{{.Id}}', DOCKER_CONTAINER], {\n encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'],\n });\n const containerId = inspectResult.stdout?.trim().slice(0, 12) || 'unknown';\n\n this.log(`Proxy running in Docker on localhost:${port} (container: ${containerId})`);\n\n this.log('');\n this.log('View logs: rulemetric proxy logs -f');\n }\n\n private findComposeFile(): string | null {\n const candidates = [\n join(process.cwd(), 'docker-compose.yml'),\n resolve(MODULE_DIR, '../../../../../docker-compose.yml'),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return null;\n }\n\n private async startLocal(port: number, useWeb: boolean, skipChecks: boolean): Promise<void> {\n // Check if already running\n if (existsSync(PID_FILE)) {\n const content = readFileSync(PID_FILE, 'utf-8').trim();\n if (content.startsWith('docker:')) {\n this.error('Proxy is running in Docker. Stop it first: rulemetric proxy stop');\n }\n // PID files survive reboots, and the OS may hand the recorded PID to an\n // unrelated process \u2014 bare `kill -0` would then block every restart with\n // \"already running\". Only a live PID whose command line is actually\n // mitmproxy counts; anything else is a stale file we overwrite below.\n const pid = Number.parseInt(content, 10);\n if (!Number.isNaN(pid) && isPidLiveAndMatching(pid, MITMPROXY_COMMAND_PATTERN)) {\n this.error(`Proxy already running (PID ${pid}). Stop it first: rulemetric proxy stop`);\n }\n }\n\n // Check mitmproxy is installed (portable PATH scan \u2014 Windows has no `which`)\n // and spawn the RESOLVED path, never the bare name: findBinary probes\n // well-known install dirs beyond $PATH, so under a GUI/minimal-PATH launch\n // the check can succeed while spawn('mitmdump') would ENOENT \u2014 the exact\n // detection-vs-spawn split that made the 0.6.6 mitmproxy fix a false fix.\n const binaryName = useWeb ? 'mitmweb' : 'mitmdump';\n const binary = findBinary(binaryName);\n if (!binary) {\n this.error(\n `${binaryName} not found. Use Docker mode instead:\\n` +\n ' rulemetric proxy start --docker\\n\\n' +\n 'Or install mitmproxy locally:\\n' +\n ' pipx install mitmproxy\\n' +\n ' brew install mitmproxy',\n );\n }\n\n // Prerequisite warnings (non-blocking)\n if (!skipChecks) {\n const warnings: string[] = [];\n\n if (!isAuthenticated() && !process.env.RULEMETRIC_API_KEY) {\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n let hasEnvAuth = false;\n if (existsSync(envFile)) {\n const content = readFileSync(envFile, 'utf-8');\n hasEnvAuth = content.includes('RULEMETRIC_API_KEY') || content.includes('RULEMETRIC_ACCESS_TOKEN');\n }\n if (!hasEnvAuth) {\n warnings.push('Not authenticated \u2014 snapshots cannot be stored. Run `rulemetric auth login`.');\n }\n }\n\n const certPath = join(homedir(), '.mitmproxy', 'mitmproxy-ca-cert.pem');\n if (!existsSync(certPath)) {\n warnings.push('CA cert not found \u2014 HTTPS interception may fail. Run `rulemetric proxy setup`.');\n }\n\n // Hooks may live in settings.local.json (current installs write\n // machine-local state there) or the shared settings.json (legacy\n // installs) \u2014 either file counts as installed.\n const hasClaudeSettings = ['settings.local.json', 'settings.json'].some((fileName) =>\n existsSync(join(process.cwd(), '.claude', fileName)),\n );\n if (!hasClaudeSettings) {\n warnings.push('Session hooks not installed \u2014 snapshots won\\'t link to sessions. Run `rulemetric hooks install`.');\n }\n\n if (warnings.length > 0) {\n for (const w of warnings) {\n this.log(` Warning: ${w}`);\n }\n this.log('');\n }\n }\n\n // Find addon\n const addonPath = findAddonPath();\n\n // Build env \u2014 pass through auth credentials for the reporter\n const env: Record<string, string | undefined> = {\n ...process.env,\n RULEMETRIC_PROJECT_PATH: process.cwd(),\n // Bound to this CLI binary's version. The addon writes this to a\n // version file the gateway watches; on drift the gateway restarts\n // mitmproxy so an upgraded CLI doesn't sit next to a stale proxy.\n RULEMETRIC_CLI_VERSION: this.config.version,\n };\n\n // Load auth from env file if not already in environment\n if (!env.RULEMETRIC_API_KEY && !env.RULEMETRIC_ACCESS_TOKEN) {\n const envFile = join(homedir(), '.config', 'rulemetric', 'env');\n if (existsSync(envFile)) {\n for (const line of readFileSync(envFile, 'utf-8').split('\\n')) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith('#') && trimmed.includes('=')) {\n const [key, ...rest] = trimmed.split('=');\n env[key] = rest.join('=');\n }\n }\n }\n }\n\n // Ensure config dir exists\n mkdirSync(CONFIG_DIR, { recursive: true });\n\n // Open log file for proxy output (fd for spawn stdio)\n appendFileSync(LOG_FILE, `\\n--- Proxy started at ${new Date().toISOString()} (port ${port}) ---\\n`);\n const logFd = openSync(LOG_FILE, 'a');\n\n // Spawn mitmproxy with output redirected to log file\n const args = [\n '--listen-port', String(port),\n '-s', addonPath,\n '--set', 'console_eventlog_verbosity=info',\n ];\n const child = spawn(binary, args, {\n env,\n stdio: ['ignore', logFd, logFd],\n detached: true,\n });\n\n child.unref();\n\n if (!child.pid) {\n this.error('Failed to start proxy process');\n }\n\n // Brief wait to check if process crashes immediately\n await new Promise<void>((resolve) => {\n let exited = false;\n child.once('exit', (code) => {\n exited = true;\n this.error(`Proxy exited immediately with code ${code}. Check logs:\\n ${LOG_FILE}`);\n });\n setTimeout(() => {\n if (!exited) resolve();\n }, 500);\n });\n\n // Write PID file\n writeFileSync(PID_FILE, String(child.pid));\n\n this.log(`Proxy running on localhost:${port} (PID ${child.pid})`);\n this.log(`Log file: ${LOG_FILE}`);\n\n if (useWeb) {\n this.log('');\n this.log('Debug UI: http://localhost:8081');\n }\n\n this.log('');\n this.log('View logs: rulemetric proxy logs -f');\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["resolve"]
7
7
  }
@@ -3,14 +3,21 @@ import {
3
3
  MITMPROXY_PORT,
4
4
  getGatewayPid,
5
5
  isGatewayRunning
6
- } from "../../chunk-DAJNO4OI.js";
6
+ } from "../../chunk-4LYCDS2N.js";
7
+ import "../../chunk-7LVVKQMZ.js";
8
+ import {
9
+ MITMPROXY_COMMAND_PATTERN,
10
+ isPidLiveAndMatching,
11
+ pidAlive
12
+ } from "../../chunk-5EDMGK3W.js";
7
13
  import {
8
14
  BaseCommand
9
- } from "../../chunk-SZ7VDCD6.js";
15
+ } from "../../chunk-2HK7RGZB.js";
10
16
  import "../../chunk-R56PH7YE.js";
11
- import "../../chunk-SLL3OBKN.js";
17
+ import "../../chunk-GQNJO2P2.js";
18
+ import "../../chunk-37LN5O7M.js";
12
19
  import "../../chunk-EKJ2CABV.js";
13
- import "../../chunk-ZRLYHBPN.js";
20
+ import "../../chunk-ZUJBM6HE.js";
14
21
  import "../../chunk-W2YERO7E.js";
15
22
  import "../../chunk-NSBPE2FW.js";
16
23
 
@@ -56,16 +63,12 @@ var ProxyStatus = class _ProxyStatus extends BaseCommand {
56
63
  this.log("Mitmproxy: not running (invalid PID file)");
57
64
  return;
58
65
  }
59
- try {
60
- process.kill(pid, 0);
66
+ if (isPidLiveAndMatching(pid, MITMPROXY_COMMAND_PATTERN)) {
61
67
  this.log(`Mitmproxy: running (PID ${pid}) on :${MITMPROXY_PORT} \u2014 capturing context`);
62
- } catch (err) {
63
- const code = err.code;
64
- if (code === "EPERM") {
65
- this.log(`Mitmproxy: running (PID ${pid}, owned by different user) on :${MITMPROXY_PORT}`);
66
- } else {
67
- this.log("Mitmproxy: not running (stale PID file)");
68
- }
68
+ } else if (pidAlive(pid)) {
69
+ this.log(`Mitmproxy: not running (PID ${pid} was reused by another process \u2014 stale PID file)`);
70
+ } else {
71
+ this.log("Mitmproxy: not running (stale PID file)");
69
72
  }
70
73
  }
71
74
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/commands/proxy/status.ts"],
4
- "sourcesContent": ["import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { BaseCommand } from '../../base-command.js';\nimport { isGatewayRunning, getGatewayPid, GATEWAY_PORT, MITMPROXY_PORT } from '../../lib/gateway-lifecycle.js';\n\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst PID_FILE = join(CONFIG_DIR, 'proxy.pid');\n\nexport default class ProxyStatus extends BaseCommand {\n static override description = 'Check gateway and context capture proxy status';\n\n static override examples = ['<%= config.bin %> proxy status'];\n\n async run(): Promise<void> {\n await this.parse(ProxyStatus);\n\n // Gateway status\n if (isGatewayRunning()) {\n const pid = getGatewayPid();\n this.log(`Gateway: running (PID ${pid}) on :${GATEWAY_PORT}`);\n } else {\n this.log(`Gateway: not running`);\n }\n\n // Mitmproxy status\n if (!existsSync(PID_FILE)) {\n this.log(`Mitmproxy: not running \u2014 routing direct (no capture)`);\n return;\n }\n\n const content = readFileSync(PID_FILE, 'utf-8').trim();\n\n // Docker mode\n if (content.startsWith('docker:')) {\n const containerName = content.slice('docker:'.length);\n const result = spawnSync('docker', ['container', 'inspect', '-f', '{{.State.Status}}', containerName], {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n const status = result.stdout?.trim();\n if (result.status === 0 && status === 'running') {\n this.log(`Mitmproxy: running in Docker (container: ${containerName}) on :${MITMPROXY_PORT} \u2014 capturing context`);\n } else {\n this.log(`Mitmproxy: container ${status || 'not running'} (stale)`);\n }\n return;\n }\n\n // Local mode\n const pid = Number.parseInt(content, 10);\n\n if (Number.isNaN(pid)) {\n this.log('Mitmproxy: not running (invalid PID file)');\n return;\n }\n\n try {\n process.kill(pid, 0);\n this.log(`Mitmproxy: running (PID ${pid}) on :${MITMPROXY_PORT} \u2014 capturing context`);\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'EPERM') {\n this.log(`Mitmproxy: running (PID ${pid}, owned by different user) on :${MITMPROXY_PORT}`);\n } else {\n this.log('Mitmproxy: not running (stale PID file)');\n }\n }\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,YAAY;AAIrB,IAAM,aAAa,KAAK,QAAQ,GAAG,WAAW,YAAY;AAC1D,IAAM,WAAW,KAAK,YAAY,WAAW;AAE7C,IAAqB,cAArB,MAAqB,qBAAoB,YAAY;AAAA,EACnD,OAAgB,cAAc;AAAA,EAE9B,OAAgB,WAAW,CAAC,gCAAgC;AAAA,EAE5D,MAAM,MAAqB;AACzB,UAAM,KAAK,MAAM,YAAW;AAG5B,QAAI,iBAAiB,GAAG;AACtB,YAAMA,OAAM,cAAc;AAC1B,WAAK,IAAI,2BAA2BA,IAAG,SAAS,YAAY,EAAE;AAAA,IAChE,OAAO;AACL,WAAK,IAAI,wBAAwB;AAAA,IACnC;AAGA,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAK,IAAI,2DAAsD;AAC/D;AAAA,IACF;AAEA,UAAM,UAAU,aAAa,UAAU,OAAO,EAAE,KAAK;AAGrD,QAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,YAAM,gBAAgB,QAAQ,MAAM,UAAU,MAAM;AACpD,YAAM,SAAS,UAAU,UAAU,CAAC,aAAa,WAAW,MAAM,qBAAqB,aAAa,GAAG;AAAA,QACrG,UAAU;AAAA,QACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,MACpC,CAAC;AACD,YAAM,SAAS,OAAO,QAAQ,KAAK;AACnC,UAAI,OAAO,WAAW,KAAK,WAAW,WAAW;AAC/C,aAAK,IAAI,4CAA4C,aAAa,SAAS,cAAc,2BAAsB;AAAA,MACjH,OAAO;AACL,aAAK,IAAI,wBAAwB,UAAU,aAAa,UAAU;AAAA,MACpE;AACA;AAAA,IACF;AAGA,UAAM,MAAM,OAAO,SAAS,SAAS,EAAE;AAEvC,QAAI,OAAO,MAAM,GAAG,GAAG;AACrB,WAAK,IAAI,2CAA2C;AACpD;AAAA,IACF;AAEA,QAAI;AACF,cAAQ,KAAK,KAAK,CAAC;AACnB,WAAK,IAAI,2BAA2B,GAAG,SAAS,cAAc,2BAAsB;AAAA,IACtF,SAAS,KAAc;AACrB,YAAM,OAAQ,IAA8B;AAC5C,UAAI,SAAS,SAAS;AACpB,aAAK,IAAI,2BAA2B,GAAG,kCAAkC,cAAc,EAAE;AAAA,MAC3F,OAAO;AACL,aAAK,IAAI,yCAAyC;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { BaseCommand } from '../../base-command.js';\nimport { isGatewayRunning, getGatewayPid, GATEWAY_PORT, MITMPROXY_PORT } from '../../lib/gateway-lifecycle.js';\nimport { isPidLiveAndMatching, pidAlive, MITMPROXY_COMMAND_PATTERN } from '../../lib/pid-identity.js';\n\nconst CONFIG_DIR = join(homedir(), '.config', 'rulemetric');\nconst PID_FILE = join(CONFIG_DIR, 'proxy.pid');\n\nexport default class ProxyStatus extends BaseCommand {\n static override description = 'Check gateway and context capture proxy status';\n\n static override examples = ['<%= config.bin %> proxy status'];\n\n async run(): Promise<void> {\n await this.parse(ProxyStatus);\n\n // Gateway status\n if (isGatewayRunning()) {\n const pid = getGatewayPid();\n this.log(`Gateway: running (PID ${pid}) on :${GATEWAY_PORT}`);\n } else {\n this.log(`Gateway: not running`);\n }\n\n // Mitmproxy status\n if (!existsSync(PID_FILE)) {\n this.log(`Mitmproxy: not running \u2014 routing direct (no capture)`);\n return;\n }\n\n const content = readFileSync(PID_FILE, 'utf-8').trim();\n\n // Docker mode\n if (content.startsWith('docker:')) {\n const containerName = content.slice('docker:'.length);\n const result = spawnSync('docker', ['container', 'inspect', '-f', '{{.State.Status}}', containerName], {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n const status = result.stdout?.trim();\n if (result.status === 0 && status === 'running') {\n this.log(`Mitmproxy: running in Docker (container: ${containerName}) on :${MITMPROXY_PORT} \u2014 capturing context`);\n } else {\n this.log(`Mitmproxy: container ${status || 'not running'} (stale)`);\n }\n return;\n }\n\n // Local mode\n const pid = Number.parseInt(content, 10);\n\n if (Number.isNaN(pid)) {\n this.log('Mitmproxy: not running (invalid PID file)');\n return;\n }\n\n // Identity-checked: a reused PID (alive but not mitmproxy) must read as\n // stale, or self-heal/restarts stay blocked on a phantom \"running\" proxy.\n if (isPidLiveAndMatching(pid, MITMPROXY_COMMAND_PATTERN)) {\n this.log(`Mitmproxy: running (PID ${pid}) on :${MITMPROXY_PORT} \u2014 capturing context`);\n } else if (pidAlive(pid)) {\n this.log(`Mitmproxy: not running (PID ${pid} was reused by another process \u2014 stale PID file)`);\n } else {\n this.log('Mitmproxy: not running (stale PID file)');\n }\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,YAAY;AAKrB,IAAM,aAAa,KAAK,QAAQ,GAAG,WAAW,YAAY;AAC1D,IAAM,WAAW,KAAK,YAAY,WAAW;AAE7C,IAAqB,cAArB,MAAqB,qBAAoB,YAAY;AAAA,EACnD,OAAgB,cAAc;AAAA,EAE9B,OAAgB,WAAW,CAAC,gCAAgC;AAAA,EAE5D,MAAM,MAAqB;AACzB,UAAM,KAAK,MAAM,YAAW;AAG5B,QAAI,iBAAiB,GAAG;AACtB,YAAMA,OAAM,cAAc;AAC1B,WAAK,IAAI,2BAA2BA,IAAG,SAAS,YAAY,EAAE;AAAA,IAChE,OAAO;AACL,WAAK,IAAI,wBAAwB;AAAA,IACnC;AAGA,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAK,IAAI,2DAAsD;AAC/D;AAAA,IACF;AAEA,UAAM,UAAU,aAAa,UAAU,OAAO,EAAE,KAAK;AAGrD,QAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,YAAM,gBAAgB,QAAQ,MAAM,UAAU,MAAM;AACpD,YAAM,SAAS,UAAU,UAAU,CAAC,aAAa,WAAW,MAAM,qBAAqB,aAAa,GAAG;AAAA,QACrG,UAAU;AAAA,QACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,MACpC,CAAC;AACD,YAAM,SAAS,OAAO,QAAQ,KAAK;AACnC,UAAI,OAAO,WAAW,KAAK,WAAW,WAAW;AAC/C,aAAK,IAAI,4CAA4C,aAAa,SAAS,cAAc,2BAAsB;AAAA,MACjH,OAAO;AACL,aAAK,IAAI,wBAAwB,UAAU,aAAa,UAAU;AAAA,MACpE;AACA;AAAA,IACF;AAGA,UAAM,MAAM,OAAO,SAAS,SAAS,EAAE;AAEvC,QAAI,OAAO,MAAM,GAAG,GAAG;AACrB,WAAK,IAAI,2CAA2C;AACpD;AAAA,IACF;AAIA,QAAI,qBAAqB,KAAK,yBAAyB,GAAG;AACxD,WAAK,IAAI,2BAA2B,GAAG,SAAS,cAAc,2BAAsB;AAAA,IACtF,WAAW,SAAS,GAAG,GAAG;AACxB,WAAK,IAAI,+BAA+B,GAAG,uDAAkD;AAAA,IAC/F,OAAO;AACL,WAAK,IAAI,yCAAyC;AAAA,IACpD;AAAA,EACF;AACF;",
6
6
  "names": ["pid"]
7
7
  }
@@ -1,10 +1,15 @@
1
+ import {
2
+ MITMPROXY_COMMAND_PATTERN,
3
+ isPidLiveAndMatching
4
+ } from "../../chunk-5EDMGK3W.js";
1
5
  import {
2
6
  BaseCommand
3
- } from "../../chunk-SZ7VDCD6.js";
7
+ } from "../../chunk-2HK7RGZB.js";
4
8
  import "../../chunk-R56PH7YE.js";
5
- import "../../chunk-SLL3OBKN.js";
9
+ import "../../chunk-GQNJO2P2.js";
10
+ import "../../chunk-37LN5O7M.js";
6
11
  import "../../chunk-EKJ2CABV.js";
7
- import "../../chunk-ZRLYHBPN.js";
12
+ import "../../chunk-ZUJBM6HE.js";
8
13
  import "../../chunk-W2YERO7E.js";
9
14
  import "../../chunk-NSBPE2FW.js";
10
15
 
@@ -50,16 +55,20 @@ var ProxyStop = class _ProxyStop extends BaseCommand {
50
55
  this.log("Invalid PID file removed.");
51
56
  return;
52
57
  }
53
- try {
54
- process.kill(pid, "SIGTERM");
55
- this.log(`Proxy stopped (PID ${pid}).`);
56
- } catch (err) {
57
- const code = err.code;
58
- if (code === "ESRCH") {
59
- this.log("Proxy process not running (stale PID file removed).");
60
- } else {
61
- this.error(`Failed to stop proxy: ${err.message}`);
58
+ if (isPidLiveAndMatching(pid, MITMPROXY_COMMAND_PATTERN)) {
59
+ try {
60
+ process.kill(pid, "SIGTERM");
61
+ this.log(`Proxy stopped (PID ${pid}).`);
62
+ } catch (err) {
63
+ const code = err.code;
64
+ if (code === "ESRCH") {
65
+ this.log("Proxy process not running (stale PID file removed).");
66
+ } else {
67
+ this.error(`Failed to stop proxy: ${err.message}`);
68
+ }
62
69
  }
70
+ } else {
71
+ this.log("Proxy process not running (stale PID file removed).");
63
72
  }
64
73
  try {
65
74
  unlinkSync(PID_FILE);