@rulemetric/cli 0.1.1 → 0.2.1

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 (259) hide show
  1. package/README.md +66 -0
  2. package/dist/base-command.d.ts.map +1 -1
  3. package/dist/base-command.js +15 -0
  4. package/dist/base-command.js.map +1 -1
  5. package/dist/commands/auth/login.d.ts.map +1 -1
  6. package/dist/commands/auth/login.js +7 -0
  7. package/dist/commands/auth/login.js.map +1 -1
  8. package/dist/commands/crons/list.d.ts +7 -0
  9. package/dist/commands/crons/list.d.ts.map +1 -0
  10. package/dist/commands/crons/list.js +24 -0
  11. package/dist/commands/crons/list.js.map +1 -0
  12. package/dist/commands/crons/run.d.ts +13 -0
  13. package/dist/commands/crons/run.d.ts.map +1 -0
  14. package/dist/commands/crons/run.js +48 -0
  15. package/dist/commands/crons/run.js.map +1 -0
  16. package/dist/commands/evals/listen.d.ts +28 -2
  17. package/dist/commands/evals/listen.d.ts.map +1 -1
  18. package/dist/commands/evals/listen.js +159 -25
  19. package/dist/commands/evals/listen.js.map +1 -1
  20. package/dist/commands/evals/listen.test.d.ts +2 -0
  21. package/dist/commands/evals/listen.test.d.ts.map +1 -0
  22. package/dist/commands/evals/listen.test.js +48 -0
  23. package/dist/commands/evals/listen.test.js.map +1 -0
  24. package/dist/commands/gateway/ensure.js +1 -1
  25. package/dist/commands/gateway/ensure.js.map +1 -1
  26. package/dist/commands/hooks/install.d.ts.map +1 -1
  27. package/dist/commands/hooks/install.js +40 -3
  28. package/dist/commands/hooks/install.js.map +1 -1
  29. package/dist/commands/hooks/run.js +1 -1
  30. package/dist/commands/hooks/run.js.map +1 -1
  31. package/dist/commands/hooks/uninstall.d.ts.map +1 -1
  32. package/dist/commands/hooks/uninstall.js +9 -1
  33. package/dist/commands/hooks/uninstall.js.map +1 -1
  34. package/dist/commands/org/current.d.ts +7 -0
  35. package/dist/commands/org/current.d.ts.map +1 -0
  36. package/dist/commands/org/current.js +70 -0
  37. package/dist/commands/org/current.js.map +1 -0
  38. package/dist/commands/org/list.d.ts +7 -0
  39. package/dist/commands/org/list.d.ts.map +1 -0
  40. package/dist/commands/org/list.js +37 -0
  41. package/dist/commands/org/list.js.map +1 -0
  42. package/dist/commands/org/switch.d.ts +13 -0
  43. package/dist/commands/org/switch.d.ts.map +1 -0
  44. package/dist/commands/org/switch.js +52 -0
  45. package/dist/commands/org/switch.js.map +1 -0
  46. package/dist/commands/proxy/restart.d.ts +11 -0
  47. package/dist/commands/proxy/restart.d.ts.map +1 -0
  48. package/dist/commands/proxy/restart.js +36 -0
  49. package/dist/commands/proxy/restart.js.map +1 -0
  50. package/dist/commands/proxy/start.d.ts.map +1 -1
  51. package/dist/commands/proxy/start.js +4 -0
  52. package/dist/commands/proxy/start.js.map +1 -1
  53. package/dist/commands/service/install.d.ts +16 -0
  54. package/dist/commands/service/install.d.ts.map +1 -1
  55. package/dist/commands/service/install.js +145 -6
  56. package/dist/commands/service/install.js.map +1 -1
  57. package/dist/commands/service/uninstall.d.ts.map +1 -1
  58. package/dist/commands/service/uninstall.js +28 -0
  59. package/dist/commands/service/uninstall.js.map +1 -1
  60. package/dist/commands/sessions/start.d.ts.map +1 -1
  61. package/dist/commands/sessions/start.js +5 -0
  62. package/dist/commands/sessions/start.js.map +1 -1
  63. package/dist/commands/signals/report.d.ts +10 -0
  64. package/dist/commands/signals/report.d.ts.map +1 -0
  65. package/dist/commands/signals/report.js +35 -0
  66. package/dist/commands/signals/report.js.map +1 -0
  67. package/dist/commands/signals/report.test.d.ts +2 -0
  68. package/dist/commands/signals/report.test.d.ts.map +1 -0
  69. package/dist/commands/signals/report.test.js +65 -0
  70. package/dist/commands/signals/report.test.js.map +1 -0
  71. package/dist/commands/skills/export-approved.d.ts +10 -0
  72. package/dist/commands/skills/export-approved.d.ts.map +1 -0
  73. package/dist/commands/skills/export-approved.js +31 -0
  74. package/dist/commands/skills/export-approved.js.map +1 -0
  75. package/dist/commands/skills/publish.d.ts +17 -0
  76. package/dist/commands/skills/publish.d.ts.map +1 -0
  77. package/dist/commands/skills/publish.js +80 -0
  78. package/dist/commands/skills/publish.js.map +1 -0
  79. package/dist/commands/skills/update.d.ts +3 -0
  80. package/dist/commands/skills/update.d.ts.map +1 -1
  81. package/dist/commands/skills/update.js +17 -6
  82. package/dist/commands/skills/update.js.map +1 -1
  83. package/dist/commands/suggestions/accept.d.ts +16 -0
  84. package/dist/commands/suggestions/accept.d.ts.map +1 -0
  85. package/dist/commands/suggestions/accept.js +61 -0
  86. package/dist/commands/suggestions/accept.js.map +1 -0
  87. package/dist/commands/suggestions/accept.test.d.ts +2 -0
  88. package/dist/commands/suggestions/accept.test.d.ts.map +1 -0
  89. package/dist/commands/suggestions/accept.test.js +52 -0
  90. package/dist/commands/suggestions/accept.test.js.map +1 -0
  91. package/dist/commands/suggestions/dismiss.d.ts +10 -0
  92. package/dist/commands/suggestions/dismiss.d.ts.map +1 -0
  93. package/dist/commands/suggestions/dismiss.js +26 -0
  94. package/dist/commands/suggestions/dismiss.js.map +1 -0
  95. package/dist/commands/suggestions/list.d.ts +10 -0
  96. package/dist/commands/suggestions/list.d.ts.map +1 -0
  97. package/dist/commands/suggestions/list.js +40 -0
  98. package/dist/commands/suggestions/list.js.map +1 -0
  99. package/dist/commands/suggestions/refresh.d.ts +7 -0
  100. package/dist/commands/suggestions/refresh.d.ts.map +1 -0
  101. package/dist/commands/suggestions/refresh.js +11 -0
  102. package/dist/commands/suggestions/refresh.js.map +1 -0
  103. package/dist/dashboard/Dashboard.d.ts.map +1 -1
  104. package/dist/dashboard/Dashboard.js +7 -1
  105. package/dist/dashboard/Dashboard.js.map +1 -1
  106. package/dist/lib/active-org-refresh.d.ts +22 -0
  107. package/dist/lib/active-org-refresh.d.ts.map +1 -0
  108. package/dist/lib/active-org-refresh.js +108 -0
  109. package/dist/lib/active-org-refresh.js.map +1 -0
  110. package/dist/lib/active-org-refresh.test.d.ts +2 -0
  111. package/dist/lib/active-org-refresh.test.d.ts.map +1 -0
  112. package/dist/lib/active-org-refresh.test.js +190 -0
  113. package/dist/lib/active-org-refresh.test.js.map +1 -0
  114. package/dist/lib/active-org.d.ts +43 -0
  115. package/dist/lib/active-org.d.ts.map +1 -0
  116. package/dist/lib/active-org.js +96 -0
  117. package/dist/lib/active-org.js.map +1 -0
  118. package/dist/lib/active-org.test.d.ts +2 -0
  119. package/dist/lib/active-org.test.d.ts.map +1 -0
  120. package/dist/lib/active-org.test.js +147 -0
  121. package/dist/lib/active-org.test.js.map +1 -0
  122. package/dist/lib/cron-registry.d.ts +47 -0
  123. package/dist/lib/cron-registry.d.ts.map +1 -0
  124. package/dist/lib/cron-registry.js +102 -0
  125. package/dist/lib/cron-registry.js.map +1 -0
  126. package/dist/lib/cron-registry.test.d.ts +2 -0
  127. package/dist/lib/cron-registry.test.d.ts.map +1 -0
  128. package/dist/lib/cron-registry.test.js +136 -0
  129. package/dist/lib/cron-registry.test.js.map +1 -0
  130. package/dist/lib/cron-runner.d.ts +16 -0
  131. package/dist/lib/cron-runner.d.ts.map +1 -0
  132. package/dist/lib/cron-runner.js +68 -0
  133. package/dist/lib/cron-runner.js.map +1 -0
  134. package/dist/lib/detect-languages.d.ts +7 -0
  135. package/dist/lib/detect-languages.d.ts.map +1 -0
  136. package/dist/lib/detect-languages.js +113 -0
  137. package/dist/lib/detect-languages.js.map +1 -0
  138. package/dist/lib/detect-languages.test.d.ts +2 -0
  139. package/dist/lib/detect-languages.test.d.ts.map +1 -0
  140. package/dist/lib/detect-languages.test.js +29 -0
  141. package/dist/lib/detect-languages.test.js.map +1 -0
  142. package/dist/lib/eval-executor.d.ts.map +1 -1
  143. package/dist/lib/eval-executor.js +5 -2
  144. package/dist/lib/eval-executor.js.map +1 -1
  145. package/dist/lib/gateway-entry.js +4 -1
  146. package/dist/lib/gateway-entry.js.map +1 -1
  147. package/dist/lib/gateway-lifecycle.d.ts +1 -1
  148. package/dist/lib/gateway-lifecycle.d.ts.map +1 -1
  149. package/dist/lib/gateway-lifecycle.js +13 -2
  150. package/dist/lib/gateway-lifecycle.js.map +1 -1
  151. package/dist/lib/gateway.d.ts +4 -5
  152. package/dist/lib/gateway.d.ts.map +1 -1
  153. package/dist/lib/gateway.js +68 -2
  154. package/dist/lib/gateway.js.map +1 -1
  155. package/dist/lib/graphile-worker-runner.d.ts +124 -0
  156. package/dist/lib/graphile-worker-runner.d.ts.map +1 -0
  157. package/dist/lib/graphile-worker-runner.js +530 -0
  158. package/dist/lib/graphile-worker-runner.js.map +1 -0
  159. package/dist/lib/graphile-worker-runner.test.d.ts +2 -0
  160. package/dist/lib/graphile-worker-runner.test.d.ts.map +1 -0
  161. package/dist/lib/graphile-worker-runner.test.js +153 -0
  162. package/dist/lib/graphile-worker-runner.test.js.map +1 -0
  163. package/dist/lib/handlers/cron-close-stale-sessions.d.ts +3 -0
  164. package/dist/lib/handlers/cron-close-stale-sessions.d.ts.map +1 -0
  165. package/dist/lib/handlers/cron-close-stale-sessions.js +8 -0
  166. package/dist/lib/handlers/cron-close-stale-sessions.js.map +1 -0
  167. package/dist/lib/handlers/cron-data-integrity-audit.d.ts +3 -0
  168. package/dist/lib/handlers/cron-data-integrity-audit.d.ts.map +1 -0
  169. package/dist/lib/handlers/cron-data-integrity-audit.js +16 -0
  170. package/dist/lib/handlers/cron-data-integrity-audit.js.map +1 -0
  171. package/dist/lib/handlers/cron-refresh-skills.d.ts +3 -0
  172. package/dist/lib/handlers/cron-refresh-skills.d.ts.map +1 -0
  173. package/dist/lib/handlers/cron-refresh-skills.js +91 -0
  174. package/dist/lib/handlers/cron-refresh-skills.js.map +1 -0
  175. package/dist/lib/handlers/cron-refresh-skills.test.d.ts +2 -0
  176. package/dist/lib/handlers/cron-refresh-skills.test.d.ts.map +1 -0
  177. package/dist/lib/handlers/cron-refresh-skills.test.js +114 -0
  178. package/dist/lib/handlers/cron-refresh-skills.test.js.map +1 -0
  179. package/dist/lib/handlers/cron-regenerate-insights.d.ts +3 -0
  180. package/dist/lib/handlers/cron-regenerate-insights.d.ts.map +1 -0
  181. package/dist/lib/handlers/cron-regenerate-insights.js +6 -0
  182. package/dist/lib/handlers/cron-regenerate-insights.js.map +1 -0
  183. package/dist/lib/handlers/cron-suggest-instructions.d.ts +3 -0
  184. package/dist/lib/handlers/cron-suggest-instructions.d.ts.map +1 -0
  185. package/dist/lib/handlers/cron-suggest-instructions.js +159 -0
  186. package/dist/lib/handlers/cron-suggest-instructions.js.map +1 -0
  187. package/dist/lib/handlers/cron-suggest-instructions.test.d.ts +2 -0
  188. package/dist/lib/handlers/cron-suggest-instructions.test.d.ts.map +1 -0
  189. package/dist/lib/handlers/cron-suggest-instructions.test.js +80 -0
  190. package/dist/lib/handlers/cron-suggest-instructions.test.js.map +1 -0
  191. package/dist/lib/handlers/process-conversation.d.ts +35 -0
  192. package/dist/lib/handlers/process-conversation.d.ts.map +1 -0
  193. package/dist/lib/handlers/process-conversation.js +35 -0
  194. package/dist/lib/handlers/process-conversation.js.map +1 -0
  195. package/dist/lib/handlers/process-eval.d.ts +32 -0
  196. package/dist/lib/handlers/process-eval.d.ts.map +1 -0
  197. package/dist/lib/handlers/process-eval.js +207 -0
  198. package/dist/lib/handlers/process-eval.js.map +1 -0
  199. package/dist/lib/handlers/process-insights.d.ts +39 -0
  200. package/dist/lib/handlers/process-insights.d.ts.map +1 -0
  201. package/dist/lib/handlers/process-insights.js +300 -0
  202. package/dist/lib/handlers/process-insights.js.map +1 -0
  203. package/dist/lib/handlers/process-launch.d.ts +29 -0
  204. package/dist/lib/handlers/process-launch.d.ts.map +1 -0
  205. package/dist/lib/handlers/process-launch.js +41 -0
  206. package/dist/lib/handlers/process-launch.js.map +1 -0
  207. package/dist/lib/handlers/process-session-goal.d.ts +29 -0
  208. package/dist/lib/handlers/process-session-goal.d.ts.map +1 -0
  209. package/dist/lib/handlers/process-session-goal.js +74 -0
  210. package/dist/lib/handlers/process-session-goal.js.map +1 -0
  211. package/dist/lib/handlers/process-session-goal.test.d.ts +2 -0
  212. package/dist/lib/handlers/process-session-goal.test.d.ts.map +1 -0
  213. package/dist/lib/handlers/process-session-goal.test.js +134 -0
  214. package/dist/lib/handlers/process-session-goal.test.js.map +1 -0
  215. package/dist/lib/hooks-config.d.ts +28 -4
  216. package/dist/lib/hooks-config.d.ts.map +1 -1
  217. package/dist/lib/hooks-config.js +138 -10
  218. package/dist/lib/hooks-config.js.map +1 -1
  219. package/dist/lib/llm-client.d.ts.map +1 -1
  220. package/dist/lib/llm-client.js +149 -16
  221. package/dist/lib/llm-client.js.map +1 -1
  222. package/dist/lib/mirror-writer-db.d.ts +12 -0
  223. package/dist/lib/mirror-writer-db.d.ts.map +1 -0
  224. package/dist/lib/mirror-writer-db.js +51 -0
  225. package/dist/lib/mirror-writer-db.js.map +1 -0
  226. package/dist/lib/mirror-writer.d.ts +35 -0
  227. package/dist/lib/mirror-writer.d.ts.map +1 -0
  228. package/dist/lib/mirror-writer.js +27 -0
  229. package/dist/lib/mirror-writer.js.map +1 -0
  230. package/dist/lib/mirror-writer.test.d.ts +2 -0
  231. package/dist/lib/mirror-writer.test.d.ts.map +1 -0
  232. package/dist/lib/mirror-writer.test.js +47 -0
  233. package/dist/lib/mirror-writer.test.js.map +1 -0
  234. package/dist/lib/permanent-job-error.d.ts +17 -0
  235. package/dist/lib/permanent-job-error.d.ts.map +1 -0
  236. package/dist/lib/permanent-job-error.js +23 -0
  237. package/dist/lib/permanent-job-error.js.map +1 -0
  238. package/dist/lib/permanent-job-error.test.d.ts +2 -0
  239. package/dist/lib/permanent-job-error.test.d.ts.map +1 -0
  240. package/dist/lib/permanent-job-error.test.js +29 -0
  241. package/dist/lib/permanent-job-error.test.js.map +1 -0
  242. package/dist/lib/version-check.d.ts +11 -0
  243. package/dist/lib/version-check.d.ts.map +1 -0
  244. package/dist/lib/version-check.js +106 -0
  245. package/dist/lib/version-check.js.map +1 -0
  246. package/oclif.manifest.json +611 -81
  247. package/package.json +21 -5
  248. package/dist/commands/insights/sync.d.ts +0 -17
  249. package/dist/commands/insights/sync.d.ts.map +0 -1
  250. package/dist/commands/insights/sync.js +0 -477
  251. package/dist/commands/insights/sync.js.map +0 -1
  252. package/dist/lib/eval-worker.d.ts +0 -12
  253. package/dist/lib/eval-worker.d.ts.map +0 -1
  254. package/dist/lib/eval-worker.js +0 -395
  255. package/dist/lib/eval-worker.js.map +0 -1
  256. package/dist/lib/insights-worker.d.ts +0 -10
  257. package/dist/lib/insights-worker.d.ts.map +0 -1
  258. package/dist/lib/insights-worker.js +0 -329
  259. package/dist/lib/insights-worker.js.map +0 -1
@@ -0,0 +1,47 @@
1
+ import type { Task } from 'graphile-worker';
2
+ /**
3
+ * Wrap a Graphile cron handler with a uniform observability envelope.
4
+ *
5
+ * Every wrapped task emits three log lines on the same `[cron <name>]` prefix:
6
+ * - `[cron <name>] start (job#<id>, attempt <n>/<max>)` — before the handler runs
7
+ * - `[cron <name>] ok in <ms>ms` — on success
8
+ * - `[cron <name>] failed in <ms>ms attempt=<n>/<max>: <err>` — on rejection
9
+ *
10
+ * Why an envelope and not per-handler logging:
11
+ * - Pre-fix, three of five cron handlers logged ad-hoc start lines, two
12
+ * logged nothing. None logged duration. After today's launch-priority +
13
+ * keepalive arc we want a consistent grep-able signature so the dashboard
14
+ * and `flyctl logs | grep '[cron'` give one truth.
15
+ * - Wrapping at the registry boundary keeps individual handlers free of
16
+ * boilerplate. The handler body still emits its own granular progress
17
+ * lines (e.g. `cron_refresh_skills` logs each batch); the envelope just
18
+ * books-ends them.
19
+ *
20
+ * Re-throws the original rejection unchanged so graphile-worker's retry /
21
+ * permanent-fail logic remains intact — the envelope only observes, it
22
+ * never decides.
23
+ */
24
+ export declare function wrapCronWithEnvelope(name: string, handler: Task): Task;
25
+ /**
26
+ * Single source of truth for every cron task this worker runs. Both the
27
+ * Graphile runner (in graphile-worker-runner.ts) and the `rulemetric crons`
28
+ * CLI commands read from this list so a schedule change in one place
29
+ * propagates everywhere.
30
+ *
31
+ * Naming: `name` is the canonical (un-suffixed) task name. The runner
32
+ * appends `__<userId>` so each laptop's worker only claims its own user's
33
+ * crons from the shared Graphile queue.
34
+ */
35
+ export interface CronDefinition {
36
+ /** Canonical task name without the per-user suffix. */
37
+ name: string;
38
+ /** Standard 5-field crontab expression (UTC). */
39
+ schedule: string;
40
+ /** One-line human description shown by `rulemetric crons list`. */
41
+ description: string;
42
+ /** Graphile Task handler. */
43
+ handler: Task;
44
+ }
45
+ export declare const CRON_REGISTRY: readonly CronDefinition[];
46
+ export declare function findCron(name: string): CronDefinition | undefined;
47
+ //# sourceMappingURL=cron-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-registry.d.ts","sourceRoot":"","sources":["../../src/lib/cron-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,iBAAiB,CAAC;AAgBxD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,IAAI,CAgDtE;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC3B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,OAAO,EAAE,IAAI,CAAC;CACjB;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,cAAc,EAiBlD,CAAC;AAEF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEjE"}
@@ -0,0 +1,102 @@
1
+ import { getTracer } from '@rulemetric/telemetry';
2
+ import { cronRegenerateInsights } from './handlers/cron-regenerate-insights.js';
3
+ import { cronSuggestInstructions } from './handlers/cron-suggest-instructions.js';
4
+ // cron_close_stale_sessions removed in phase 1 (migration 00064 → pg_cron).
5
+ // cron_data_integrity_audit removed in phase 2 (migration 00065 → pg_cron).
6
+ // cron_refresh_skills removed in phase 3 (.github/workflows/refresh-skills-registry.yml
7
+ // now POSTs to /api/skills/sync-public
8
+ // after fetching from GitHub, daily).
9
+ // The handler files are kept as documentation of the original behaviour.
10
+ // cron_close_stale_sessions removed — migrated to Supabase pg_cron in
11
+ // supabase/migrations/00064_pg_cron_close_stale_sessions.sql. The handler
12
+ // file (handlers/cron-close-stale-sessions.ts) is kept as documentation of
13
+ // the original intent + the API endpoint /api/sessions/close-stale it
14
+ // shelled out to, but is no longer registered with the runner.
15
+ /**
16
+ * Wrap a Graphile cron handler with a uniform observability envelope.
17
+ *
18
+ * Every wrapped task emits three log lines on the same `[cron <name>]` prefix:
19
+ * - `[cron <name>] start (job#<id>, attempt <n>/<max>)` — before the handler runs
20
+ * - `[cron <name>] ok in <ms>ms` — on success
21
+ * - `[cron <name>] failed in <ms>ms attempt=<n>/<max>: <err>` — on rejection
22
+ *
23
+ * Why an envelope and not per-handler logging:
24
+ * - Pre-fix, three of five cron handlers logged ad-hoc start lines, two
25
+ * logged nothing. None logged duration. After today's launch-priority +
26
+ * keepalive arc we want a consistent grep-able signature so the dashboard
27
+ * and `flyctl logs | grep '[cron'` give one truth.
28
+ * - Wrapping at the registry boundary keeps individual handlers free of
29
+ * boilerplate. The handler body still emits its own granular progress
30
+ * lines (e.g. `cron_refresh_skills` logs each batch); the envelope just
31
+ * books-ends them.
32
+ *
33
+ * Re-throws the original rejection unchanged so graphile-worker's retry /
34
+ * permanent-fail logic remains intact — the envelope only observes, it
35
+ * never decides.
36
+ */
37
+ export function wrapCronWithEnvelope(name, handler) {
38
+ return (async (payload, helpers) => {
39
+ const start = Date.now();
40
+ const job = helpers.job;
41
+ const meta = `job#${job.id}, attempt ${job.attempts}/${job.max_attempts}`;
42
+ // Open an OTel span around the entire firing so the worker-side trace
43
+ // surface mirrors the API's. With ConsoleSpanExporter (the default when
44
+ // OTEL_EXPORTER_OTLP_ENDPOINT is unset) this prints to worker-stdout
45
+ // alongside the existing envelope log lines; with OTLP configured it
46
+ // ships to a real backend. `startActiveSpan` makes child spans
47
+ // (e.g. inside the handler if it ever instruments DB calls) inherit
48
+ // this as parent.
49
+ const tracer = getTracer('rulemetric-cron');
50
+ return tracer.startActiveSpan(`cron ${name}`, {
51
+ attributes: {
52
+ 'cron.name': name,
53
+ 'cron.job_id': String(job.id),
54
+ 'cron.attempt': job.attempts,
55
+ 'cron.max_attempts': job.max_attempts,
56
+ },
57
+ }, async (span) => {
58
+ helpers.logger.info(`[cron ${name}] start (${meta})`);
59
+ try {
60
+ await handler(payload, helpers);
61
+ const duration = Date.now() - start;
62
+ helpers.logger.info(`[cron ${name}] ok in ${duration}ms`);
63
+ span.setAttribute('cron.duration_ms', duration);
64
+ span.setAttribute('cron.outcome', 'ok');
65
+ }
66
+ catch (err) {
67
+ const duration = Date.now() - start;
68
+ const msg = err instanceof Error ? err.message : String(err);
69
+ helpers.logger.error(`[cron ${name}] failed in ${duration}ms attempt=${job.attempts}/${job.max_attempts}: ${msg}`);
70
+ span.setAttribute('cron.duration_ms', duration);
71
+ span.setAttribute('cron.outcome', 'failed');
72
+ span.recordException(err instanceof Error ? err : new Error(msg));
73
+ throw err;
74
+ }
75
+ finally {
76
+ span.end();
77
+ }
78
+ });
79
+ });
80
+ }
81
+ export const CRON_REGISTRY = [
82
+ {
83
+ name: 'cron_regenerate_insights',
84
+ schedule: '0 */6 * * *',
85
+ description: 'Regenerate aggregated insights every 6 hours.',
86
+ handler: cronRegenerateInsights,
87
+ },
88
+ // cron_refresh_skills — moved to GitHub Actions (phase 3, daily 06:00 UTC).
89
+ // cron_close_stale_sessions — moved to Supabase pg_cron (migration 00064).
90
+ // cron_data_integrity_audit — moved to Supabase pg_cron (migration 00065).
91
+ // See note at the top of this file.
92
+ {
93
+ name: 'cron_suggest_instructions',
94
+ schedule: '30 4 * * *',
95
+ description: 'Precompute per-project instruction suggestions for the SessionStart hook.',
96
+ handler: cronSuggestInstructions,
97
+ },
98
+ ];
99
+ export function findCron(name) {
100
+ return CRON_REGISTRY.find((c) => c.name === name);
101
+ }
102
+ //# sourceMappingURL=cron-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-registry.js","sourceRoot":"","sources":["../../src/lib/cron-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cron-registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-registry.test.d.ts","sourceRoot":"","sources":["../../src/lib/cron-registry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,136 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { CRON_REGISTRY, findCron, wrapCronWithEnvelope } from './cron-registry.js';
3
+ describe('CRON_REGISTRY', () => {
4
+ it('has only the claude-spawning crons remaining after the architecture migration', () => {
5
+ // cron_close_stale_sessions → pg_cron (phase 1, migration 00064)
6
+ // cron_data_integrity_audit → pg_cron (phase 2, migration 00065)
7
+ // cron_refresh_skills → GitHub Actions (phase 3,
8
+ // .github/workflows/refresh-skills-registry.yml)
9
+ // Remaining: regenerate_insights + suggest_instructions
10
+ // (genuinely need the laptop — they spawn `claude` CLI per project).
11
+ // These are exactly the two crons the worker is FOR.
12
+ const names = CRON_REGISTRY.map((c) => c.name);
13
+ expect(names).toContain('cron_suggest_instructions');
14
+ expect(names).toContain('cron_regenerate_insights');
15
+ expect(names).not.toContain('cron_close_stale_sessions');
16
+ expect(names).not.toContain('cron_data_integrity_audit');
17
+ expect(names).not.toContain('cron_refresh_skills');
18
+ // Worker is now responsible for ONLY the claude-spawning work.
19
+ expect(names.length).toBe(2);
20
+ });
21
+ it('has unique names (no double-registration)', () => {
22
+ const names = CRON_REGISTRY.map((c) => c.name);
23
+ expect(new Set(names).size).toBe(names.length);
24
+ });
25
+ it('every entry has a valid 5-field crontab expression', () => {
26
+ for (const c of CRON_REGISTRY) {
27
+ const fields = c.schedule.trim().split(/\s+/);
28
+ expect(fields, `${c.name} schedule "${c.schedule}"`).toHaveLength(5);
29
+ }
30
+ });
31
+ it('every entry has a non-empty description', () => {
32
+ for (const c of CRON_REGISTRY) {
33
+ expect(c.description.length, c.name).toBeGreaterThan(10);
34
+ }
35
+ });
36
+ it('findCron returns the right entry by name', () => {
37
+ // cron_refresh_skills (the historical test target) moved to GH Actions
38
+ // in phase 3. Use one of the remaining worker-side crons.
39
+ const found = findCron('cron_suggest_instructions');
40
+ expect(found?.name).toBe('cron_suggest_instructions');
41
+ expect(findCron('nope')).toBeUndefined();
42
+ });
43
+ // (Removed: 'suggest cron is scheduled after refresh-skills cron' — that
44
+ // ordering assertion was about cron_refresh_skills running at 04:00 UTC
45
+ // before cron_suggest_instructions at 04:30 UTC so suggest saw fresh
46
+ // skills. refresh_skills moved to GitHub Actions in phase 3 [daily
47
+ // 06:00 UTC], so it now runs AFTER suggest_instructions. Net effect on
48
+ // user experience: suggest may see day-old skills the day after a new
49
+ // source is added to sources.ts. Acceptable trade-off — the skills
50
+ // registry doesn't change daily in practice. If this becomes a problem,
51
+ // shift suggest_instructions to 06:30 UTC.)
52
+ });
53
+ // Test helpers for the envelope ----------------------------------------------
54
+ /** Build a minimal JobHelpers stub that records calls to `logger.{info,warn,error}`. */
55
+ function makeFakeHelpers(jobOverrides = {}) {
56
+ const calls = [];
57
+ const mkLog = (level) => (msg) => {
58
+ calls.push({ level, msg });
59
+ };
60
+ const logger = { info: mkLog('info'), warn: mkLog('warn'), error: mkLog('error') };
61
+ const job = {
62
+ id: '7777',
63
+ attempts: 1,
64
+ max_attempts: 25,
65
+ ...jobOverrides,
66
+ };
67
+ const helpers = { job, logger, addJob: vi.fn() };
68
+ return { helpers, calls };
69
+ }
70
+ describe('wrapCronWithEnvelope', () => {
71
+ // Each cron handler previously logged ad-hoc start lines (some did, some
72
+ // didn't) and never logged duration. The envelope adds a uniform contract
73
+ // around every cron, callable by the runner at registration time. Tested
74
+ // here, not in the runner, so the logic stays a pure unit.
75
+ it('logs a start line BEFORE invoking the wrapped handler', async () => {
76
+ const order = [];
77
+ const { helpers } = makeFakeHelpers({ id: '42', attempts: 1, max_attempts: 3 });
78
+ helpers.logger.info = (m) => order.push(`log:${m}`);
79
+ const wrapped = wrapCronWithEnvelope('cron_demo', async () => {
80
+ order.push('handler-ran');
81
+ });
82
+ await wrapped({}, helpers);
83
+ expect(order[0]).toMatch(/^log:\[cron cron_demo\] start /);
84
+ expect(order).toContain('handler-ran');
85
+ });
86
+ it('logs an ok line with duration when the handler resolves', async () => {
87
+ const { helpers, calls } = makeFakeHelpers();
88
+ const wrapped = wrapCronWithEnvelope('cron_demo', async () => undefined);
89
+ await wrapped({}, helpers);
90
+ const ok = calls.find((c) => /\[cron cron_demo\] ok /.test(c.msg));
91
+ expect(ok).toBeDefined();
92
+ expect(ok.level).toBe('info');
93
+ expect(ok.msg).toMatch(/in \d+ms/);
94
+ });
95
+ it('logs an error line + re-throws when the handler rejects', async () => {
96
+ const { helpers, calls } = makeFakeHelpers({ attempts: 2, max_attempts: 3 });
97
+ const boom = new Error('kaboom');
98
+ const wrapped = wrapCronWithEnvelope('cron_demo', async () => {
99
+ throw boom;
100
+ });
101
+ await expect(wrapped({}, helpers)).rejects.toBe(boom);
102
+ const fail = calls.find((c) => /\[cron cron_demo\] failed /.test(c.msg));
103
+ expect(fail).toBeDefined();
104
+ expect(fail.level).toBe('error');
105
+ expect(fail.msg).toMatch(/attempt=2\/3/);
106
+ expect(fail.msg).toContain('kaboom');
107
+ });
108
+ it('reports duration as a non-negative integer', async () => {
109
+ const { helpers, calls } = makeFakeHelpers();
110
+ const wrapped = wrapCronWithEnvelope('cron_demo', async () => undefined);
111
+ await wrapped({}, helpers);
112
+ const ok = calls.find((c) => /\[cron cron_demo\] ok /.test(c.msg));
113
+ const match = ok.msg.match(/in (\d+)ms/);
114
+ expect(match).not.toBeNull();
115
+ expect(Number(match[1])).toBeGreaterThanOrEqual(0);
116
+ });
117
+ it('carries job#id and attempt info on the start line for grep-ability', async () => {
118
+ const { helpers, calls } = makeFakeHelpers({ id: '9999', attempts: 3, max_attempts: 25 });
119
+ const wrapped = wrapCronWithEnvelope('cron_demo', async () => undefined);
120
+ await wrapped({}, helpers);
121
+ const start = calls.find((c) => /\[cron cron_demo\] start /.test(c.msg));
122
+ expect(start.msg).toMatch(/job#9999/);
123
+ expect(start.msg).toMatch(/attempt 3\/25/);
124
+ });
125
+ it('preserves non-Error throws (e.g. string) without crashing the envelope', async () => {
126
+ const { helpers, calls } = makeFakeHelpers();
127
+ const wrapped = wrapCronWithEnvelope('cron_demo', async () => {
128
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
129
+ throw 'just-a-string';
130
+ });
131
+ await expect(wrapped({}, helpers)).rejects.toBe('just-a-string');
132
+ const fail = calls.find((c) => c.level === 'error');
133
+ expect(fail.msg).toContain('just-a-string');
134
+ });
135
+ });
136
+ //# sourceMappingURL=cron-registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-registry.test.js","sourceRoot":"","sources":["../../src/lib/cron-registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface CronRunResult {
2
+ name: string;
3
+ durationMs: number;
4
+ ok: boolean;
5
+ error?: string;
6
+ logs: Array<{
7
+ level: string;
8
+ message: string;
9
+ }>;
10
+ }
11
+ /**
12
+ * Synchronously invoke a cron handler by name. Returns a structured result
13
+ * with captured log lines so callers (CLI, tests) can render or assert.
14
+ */
15
+ export declare function runCronByName(name: string): Promise<CronRunResult>;
16
+ //# sourceMappingURL=cron-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-runner.d.ts","sourceRoot":"","sources":["../../src/lib/cron-runner.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAyBxE"}
@@ -0,0 +1,68 @@
1
+ import { findCron } from './cron-registry.js';
2
+ /**
3
+ * Minimal JobHelpers stub for invoking a cron handler outside Graphile
4
+ * (from `rulemetric crons run`, tests, etc.). Handlers in this codebase
5
+ * only use `helpers.logger` and `helpers.job` — we provide both.
6
+ */
7
+ function makeStubHelpers(name, onLog) {
8
+ const logger = {
9
+ info: (msg) => onLog('info', msg),
10
+ warn: (msg) => onLog('warn', msg),
11
+ error: (msg) => onLog('error', msg),
12
+ debug: (msg) => onLog('debug', msg),
13
+ scope: () => logger,
14
+ };
15
+ const job = {
16
+ id: 0n,
17
+ task_identifier: name,
18
+ attempts: 0,
19
+ max_attempts: 1,
20
+ payload: {},
21
+ run_at: new Date(),
22
+ created_at: new Date(),
23
+ updated_at: new Date(),
24
+ };
25
+ return {
26
+ logger,
27
+ job: job,
28
+ // The handlers never call these, but the type demands them:
29
+ withPgClient: () => { throw new Error('withPgClient not available in stub helpers'); },
30
+ query: () => { throw new Error('query not available in stub helpers'); },
31
+ addJob: () => { throw new Error('addJob not available in stub helpers'); },
32
+ getQueueName: () => null,
33
+ abortPromise: new Promise(() => { }),
34
+ abortSignal: new AbortController().signal,
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ };
37
+ }
38
+ /**
39
+ * Synchronously invoke a cron handler by name. Returns a structured result
40
+ * with captured log lines so callers (CLI, tests) can render or assert.
41
+ */
42
+ export async function runCronByName(name) {
43
+ const def = findCron(name);
44
+ if (!def) {
45
+ return {
46
+ name, durationMs: 0, ok: false,
47
+ error: `Unknown cron: ${name}`,
48
+ logs: [],
49
+ };
50
+ }
51
+ const logs = [];
52
+ const helpers = makeStubHelpers(name, (level, message) => logs.push({ level, message }));
53
+ const start = Date.now();
54
+ try {
55
+ await def.handler({}, helpers);
56
+ return { name, durationMs: Date.now() - start, ok: true, logs };
57
+ }
58
+ catch (err) {
59
+ return {
60
+ name,
61
+ durationMs: Date.now() - start,
62
+ ok: false,
63
+ error: err instanceof Error ? err.message : String(err),
64
+ logs,
65
+ };
66
+ }
67
+ }
68
+ //# sourceMappingURL=cron-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-runner.js","sourceRoot":"","sources":["../../src/lib/cron-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Walk a directory up to MAX_DEPTH levels and collect filesystem signals.
3
+ * Returns a deduplicated array of language names. Requires ≥2 distinct
4
+ * signals before the caller scores; one signal is treated as insufficient.
5
+ */
6
+ export declare function detectLanguages(projectPath: string): string[];
7
+ //# sourceMappingURL=detect-languages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-languages.d.ts","sourceRoot":"","sources":["../../src/lib/detect-languages.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA6E7D"}
@@ -0,0 +1,113 @@
1
+ import { existsSync, statSync, readdirSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ const EXCLUDE_DIRS = new Set([
4
+ 'node_modules', '.git', 'dist', 'build', '.next', '.turbo',
5
+ '.worktrees', 'target', 'venv', '__pycache__', '.cache',
6
+ ]);
7
+ const MAX_DEPTH = 3;
8
+ /**
9
+ * Walk a directory up to MAX_DEPTH levels and collect filesystem signals.
10
+ * Returns a deduplicated array of language names. Requires ≥2 distinct
11
+ * signals before the caller scores; one signal is treated as insufficient.
12
+ */
13
+ export function detectLanguages(projectPath) {
14
+ if (!existsSync(projectPath))
15
+ return [];
16
+ const signals = new Set();
17
+ const walk = (dir, depth) => {
18
+ if (depth > MAX_DEPTH)
19
+ return;
20
+ let entries;
21
+ try {
22
+ entries = readdirSync(dir);
23
+ }
24
+ catch {
25
+ return;
26
+ }
27
+ // Inspect file markers at this level. Each marker contributes a *distinct*
28
+ // signal so two files for the same language (e.g. pyproject.toml +
29
+ // requirements.txt) clear the ≥2-signals minimum on their own.
30
+ for (const name of entries) {
31
+ if (name === 'package.json')
32
+ signals.add('JavaScript/TypeScript');
33
+ if (name === 'tsconfig.json')
34
+ signals.add('TypeScript-config');
35
+ if (name === 'pyproject.toml')
36
+ signals.add('Python-pyproject');
37
+ if (name === 'setup.py')
38
+ signals.add('Python-setup');
39
+ if (name === 'requirements.txt')
40
+ signals.add('Python-requirements');
41
+ if (name === 'Pipfile')
42
+ signals.add('Python-pipfile');
43
+ if (name === 'Cargo.toml')
44
+ signals.add('Rust-cargo');
45
+ if (name === 'go.mod')
46
+ signals.add('Go-mod');
47
+ if (name === 'pom.xml')
48
+ signals.add('Java-pom');
49
+ if (name === 'build.gradle' || name === 'build.gradle.kts')
50
+ signals.add('Java-gradle');
51
+ if (name === 'Gemfile')
52
+ signals.add('Ruby-gemfile');
53
+ if (name === 'composer.json')
54
+ signals.add('PHP-composer');
55
+ if (name.endsWith('.ts') || name.endsWith('.tsx'))
56
+ signals.add('TypeScript-source');
57
+ if (name.endsWith('.py'))
58
+ signals.add('Python-source');
59
+ if (name.endsWith('.rs'))
60
+ signals.add('Rust-source');
61
+ if (name.endsWith('.go'))
62
+ signals.add('Go-source');
63
+ }
64
+ if (depth >= MAX_DEPTH)
65
+ return;
66
+ // Recurse into non-excluded subdirectories
67
+ for (const name of entries) {
68
+ if (EXCLUDE_DIRS.has(name))
69
+ continue;
70
+ const full = path.join(dir, name);
71
+ try {
72
+ if (statSync(full).isDirectory())
73
+ walk(full, depth + 1);
74
+ }
75
+ catch {
76
+ // skip unreadable
77
+ }
78
+ }
79
+ };
80
+ walk(projectPath, 0);
81
+ // Collapse the raw signals into language names for the LLM prompt
82
+ const result = new Set();
83
+ if (signals.has('TypeScript-source') || signals.has('TypeScript-config')) {
84
+ result.add('TypeScript');
85
+ }
86
+ else if (signals.has('JavaScript/TypeScript')) {
87
+ result.add('JavaScript');
88
+ }
89
+ if (signals.has('Python-pyproject') ||
90
+ signals.has('Python-setup') ||
91
+ signals.has('Python-requirements') ||
92
+ signals.has('Python-pipfile') ||
93
+ signals.has('Python-source'))
94
+ result.add('Python');
95
+ if (signals.has('Rust-cargo') || signals.has('Rust-source'))
96
+ result.add('Rust');
97
+ if (signals.has('Go-mod') || signals.has('Go-source'))
98
+ result.add('Go');
99
+ if (signals.has('Java-pom') || signals.has('Java-gradle'))
100
+ result.add('Java');
101
+ if (signals.has('Ruby-gemfile'))
102
+ result.add('Ruby');
103
+ if (signals.has('PHP-composer'))
104
+ result.add('PHP');
105
+ // The minimum-2-signals gate counts the raw signals, not the
106
+ // normalized language list. A package.json + tsconfig.json + .ts source
107
+ // is three signals → strong evidence even though the language collapses
108
+ // to one entry. A bare package.json with no .ts/.js source is one signal.
109
+ if (signals.size < 2)
110
+ return [];
111
+ return [...result];
112
+ }
113
+ //# sourceMappingURL=detect-languages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-languages.js","sourceRoot":"","sources":["../../src/lib/detect-languages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=detect-languages.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-languages.test.d.ts","sourceRoot":"","sources":["../../src/lib/detect-languages.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import path from 'node:path';
5
+ import { detectLanguages } from './detect-languages.js';
6
+ describe('detectLanguages', () => {
7
+ let dir;
8
+ beforeAll(() => {
9
+ dir = mkdtempSync(path.join(tmpdir(), 'rm-lang-test-'));
10
+ writeFileSync(path.join(dir, 'package.json'), '{}');
11
+ writeFileSync(path.join(dir, 'tsconfig.json'), '{}');
12
+ mkdirSync(path.join(dir, 'src'));
13
+ writeFileSync(path.join(dir, 'src', 'index.ts'), '');
14
+ });
15
+ afterAll(() => rmSync(dir, { recursive: true, force: true }));
16
+ it('returns TypeScript when ≥2 signals present', () => {
17
+ expect(detectLanguages(dir)).toEqual(['TypeScript']);
18
+ });
19
+ it('returns [] for nonexistent paths', () => {
20
+ expect(detectLanguages('/no/such/path')).toEqual([]);
21
+ });
22
+ it('returns [] when only one signal is present', () => {
23
+ const lone = mkdtempSync(path.join(tmpdir(), 'rm-lang-lone-'));
24
+ writeFileSync(path.join(lone, 'package.json'), '{}');
25
+ expect(detectLanguages(lone)).toEqual([]);
26
+ rmSync(lone, { recursive: true, force: true });
27
+ });
28
+ });
29
+ //# sourceMappingURL=detect-languages.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-languages.test.js","sourceRoot":"","sources":["../../src/lib/detect-languages.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,GAAW,CAAC;IAChB,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;QACxD,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,CAAC;QACpD,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,CAAC;QACrD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QACjC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE9D,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;QAC/D,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,CAAC;QACrD,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"eval-executor.d.ts","sourceRoot":"","sources":["../../src/lib/eval-executor.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA2F3F"}
1
+ {"version":3,"file":"eval-executor.d.ts","sourceRoot":"","sources":["../../src/lib/eval-executor.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA8F3F"}
@@ -15,10 +15,13 @@ export async function executeEval(options) {
15
15
  }
16
16
  const startTime = Date.now();
17
17
  return new Promise((resolve) => {
18
- // Remove CLAUDECODE flag so spawned claude doesn't think it's a nested session,
19
- // but keep CLAUDE_CODE_SSE_PORT etc. so it can still authenticate
18
+ // Remove CLAUDECODE flag so spawned claude doesn't think it's a nested session.
19
+ // Remove HTTPS_PROXY so eval runs bypass the capture proxy — these are internal
20
+ // infrastructure calls, not user sessions. Routing through the proxy creates
21
+ // phantom sessions that pollute insights.
20
22
  const env = { ...process.env };
21
23
  delete env.CLAUDECODE;
24
+ delete env.HTTPS_PROXY;
22
25
  const proc = spawn('claude', args, {
23
26
  cwd: workDir,
24
27
  env,
@@ -1 +1 @@
1
- {"version":3,"file":"eval-executor.js","sourceRoot":"","sources":["../../src/lib/eval-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"eval-executor.js","sourceRoot":"","sources":["../../src/lib/eval-executor.ts"],"names":[],"mappings":"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"}