@rulemetric/cli 0.9.0 → 0.11.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 (196) hide show
  1. package/README.md +1 -2
  2. package/dist/base-command.js +1 -1
  3. package/dist/chunk-35KBN23A.js +1 -0
  4. package/dist/{chunk-PQN2GAG4.js → chunk-7FWIIVMC.js} +1 -1
  5. package/dist/{chunk-X3VL5H24.js → chunk-AC2NUNFC.js} +1 -1
  6. package/dist/{chunk-7FZB65VH.js → chunk-AJN2BLMV.js} +1 -1
  7. package/dist/{chunk-HYDGERWD.js → chunk-BMDHPIW6.js} +1 -1
  8. package/dist/{chunk-IVDTORX5.js → chunk-BMN2WZM2.js} +1 -1
  9. package/dist/{chunk-UUZB4IKU.js → chunk-CLCRZWAG.js} +1 -1
  10. package/dist/chunk-DN2T3FXN.js +1 -0
  11. package/dist/chunk-E4U6AOTM.js +46 -0
  12. package/dist/{chunk-CBUTNIJA.js → chunk-EJZGGT52.js} +1 -1
  13. package/dist/{chunk-KHWG7ZG4.js → chunk-FAOSXPRO.js} +1 -1
  14. package/dist/{chunk-FWTYR36W.js → chunk-FF5TAMDH.js} +1 -1
  15. package/dist/chunk-FK73GD2X.js +2 -0
  16. package/dist/{chunk-YFQ4FOAS.js → chunk-FM4LTGMI.js} +1 -1
  17. package/dist/chunk-FOUGYDLH.js +11 -0
  18. package/dist/{chunk-GF76D2DU.js → chunk-GL3ZDOKJ.js} +1 -1
  19. package/dist/{chunk-5EDINFHF.js → chunk-HWZTQXNM.js} +1 -1
  20. package/dist/chunk-IOV2BEW7.js +13 -0
  21. package/dist/{chunk-VFYT3SC5.js → chunk-IPL2DHU4.js} +1 -1
  22. package/dist/{chunk-MO57LGGK.js → chunk-KDFBKYXK.js} +1 -1
  23. package/dist/{chunk-LLIHRQPH.js → chunk-LWUA3NUZ.js} +1 -1
  24. package/dist/chunk-LZO6YBUW.js +2 -0
  25. package/dist/{chunk-QAV4HW7D.js → chunk-MPDSQALK.js} +1 -1
  26. package/dist/{chunk-X23L2MF6.js → chunk-NBTC5FNV.js} +1 -1
  27. package/dist/{chunk-C2275MFP.js → chunk-NPNSUG3N.js} +1 -1
  28. package/dist/{chunk-S62MK372.js → chunk-OUXWBHCI.js} +1 -1
  29. package/dist/chunk-PK6PSCIP.js +1 -0
  30. package/dist/chunk-PZNWH4VQ.js +7 -0
  31. package/dist/{chunk-BPP7AEFW.js → chunk-R4SSIFKY.js} +1 -1
  32. package/dist/{chunk-3DGL2ZY3.js → chunk-R4W4QDTP.js} +1 -1
  33. package/dist/{chunk-EQHKCGSX.js → chunk-RE7DDQ3O.js} +1 -1
  34. package/dist/{chunk-E2NVNLFD.js → chunk-RS4LSJI2.js} +1 -1
  35. package/dist/{chunk-QTZPLAYC.js → chunk-RUIX6AZ6.js} +1 -1
  36. package/dist/{chunk-WKDXH7NO.js → chunk-SBFTRVZM.js} +1 -1
  37. package/dist/{chunk-SYTQDPPN.js → chunk-SBJNQ5Q6.js} +1 -1
  38. package/dist/{chunk-VA5DPQB4.js → chunk-SV7FDAKW.js} +1 -1
  39. package/dist/{chunk-B22HYCBV.js → chunk-TU2AR6XO.js} +1 -1
  40. package/dist/{chunk-CDDICCY2.js → chunk-UT3EQR4C.js} +1 -1
  41. package/dist/{chunk-KWNIKGAE.js → chunk-V5XRGRJC.js} +1 -1
  42. package/dist/{chunk-2B7Y6JNB.js → chunk-W44E3DYZ.js} +1 -1
  43. package/dist/{chunk-K4B24SMJ.js → chunk-W4ZDAJ6S.js} +1 -1
  44. package/dist/{chunk-PKLXZYBY.js → chunk-WOBFJCMO.js} +1 -1
  45. package/dist/chunk-XK52UAFB.js +17 -0
  46. package/dist/{chunk-6M74HH6Y.js → chunk-XVRQ5WUB.js} +1 -1
  47. package/dist/{chunk-X3RTCN6S.js → chunk-YWALNDT3.js} +1 -1
  48. package/dist/{chunk-SANYAPBK.js → chunk-YZNP4TW4.js} +1 -1
  49. package/dist/{chunk-3AZV7ZPJ.js → chunk-ZXOAI65J.js} +1 -1
  50. package/dist/commands/antigravity/backfill.js +1 -1
  51. package/dist/commands/auth/create-key.js +1 -1
  52. package/dist/commands/auth/login.js +1 -1
  53. package/dist/commands/auth/logout.js +1 -1
  54. package/dist/commands/auth/revoke-key.js +1 -1
  55. package/dist/commands/auth/signup.js +1 -1
  56. package/dist/commands/auth/status.js +1 -1
  57. package/dist/commands/capture/scope.js +1 -1
  58. package/dist/commands/catalog/index.js +1 -1
  59. package/dist/commands/catalog/recommend.js +1 -1
  60. package/dist/commands/crons/list.js +1 -1
  61. package/dist/commands/crons/run.js +1 -1
  62. package/dist/commands/dashboard.js +1 -1
  63. package/dist/commands/diagnostics.js +1 -1
  64. package/dist/commands/eval-targets/create.js +1 -1
  65. package/dist/commands/eval-targets/list.js +1 -1
  66. package/dist/commands/evals/agent.js +1 -1
  67. package/dist/commands/evals/auto-run.js +1 -1
  68. package/dist/commands/evals/benchmark.js +1 -1
  69. package/dist/commands/evals/compare.js +1 -1
  70. package/dist/commands/evals/create.js +1 -1
  71. package/dist/commands/evals/optimize-description.js +1 -1
  72. package/dist/commands/evals/optimize.js +1 -1
  73. package/dist/commands/evals/refine-cases.js +1 -1
  74. package/dist/commands/evals/run.js +1 -1
  75. package/dist/commands/evals/validate-judge.js +1 -1
  76. package/dist/commands/experiments/list.js +1 -1
  77. package/dist/commands/gateway/ensure.js +1 -1
  78. package/dist/commands/hooks/install.js +1 -1
  79. package/dist/commands/hooks/run.js +1 -1
  80. package/dist/commands/hooks/uninstall.js +1 -1
  81. package/dist/commands/instructions/create.js +1 -1
  82. package/dist/commands/instructions/dedupe.js +1 -0
  83. package/dist/commands/instructions/delete.js +1 -1
  84. package/dist/commands/instructions/fork.js +1 -1
  85. package/dist/commands/instructions/get.js +1 -1
  86. package/dist/commands/instructions/list.js +1 -1
  87. package/dist/commands/instructions/promote.js +1 -1
  88. package/dist/commands/instructions/pull.js +1 -1
  89. package/dist/commands/instructions/restore.js +1 -1
  90. package/dist/commands/instructions/retract.js +1 -1
  91. package/dist/commands/instructions/upstream.js +1 -1
  92. package/dist/commands/instructions/versions.js +1 -1
  93. package/dist/commands/launcher.js +1 -1
  94. package/dist/commands/local/down.js +1 -1
  95. package/dist/commands/local/up.js +1 -1
  96. package/dist/commands/org/current.js +1 -1
  97. package/dist/commands/org/list.js +1 -1
  98. package/dist/commands/org/switch.js +1 -1
  99. package/dist/commands/packs/add-instruction.js +1 -1
  100. package/dist/commands/packs/apply.js +1 -1
  101. package/dist/commands/packs/create.js +1 -1
  102. package/dist/commands/packs/fork.js +1 -1
  103. package/dist/commands/packs/get.js +1 -1
  104. package/dist/commands/packs/list.js +1 -1
  105. package/dist/commands/packs/remove-instruction.js +1 -1
  106. package/dist/commands/proxy/env.js +1 -1
  107. package/dist/commands/proxy/logs.js +1 -1
  108. package/dist/commands/proxy/restart.js +1 -1
  109. package/dist/commands/proxy/setup.js +1 -1
  110. package/dist/commands/proxy/start.js +1 -1
  111. package/dist/commands/proxy/status.js +1 -1
  112. package/dist/commands/proxy/stop.js +1 -1
  113. package/dist/commands/research/backfill.js +1 -1
  114. package/dist/commands/research/tail-transcript.js +1 -1
  115. package/dist/commands/service/install.js +1 -1
  116. package/dist/commands/service/status.js +1 -1
  117. package/dist/commands/service/uninstall.js +1 -1
  118. package/dist/commands/sessions/analyze.js +1 -1
  119. package/dist/commands/sessions/delete.js +1 -1
  120. package/dist/commands/sessions/end.js +1 -1
  121. package/dist/commands/sessions/import.js +1 -1
  122. package/dist/commands/sessions/list.js +1 -1
  123. package/dist/commands/sessions/start.js +1 -1
  124. package/dist/commands/setup.js +1 -1
  125. package/dist/commands/skills/export-approved.js +1 -1
  126. package/dist/commands/skills/install.js +4 -4
  127. package/dist/commands/skills/list.js +1 -1
  128. package/dist/commands/skills/publish.js +1 -1
  129. package/dist/commands/skills/search.js +1 -1
  130. package/dist/commands/skills/update.js +1 -1
  131. package/dist/commands/suggestions/accept.js +1 -1
  132. package/dist/commands/suggestions/auto.js +1 -1
  133. package/dist/commands/suggestions/dismiss.js +1 -1
  134. package/dist/commands/suggestions/list.js +1 -1
  135. package/dist/commands/suggestions/refresh.js +1 -1
  136. package/dist/commands/suggestions/undo.js +1 -1
  137. package/dist/dashboard/Dashboard.js +1 -1
  138. package/dist/dashboard/data.js +1 -1
  139. package/dist/dashboard/launcher/ActiveJobsList.js +1 -1
  140. package/dist/dashboard/launcher/LauncherOverlay.js +1 -1
  141. package/dist/dashboard/launcher/NewLaunchForm.js +1 -1
  142. package/dist/dashboard/launcher/api.js +1 -1
  143. package/dist/dashboard/launcher/useLaunchJobs.js +1 -1
  144. package/dist/lib/active-org-refresh.js +1 -1
  145. package/dist/lib/agent-loop.js +1 -1
  146. package/dist/lib/antigravity-transcript.js +1 -1
  147. package/dist/lib/api-client.js +1 -1
  148. package/dist/lib/auth.js +1 -1
  149. package/dist/lib/claude-md-blocks.js +1 -0
  150. package/dist/lib/ensure-api-key.js +1 -1
  151. package/dist/lib/ensure-fresh-token.js +1 -1
  152. package/dist/lib/eval-benchmark.js +1 -1
  153. package/dist/lib/eval-candidate-run.js +1 -1
  154. package/dist/lib/eval-conversation-handler.js +1 -1
  155. package/dist/lib/eval-resume.js +1 -1
  156. package/dist/lib/eval-run-batch.js +1 -1
  157. package/dist/lib/eval-workspace.js +1 -1
  158. package/dist/lib/evolution-enrolment.js +1 -1
  159. package/dist/lib/handlers/cron-auto-accept-suggestions.js +1 -1
  160. package/dist/lib/handlers/cron-eval-autorun.js +1 -1
  161. package/dist/lib/handlers/cron-instruction-evolution.js +1 -1
  162. package/dist/lib/handlers/cron-instruction-training.js +1 -1
  163. package/dist/lib/handlers/cron-refresh-pricing.js +1 -1
  164. package/dist/lib/handlers/cron-suggest-instructions.js +1 -1
  165. package/dist/lib/handlers/distill-memories.js +1 -1
  166. package/dist/lib/handlers/process-changelog.js +1 -1
  167. package/dist/lib/handlers/process-conversation.js +1 -1
  168. package/dist/lib/handlers/process-eval.js +1 -1
  169. package/dist/lib/handlers/process-insights.js +1 -1
  170. package/dist/lib/handlers/process-judge-review.js +1 -1
  171. package/dist/lib/handlers/process-launch.js +1 -1
  172. package/dist/lib/handlers/process-memory-ab.js +1 -1
  173. package/dist/lib/handlers/process-run-cleanup.js +1 -1
  174. package/dist/lib/handlers/process-session-goal.js +1 -1
  175. package/dist/lib/judge-review-runner.js +1 -1
  176. package/dist/lib/manual-tasks.js +1 -1
  177. package/dist/lib/research-client.js +1 -1
  178. package/dist/lib/retraction.js +1 -1
  179. package/dist/lib/setup-steps.js +1 -1
  180. package/dist/lib/skill-paths.js +1 -0
  181. package/dist/lib/suggestion-accept.js +1 -1
  182. package/dist/lib/telemetry.js +1 -1
  183. package/dist/lib/terminal-target-heartbeat.js +1 -1
  184. package/oclif.manifest.json +151 -257
  185. package/package.json +7 -7
  186. package/dist/chunk-3PUOJ6F2.js +0 -45
  187. package/dist/chunk-DZ3FBQYD.js +0 -17
  188. package/dist/chunk-FP6QAPNK.js +0 -1
  189. package/dist/chunk-JZ5Z2BRO.js +0 -7
  190. package/dist/chunk-L2CFSMBC.js +0 -1
  191. package/dist/chunk-MMPZIZYZ.js +0 -10
  192. package/dist/chunk-QWPWY3SW.js +0 -1
  193. package/dist/chunk-R6JXE273.js +0 -13
  194. package/dist/commands/convert.js +0 -1
  195. package/dist/commands/converters.js +0 -1
  196. package/dist/commands/import.js +0 -1
@@ -1,4 +1,4 @@
1
- import{a as h,b as D}from"./chunk-FP6QAPNK.js";import{d as _,e as C}from"./chunk-3PUOJ6F2.js";import{a as o}from"./chunk-ZLLER3HP.js";import*as m from"node:fs/promises";import*as x from"node:path";import{eq as z}from"drizzle-orm";import{randomBytes as H}from"node:crypto";var A="#0d9488",g="#1a1a1a",y="#666666",M="#f5f5f7",k="#ffffff",I="#e5e5e9",O=["Added","Changed","Fixed","Removed","Deprecated","Security"];function U(e){let t=["January","February","March","April","May","June","July","August","September","October","November","December"],[n,r,a]=e.split("-").map(p=>parseInt(p,10));return!n||!r||!a||r<1||r>12?e:`${t[r-1]} ${a}, ${n}`}o(U,"formatIsoDate");function l(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}o(l,"escapeHtml");function P(e){let t=[];for(let n of O){let r=e[n];r&&r.length>0&&t.push({name:n,items:r})}return t}o(P,"orderedSections");function v(e){let{version:t,date:n,sections:r,unsubscribeUrl:a,productUrl:p,recipientName:u}=e,c=U(n),s=`What's new in RuleMetric \u2014 ${c}`,b=u?`Hi ${u},`:"Hi there,",i=P(r),d=new Date().getUTCFullYear(),E=i.map(({name:$,items:R})=>{let w=R.map(S=>` <li style="margin:0 0 6px 0;font-size:15px;line-height:1.5;color:${g};">${l(S)}</li>`).join(`
1
+ import{a as h,b as D}from"./chunk-35KBN23A.js";import{d as _,e as C}from"./chunk-E4U6AOTM.js";import{a as o}from"./chunk-ZLLER3HP.js";import*as m from"node:fs/promises";import*as x from"node:path";import{eq as z}from"drizzle-orm";import{randomBytes as H}from"node:crypto";var A="#0d9488",g="#1a1a1a",y="#666666",M="#f5f5f7",k="#ffffff",I="#e5e5e9",O=["Added","Changed","Fixed","Removed","Deprecated","Security"];function U(e){let t=["January","February","March","April","May","June","July","August","September","October","November","December"],[n,r,a]=e.split("-").map(p=>parseInt(p,10));return!n||!r||!a||r<1||r>12?e:`${t[r-1]} ${a}, ${n}`}o(U,"formatIsoDate");function l(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}o(l,"escapeHtml");function P(e){let t=[];for(let n of O){let r=e[n];r&&r.length>0&&t.push({name:n,items:r})}return t}o(P,"orderedSections");function v(e){let{version:t,date:n,sections:r,unsubscribeUrl:a,productUrl:p,recipientName:u}=e,c=U(n),s=`What's new in RuleMetric \u2014 ${c}`,b=u?`Hi ${u},`:"Hi there,",i=P(r),d=new Date().getUTCFullYear(),E=i.map(({name:$,items:R})=>{let w=R.map(S=>` <li style="margin:0 0 6px 0;font-size:15px;line-height:1.5;color:${g};">${l(S)}</li>`).join(`
2
2
  `);return` <h3 style="margin:24px 0 8px 0;font-size:16px;line-height:1.3;font-weight:600;color:${g};">${$}</h3>
3
3
  <ul style="margin:0 0 8px 0;padding-left:20px;">
4
4
  ${w}
@@ -1 +1 @@
1
- import{e as k}from"./chunk-L2CFSMBC.js";import{a as f}from"./chunk-KGURGIZ2.js";import{a as $}from"./chunk-JPUH3V67.js";import{d as v}from"./chunk-TZA4HAVF.js";import{f as p}from"./chunk-QAV4HW7D.js";import{a as c}from"./chunk-ZLLER3HP.js";async function x(m,t,s=()=>{}){let{eval_:r,configuration:i,targetContent:g,runNumber:o}=m;s(`[${i}] ${r.name} run#${o} \u2014 executing...`);let a=k({targetType:t.targetType,targetContent:g,targetName:t.targetName}),d={methodology:a.methodology,delivery:a.delivery,isolated:a.isWorktree,...t.candidateContentHash?{candidateContentHash:t.candidateContentHash}:{},...a.leakedFiles.length?{leakedFiles:a.leakedFiles}:{}};a.isWorktree||s(`[${i}] ${r.name} run#${o} \u2014 \u26A0 no git worktree; running without repo context`),a.leakedFiles.length&&s(`[${i}] ${r.name} run#${o} \u2014 \u26A0 CONTAMINATED: ${a.leakedFiles.join(", ")} survived the strip`);try{let n=await v({prompt:r.prompt,targetContent:a.systemPrompt,workDir:a.workDir,timeout:t.timeout,model:t.model});if(n.error){let e=f(n.error);return s(`[${i}] ${r.name} run#${o} \u2014 FAILED (${e.kind}): ${n.error}`),{evalId:r.id,evalTargetId:t.targetId,evalTargetVersion:t.targetVersion,configuration:i,runNumber:o,iteration:t.iteration,status:"failed",outputs:{error:n.error,failureKind:e.kind,failureClass:e.class,...d},timing:{duration_ms:n.durationMs,total_tokens:n.totalTokens},grading:{},failure:e}}s(`[${i}] ${r.name} run#${o} \u2014 completed in ${(n.durationMs/1e3).toFixed(1)}s`);let u={};if(!t.skipGrading&&r.expectations.length>0){s(`[${i}] ${r.name} run#${o} \u2014 grading...`);let e=await $({prompt:r.prompt,output:n.output,expectations:r.expectations,model:t.graderModel??t.model,timeout:t.timeout});u=e,s(`[${i}] ${r.name} run#${o} \u2014 grading done: pass_rate=${e.summary.pass_rate==null?"n/a (all assertions errored)":`${(e.summary.pass_rate*100).toFixed(0)}%`}`)}return{evalId:r.id,evalTargetId:t.targetId,evalTargetVersion:t.targetVersion,configuration:i,runNumber:o,iteration:t.iteration,status:"completed",outputs:{transcript:n.output,...d},timing:{duration_ms:n.durationMs,total_tokens:n.totalTokens,total_duration_seconds:n.durationMs/1e3},grading:u}}finally{a.cleanup()}}c(x,"executeAndGradeCase");async function R(m){let{cases:t,targetContent:s,concurrency:r,runNumber:i,opts:g,skipBaseline:o,onLog:a=c(()=>{},"onLog")}=m,d=o?["with_target"]:["with_target","without_target"],n=[];for(let e of t)for(let l of d)n.push({eval_:e,configuration:l,targetContent:l==="with_target"?s:void 0,runNumber:i});let u=[];for(let e=0;e<n.length;e+=Math.max(1,r)){let l=n.slice(e,e+Math.max(1,r)),h=await Promise.all(l.map(b=>x(b,g,a)));u.push(...h)}for(let e of u)try{await p("/api/eval-runs",e)}catch(l){a(` \u26A0 failed to post a run result: ${l instanceof Error?l.message:String(l)}`)}try{await p(`/api/eval-targets/${g.targetId}/label-state`,{})}catch(e){a(` \u26A0 label-state notification skipped: ${e instanceof Error?e.message:String(e)}`)}return{completed:u.filter(e=>e.status==="completed").length,failed:u.filter(e=>e.status==="failed").length,results:u}}c(R,"runBatchAndPost");export{x as a,R as b};
1
+ import{e as k}from"./chunk-DN2T3FXN.js";import{a as f}from"./chunk-KGURGIZ2.js";import{a as $}from"./chunk-JPUH3V67.js";import{d as v}from"./chunk-TZA4HAVF.js";import{f as p}from"./chunk-MPDSQALK.js";import{a as c}from"./chunk-ZLLER3HP.js";async function x(m,t,s=()=>{}){let{eval_:r,configuration:i,targetContent:g,runNumber:o}=m;s(`[${i}] ${r.name} run#${o} \u2014 executing...`);let a=k({targetType:t.targetType,targetContent:g,targetName:t.targetName}),d={methodology:a.methodology,delivery:a.delivery,isolated:a.isWorktree,...t.candidateContentHash?{candidateContentHash:t.candidateContentHash}:{},...a.leakedFiles.length?{leakedFiles:a.leakedFiles}:{}};a.isWorktree||s(`[${i}] ${r.name} run#${o} \u2014 \u26A0 no git worktree; running without repo context`),a.leakedFiles.length&&s(`[${i}] ${r.name} run#${o} \u2014 \u26A0 CONTAMINATED: ${a.leakedFiles.join(", ")} survived the strip`);try{let n=await v({prompt:r.prompt,targetContent:a.systemPrompt,workDir:a.workDir,timeout:t.timeout,model:t.model});if(n.error){let e=f(n.error);return s(`[${i}] ${r.name} run#${o} \u2014 FAILED (${e.kind}): ${n.error}`),{evalId:r.id,evalTargetId:t.targetId,evalTargetVersion:t.targetVersion,configuration:i,runNumber:o,iteration:t.iteration,status:"failed",outputs:{error:n.error,failureKind:e.kind,failureClass:e.class,...d},timing:{duration_ms:n.durationMs,total_tokens:n.totalTokens},grading:{},failure:e}}s(`[${i}] ${r.name} run#${o} \u2014 completed in ${(n.durationMs/1e3).toFixed(1)}s`);let u={};if(!t.skipGrading&&r.expectations.length>0){s(`[${i}] ${r.name} run#${o} \u2014 grading...`);let e=await $({prompt:r.prompt,output:n.output,expectations:r.expectations,model:t.graderModel??t.model,timeout:t.timeout});u=e,s(`[${i}] ${r.name} run#${o} \u2014 grading done: pass_rate=${e.summary.pass_rate==null?"n/a (all assertions errored)":`${(e.summary.pass_rate*100).toFixed(0)}%`}`)}return{evalId:r.id,evalTargetId:t.targetId,evalTargetVersion:t.targetVersion,configuration:i,runNumber:o,iteration:t.iteration,status:"completed",outputs:{transcript:n.output,...d},timing:{duration_ms:n.durationMs,total_tokens:n.totalTokens,total_duration_seconds:n.durationMs/1e3},grading:u}}finally{a.cleanup()}}c(x,"executeAndGradeCase");async function R(m){let{cases:t,targetContent:s,concurrency:r,runNumber:i,opts:g,skipBaseline:o,onLog:a=c(()=>{},"onLog")}=m,d=o?["with_target"]:["with_target","without_target"],n=[];for(let e of t)for(let l of d)n.push({eval_:e,configuration:l,targetContent:l==="with_target"?s:void 0,runNumber:i});let u=[];for(let e=0;e<n.length;e+=Math.max(1,r)){let l=n.slice(e,e+Math.max(1,r)),h=await Promise.all(l.map(b=>x(b,g,a)));u.push(...h)}for(let e of u)try{await p("/api/eval-runs",e)}catch(l){a(` \u26A0 failed to post a run result: ${l instanceof Error?l.message:String(l)}`)}try{await p(`/api/eval-targets/${g.targetId}/label-state`,{})}catch(e){a(` \u26A0 label-state notification skipped: ${e instanceof Error?e.message:String(e)}`)}return{completed:u.filter(e=>e.status==="completed").length,failed:u.filter(e=>e.status==="failed").length,results:u}}c(R,"runBatchAndPost");export{x as a,R as b};
@@ -1 +1 @@
1
- import{b as g,c as m}from"./chunk-N7ODX6PO.js";import{e as s,h as c}from"./chunk-QAV4HW7D.js";import{a as i}from"./chunk-ZLLER3HP.js";var u=6e4;function o(t,e){try{t(JSON.stringify({ts:new Date().toISOString(),...e}))}catch{t(`[tt-heartbeat] log_error event=${e.event}`)}}i(o,"structuredLog");function d(t,e){return e.aborted?Promise.resolve(!1):t<=0?Promise.resolve(!0):new Promise(r=>{let a=setTimeout(()=>{e.removeEventListener("abort",n),r(!0)},t),n=i(()=>{clearTimeout(a),e.removeEventListener("abort",n),r(!1)},"onAbort");e.addEventListener("abort",n,{once:!0})})}i(d,"abortableSleep");async function l(t,e){if(t.kind!=="tmux")return;let a=(await g(m(t.target))).code===0?"active":"missing";try{await c(`/api/terminal-targets/${t.id}/status`,{status:a,lastSeenAt:new Date().toISOString()}),o(e,{event:"tt_heartbeat",targetId:t.id,target:t.target,status:a})}catch(n){o(e,{event:"tt_heartbeat_error",targetId:t.id,target:t.target,error:n instanceof Error?n.message:String(n)})}}i(l,"probeAndReport");async function b(t){let e;try{e=await s("/api/terminal-targets?status=active")}catch(r){o(t,{event:"tt_heartbeat_list_error",error:r instanceof Error?r.message:String(r)});return}for(let r of e.targets??[])try{await l(r,t)}catch(a){o(t,{event:"tt_heartbeat_probe_error",targetId:r.id,error:a instanceof Error?a.message:String(a)})}}i(b,"runOneHeartbeatCycle");async function p(t){let e=t.log??(()=>{}),r=t.intervalMs??u;for(o(e,{event:"tt_heartbeat_start",intervalMs:r});!t.signal.aborted&&(await b(e),!!await d(r,t.signal)););o(e,{event:"tt_heartbeat_stop"})}i(p,"startTerminalTargetHeartbeat");export{l as a,b,p as c};
1
+ import{b as g,c as m}from"./chunk-N7ODX6PO.js";import{e as s,h as c}from"./chunk-MPDSQALK.js";import{a as i}from"./chunk-ZLLER3HP.js";var u=6e4;function o(t,e){try{t(JSON.stringify({ts:new Date().toISOString(),...e}))}catch{t(`[tt-heartbeat] log_error event=${e.event}`)}}i(o,"structuredLog");function d(t,e){return e.aborted?Promise.resolve(!1):t<=0?Promise.resolve(!0):new Promise(r=>{let a=setTimeout(()=>{e.removeEventListener("abort",n),r(!0)},t),n=i(()=>{clearTimeout(a),e.removeEventListener("abort",n),r(!1)},"onAbort");e.addEventListener("abort",n,{once:!0})})}i(d,"abortableSleep");async function l(t,e){if(t.kind!=="tmux")return;let a=(await g(m(t.target))).code===0?"active":"missing";try{await c(`/api/terminal-targets/${t.id}/status`,{status:a,lastSeenAt:new Date().toISOString()}),o(e,{event:"tt_heartbeat",targetId:t.id,target:t.target,status:a})}catch(n){o(e,{event:"tt_heartbeat_error",targetId:t.id,target:t.target,error:n instanceof Error?n.message:String(n)})}}i(l,"probeAndReport");async function b(t){let e;try{e=await s("/api/terminal-targets?status=active")}catch(r){o(t,{event:"tt_heartbeat_list_error",error:r instanceof Error?r.message:String(r)});return}for(let r of e.targets??[])try{await l(r,t)}catch(a){o(t,{event:"tt_heartbeat_probe_error",targetId:r.id,error:a instanceof Error?a.message:String(a)})}}i(b,"runOneHeartbeatCycle");async function p(t){let e=t.log??(()=>{}),r=t.intervalMs??u;for(o(e,{event:"tt_heartbeat_start",intervalMs:r});!t.signal.aborted&&(await b(e),!!await d(r,t.signal)););o(e,{event:"tt_heartbeat_stop"})}i(p,"startTerminalTargetHeartbeat");export{l as a,b,p as c};
@@ -0,0 +1,2 @@
1
+ import{a as l}from"./chunk-ZLLER3HP.js";import*as r from"node:fs";import*as c from"node:path";import k from"gray-matter";var f=".agents/skills",h=".claude/skills",d=64,u=1024;function p(t){return(t??"").replace(/^skills--/,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,d).replace(/-+$/,"")||"skill"}l(p,"skillDirName");function N(t){let i=[];return t||i.push("name is required"),t.length>d&&i.push(`name exceeds ${d} characters`),/[^a-z0-9-]/.test(t)&&i.push("name may only contain lowercase letters, digits and hyphens"),/^-|-$/.test(t)&&i.push("name must not start or end with a hyphen"),t.includes("--")&&i.push("name must not contain consecutive hyphens"),i}l(N,"validateSkillName");function g(t){let i=t.trim();return!i||/^[#>|<]|^```|^~~~/.test(i)||/^!?\[[^\]]*\]\s*(\([^)]*\))?$/.test(i)||!/[A-Za-z]{3}/.test(i)?"":i}l(g,"usableDescription");function m(t){let i=!1;for(let n of t.split(`
2
+ `)){let e=n.trim();if(!e)continue;if(e.startsWith("```")||e.startsWith("~~~")){i=!i;continue}if(i||/^[#>|<-]|^---/.test(e))continue;let s=e.replace(/!\[[^\]]*\]\([^)]*\)/g,"").replace(/\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^[*+]\s+/,"").replace(/[*_`]/g,"").trim();if(!(s.length<20)&&s.includes(" ")&&/[A-Za-z]{3}/.test(s))return s}return""}l(m,"firstMeaningfulLine");function y(t){let i=[],n={},e=t.content,s=!1;try{let a=k(t.content);s=t.content.trimStart().startsWith("---")&&Object.keys(a.data).length>0,s&&(n={...a.data},e=a.content)}catch{i.push("existing frontmatter was not valid YAML and was replaced")}typeof n.name=="string"&&n.name!==t.dirName&&i.push(`frontmatter name "${n.name}" renamed to "${t.dirName}" to match its directory`),n.name=t.dirName;let o=g(typeof n.description=="string"?n.description:"");if(o)o.length>u&&(n.description=o.slice(0,u),i.push(`description truncated to the ${u}-character spec limit`));else{let a=g(t.description??"")||m(e);a?(n.description=a.slice(0,u),i.push("description was missing and has been derived; agents match on it, so review it")):(n.description=`Skill: ${t.dirName}`,i.push("no description available \u2014 a placeholder was written, and this skill will rarely trigger until it is written properly"))}return{text:k.stringify(e,n),addedFrontmatter:!s,warnings:i}}l(y,"buildSkillFile");function w(t,i){let n=c.join(t,f,i),e=c.join(t,h,i);return{realDir:n,skillFile:c.join(n,"SKILL.md"),linkPath:e,linkTarget:c.relative(c.dirname(e),n)}}l(w,"skillTargets");function b(t){let i=p(t.name),n=w(t.dir,i),e=y({dirName:i,content:t.content,description:t.description}),s=[...e.warnings];r.mkdirSync(n.realDir,{recursive:!0}),r.writeFileSync(n.skillFile,e.text,"utf8"),r.mkdirSync(c.dirname(n.linkPath),{recursive:!0});let o=P(n.linkPath);if(o){if(o.isSymbolicLink()&&x(n.linkPath)===n.linkTarget)return{dirName:i,skillFile:n.skillFile,linkPath:n.linkPath,linkKind:"symlink",warnings:s};if(!t.force)return s.push(`${n.linkPath} already exists and was not written by this command \u2014 left as is. Re-run with --force to replace it.`),{dirName:i,skillFile:n.skillFile,linkPath:n.linkPath,linkKind:"none",warnings:s};r.rmSync(n.linkPath,{recursive:!0,force:!0})}let a=S(n);return s.push(...a.warnings),{dirName:i,skillFile:n.skillFile,linkPath:n.linkPath,linkKind:a.linkKind,warnings:s}}l(b,"writeSkill");function S(t,i=(n,e)=>r.symlinkSync(n,e,"dir")){try{return i(t.linkTarget,t.linkPath),{linkKind:"symlink",warnings:[]}}catch{return r.cpSync(t.realDir,t.linkPath,{recursive:!0}),{linkKind:"copy",warnings:[`symlink refused by this platform \u2014 wrote a copy to ${t.linkPath}. Re-install after editing the skill, or the two will drift.`]}}}l(S,"linkOrCopy");function P(t){try{return r.lstatSync(t)}catch{return null}}l(P,"lstatOrNull");function x(t){try{return r.readlinkSync(t)}catch{return null}}l(x,"safeReadlink");export{f as a,h as b,p as c,N as d,y as e,w as f,b as g,S as h};
@@ -1 +1 @@
1
- import{k as E}from"./chunk-3PUOJ6F2.js";import{a as p,e as w}from"./chunk-JZ5Z2BRO.js";import{a as o}from"./chunk-ZLLER3HP.js";import{fileURLToPath as v}from"node:url";import{existsSync as A,readFileSync as b}from"node:fs";import{dirname as L,join as x}from"node:path";function C(){let t=L(v(import.meta.url));for(let e=0;e<8;e++){let s=x(t,"package.json");if(A(s))try{let i=JSON.parse(b(s,"utf8"));if(i.name==="@rulemetric/cli"&&i.version)return i.version}catch{}let n=L(t);if(n===t)break;t=n}return"0.0.0"}o(C,"readCliVersion");var O=C(),I="https://rulemetric.com",l=class extends Error{constructor(s,n){super(n);this.statusCode=s;this.name="ApiError"}static{o(this,"ApiError")}};function S(){let t=p(),e=process.env.RULEMETRIC_API_URL??t.apiUrl;if(!e){if(process.env.RULEMETRIC_STRICT_LOCAL==="1"||t.strictLocal==="1")throw new Error("RULEMETRIC_STRICT_LOCAL is set but no RULEMETRIC_API_URL is configured \u2014 refusing the cloud default. Set RULEMETRIC_API_URL in the environment or ~/.config/rulemetric/env.");e=I}let s=new URL(e);if(s.protocol==="http:"&&s.hostname!=="localhost"&&s.hostname!=="127.0.0.1")throw new Error(`API URL must use HTTPS for non-localhost hosts: ${e}`);return e}o(S,"getBaseUrl");async function a(t,e={}){let n=`${S()}${t}`,i={"Content-Type":"application/json","User-Agent":`rulemetric-cli/${O}`,...e.headers},m=p(),d=process.env.RULEMETRIC_API_KEY||m.apiKey||w()?.accessToken||m.accessToken;d&&(i.Authorization=`Bearer ${d}`);let h=new URL(n),f=h.hostname==="localhost"||h.hostname==="127.0.0.1",P=process.env.HTTPS_PROXY,R=process.env.HTTP_PROXY;f&&(delete process.env.HTTPS_PROXY,delete process.env.HTTP_PROXY);let u=e.timeoutMs?new AbortController:void 0,g=!1,y=u?setTimeout(()=>{g=!0,u.abort()},e.timeoutMs):void 0,r;try{r=await fetch(n,{method:e.method??"GET",headers:i,body:e.body?JSON.stringify(e.body):void 0,signal:u?.signal})}catch(T){if(g){let U=new URL(n).host,_=Math.round(e.timeoutMs/1e3);throw new l(408,`Request to ${U} timed out after ${_}s. This is usually transient or a local proxy/gateway issue \u2014 retry, and if it persists check HTTPS_PROXY / the RuleMetric gateway (:8787).`)}throw T}finally{y&&clearTimeout(y),f&&(P!==void 0&&(process.env.HTTPS_PROXY=P),R!==void 0&&(process.env.HTTP_PROXY=R))}let c;if(r.headers.get("content-type")?.includes("application/json")?c=await r.json():c=await r.text(),!r.ok){let{message:T}=E(r.status,c);throw new l(r.status,T)}return c}o(a,"api");var j=o(t=>a(t),"apiGet"),F=o((t,e)=>a(t,{method:"POST",body:e}),"apiPost"),B=o((t,e)=>a(t,{method:"PUT",body:e}),"apiPut"),D=o((t,e)=>a(t,{method:"PATCH",body:e}),"apiPatch"),G=o(t=>a(t,{method:"DELETE"}),"apiDelete");export{I as a,l as b,S as c,a as d,j as e,F as f,B as g,D as h,G as i};
1
+ import{k as E}from"./chunk-E4U6AOTM.js";import{a as p,e as w}from"./chunk-PZNWH4VQ.js";import{a as o}from"./chunk-ZLLER3HP.js";import{fileURLToPath as v}from"node:url";import{existsSync as A,readFileSync as b}from"node:fs";import{dirname as L,join as x}from"node:path";function C(){let t=L(v(import.meta.url));for(let e=0;e<8;e++){let s=x(t,"package.json");if(A(s))try{let i=JSON.parse(b(s,"utf8"));if(i.name==="@rulemetric/cli"&&i.version)return i.version}catch{}let n=L(t);if(n===t)break;t=n}return"0.0.0"}o(C,"readCliVersion");var O=C(),I="https://rulemetric.com",l=class extends Error{constructor(s,n){super(n);this.statusCode=s;this.name="ApiError"}static{o(this,"ApiError")}};function S(){let t=p(),e=process.env.RULEMETRIC_API_URL??t.apiUrl;if(!e){if(process.env.RULEMETRIC_STRICT_LOCAL==="1"||t.strictLocal==="1")throw new Error("RULEMETRIC_STRICT_LOCAL is set but no RULEMETRIC_API_URL is configured \u2014 refusing the cloud default. Set RULEMETRIC_API_URL in the environment or ~/.config/rulemetric/env.");e=I}let s=new URL(e);if(s.protocol==="http:"&&s.hostname!=="localhost"&&s.hostname!=="127.0.0.1")throw new Error(`API URL must use HTTPS for non-localhost hosts: ${e}`);return e}o(S,"getBaseUrl");async function a(t,e={}){let n=`${S()}${t}`,i={"Content-Type":"application/json","User-Agent":`rulemetric-cli/${O}`,...e.headers},m=p(),d=process.env.RULEMETRIC_API_KEY||m.apiKey||w()?.accessToken||m.accessToken;d&&(i.Authorization=`Bearer ${d}`);let h=new URL(n),f=h.hostname==="localhost"||h.hostname==="127.0.0.1",P=process.env.HTTPS_PROXY,R=process.env.HTTP_PROXY;f&&(delete process.env.HTTPS_PROXY,delete process.env.HTTP_PROXY);let u=e.timeoutMs?new AbortController:void 0,g=!1,y=u?setTimeout(()=>{g=!0,u.abort()},e.timeoutMs):void 0,r;try{r=await fetch(n,{method:e.method??"GET",headers:i,body:e.body?JSON.stringify(e.body):void 0,signal:u?.signal})}catch(T){if(g){let U=new URL(n).host,_=Math.round(e.timeoutMs/1e3);throw new l(408,`Request to ${U} timed out after ${_}s. This is usually transient or a local proxy/gateway issue \u2014 retry, and if it persists check HTTPS_PROXY / the RuleMetric gateway (:8787).`)}throw T}finally{y&&clearTimeout(y),f&&(P!==void 0&&(process.env.HTTPS_PROXY=P),R!==void 0&&(process.env.HTTP_PROXY=R))}let c;if(r.headers.get("content-type")?.includes("application/json")?c=await r.json():c=await r.text(),!r.ok){let{message:T}=E(r.status,c);throw new l(r.status,T)}return c}o(a,"api");var j=o(t=>a(t),"apiGet"),F=o((t,e)=>a(t,{method:"POST",body:e}),"apiPost"),B=o((t,e)=>a(t,{method:"PUT",body:e}),"apiPut"),D=o((t,e)=>a(t,{method:"PATCH",body:e}),"apiPatch"),G=o(t=>a(t,{method:"DELETE"}),"apiDelete");export{I as a,l as b,S as c,a as d,j as e,F as f,B as g,D as h,G as i};
@@ -1 +1 @@
1
- import{b as f}from"./chunk-ZXF5NE54.js";import{d as i,e as n,g,h as m}from"./chunk-NJ5UED3H.js";import{a as s}from"./chunk-ZLLER3HP.js";import{Box as u,Text as t}from"ink";import{jsx as l,jsxs as e}from"react/jsx-runtime";var y={pending:{glyph:"\u25CC",color:n},queued:{glyph:"\u25CC",color:n},running:{glyph:"\u25CF",color:i},completed:{glyph:"\u2713",color:g},failed:{glyph:"\u2717",color:m},cancelled:{glyph:"\u2298",color:n}};function b(c){let p=Date.now()-new Date(c).getTime(),r=Math.floor(p/6e4);if(r<1)return"now";if(r<60)return`${r}m`;let o=Math.floor(r/60);return o<24?`${o}h`:`${Math.floor(o/24)}d`}s(b,"ago");function w({jobs:c,selectedIndex:p,focused:r}){return c.length===0?e(u,{flexDirection:"column",paddingX:1,children:[l(t,{bold:!0,color:i,children:"\u25BC Active jobs"}),l(t,{dimColor:!0,children:" (no jobs yet \u2014 press tab to focus the form below)"})]}):e(u,{flexDirection:"column",paddingX:1,children:[e(t,{bold:!0,color:i,children:["\u25BC Active jobs (last ",c.length,")"]}),c.map((o,h)=>{let d=r&&h===p,a=y[o.status]??{glyph:"?",color:n},x=o.config?.projectPath??"",T=(o.config?.prompt??"").slice(0,30);return e(t,{wrap:"truncate-end",children:[l(t,{color:d?i:n,children:d?"\u25B6 ":" "}),e(t,{color:a.color,children:[a.glyph," "]}),l(t,{dimColor:!0,children:o.status.padEnd(10)}),l(t,{children:f(o.tool).padEnd(14)}),l(t,{dimColor:!0,children:x.padEnd(28)}),e(t,{children:['"',T,'"']}),e(t,{dimColor:!0,children:[" ",b(o.createdAt)]})]},o.id)})]})}s(w,"ActiveJobsList");export{w as a};
1
+ import{d as i,e as n,g,h as m}from"./chunk-NJ5UED3H.js";import{b as f}from"./chunk-ZXF5NE54.js";import{a as s}from"./chunk-ZLLER3HP.js";import{Box as u,Text as t}from"ink";import{jsx as l,jsxs as e}from"react/jsx-runtime";var y={pending:{glyph:"\u25CC",color:n},queued:{glyph:"\u25CC",color:n},running:{glyph:"\u25CF",color:i},completed:{glyph:"\u2713",color:g},failed:{glyph:"\u2717",color:m},cancelled:{glyph:"\u2298",color:n}};function b(c){let p=Date.now()-new Date(c).getTime(),r=Math.floor(p/6e4);if(r<1)return"now";if(r<60)return`${r}m`;let o=Math.floor(r/60);return o<24?`${o}h`:`${Math.floor(o/24)}d`}s(b,"ago");function w({jobs:c,selectedIndex:p,focused:r}){return c.length===0?e(u,{flexDirection:"column",paddingX:1,children:[l(t,{bold:!0,color:i,children:"\u25BC Active jobs"}),l(t,{dimColor:!0,children:" (no jobs yet \u2014 press tab to focus the form below)"})]}):e(u,{flexDirection:"column",paddingX:1,children:[e(t,{bold:!0,color:i,children:["\u25BC Active jobs (last ",c.length,")"]}),c.map((o,h)=>{let d=r&&h===p,a=y[o.status]??{glyph:"?",color:n},x=o.config?.projectPath??"",T=(o.config?.prompt??"").slice(0,30);return e(t,{wrap:"truncate-end",children:[l(t,{color:d?i:n,children:d?"\u25B6 ":" "}),e(t,{color:a.color,children:[a.glyph," "]}),l(t,{dimColor:!0,children:o.status.padEnd(10)}),l(t,{children:f(o.tool).padEnd(14)}),l(t,{dimColor:!0,children:x.padEnd(28)}),e(t,{children:['"',T,'"']}),e(t,{dimColor:!0,children:[" ",b(o.createdAt)]})]},o.id)})]})}s(w,"ActiveJobsList");export{w as a};
@@ -1 +1 @@
1
- import{c as d,d as t}from"./chunk-SYTQDPPN.js";import{a as r}from"./chunk-ZLLER3HP.js";async function g(o,i){let{evalTargetId:s}=o;try{let e=await t({targetId:s,engineFlag:"auto",skipReviewed:!0,log:r(a=>i.logger.info(`[judge-review] ${a}`),"log"),warn:r(a=>i.logger.warn(`[judge-review] ${a}`),"warn")});return{evalTargetId:s,reviewerModel:e.reviewerModel,comparedPairs:e.report.pairs,disagreements:e.report.disagreements.length,persisted:e.persisted,alreadyReviewed:e.alreadyReviewed,deferredPartialRuns:e.deferredPartialRuns}}catch(e){if(e instanceof d)return i.logger.info(`[judge-review] skipped (${e.reason}): ${e.message}`),{evalTargetId:s,skipped:e.reason};throw e}}r(g,"processJudgeReview");export{g as a};
1
+ import{c as d,d as t}from"./chunk-SBJNQ5Q6.js";import{a as r}from"./chunk-ZLLER3HP.js";async function g(o,i){let{evalTargetId:s}=o;try{let e=await t({targetId:s,engineFlag:"auto",skipReviewed:!0,log:r(a=>i.logger.info(`[judge-review] ${a}`),"log"),warn:r(a=>i.logger.warn(`[judge-review] ${a}`),"warn")});return{evalTargetId:s,reviewerModel:e.reviewerModel,comparedPairs:e.report.pairs,disagreements:e.report.disagreements.length,persisted:e.persisted,alreadyReviewed:e.alreadyReviewed,deferredPartialRuns:e.deferredPartialRuns}}catch(e){if(e instanceof d)return i.logger.info(`[judge-review] skipped (${e.reason}): ${e.message}`),{evalTargetId:s,skipped:e.reason};throw e}}r(g,"processJudgeReview");export{g as a};
@@ -1,4 +1,4 @@
1
- import{f}from"./chunk-B3BHB26P.js";import{b as S,e as a,h as y}from"./chunk-QAV4HW7D.js";import{a as p}from"./chunk-ZLLER3HP.js";var _=1800*1e3,G=300*1e3,T=10,h=`Given these messages from an AI coding session, write a 1-2 sentence summary of what the user is trying to accomplish. Focus on the goal, not the steps. No preamble.
1
+ import{f}from"./chunk-B3BHB26P.js";import{b as S,e as a,h as y}from"./chunk-MPDSQALK.js";import{a as p}from"./chunk-ZLLER3HP.js";var _=1800*1e3,G=300*1e3,T=10,h=`Given these messages from an AI coding session, write a 1-2 sentence summary of what the user is trying to accomplish. Focus on the goal, not the steps. No preamble.
2
2
 
3
3
  Return strict JSON in the form: {"goalSummary": "..."}`;async function k(n,e={}){let d=e.llm??f,o=e.now??Date.now,w=e.getSession??(async s=>{try{return await a(`/api/sessions/${s}`)}catch(t){if(t instanceof S&&t.statusCode===404)return null;throw t}}),m=e.getEvents??((s,t)=>a(`/api/sessions/${s}/events?limit=${t.limit}&sort=${t.sort}`)),v=e.saveGoal??(async(s,t)=>{await y(`/api/sessions/${s}/enrich`,{analysis:t})}),i=await w(n.sessionId);if(!i)return{skipped:"not_found"};let[P]=await m(n.sessionId,{limit:1,sort:"desc"}),A=new Date(P?.timestamp??i.startedAt).getTime();if(o()-A>_)return{skipped:"stale"};let l=i.analysis??{},c=l.goalSummaryAt?new Date(l.goalSummaryAt).getTime():0;if(c&&o()-c<G)return{skipped:"recent"};let g=(await m(n.sessionId,{limit:T*2,sort:"asc"})).filter(s=>s.content&&(s.eventType==="user_message"||s.eventType==="assistant_response")).map(s=>`${s.eventType==="user_message"?"USER":"ASSISTANT"}: ${s.content}`).join(`
4
4
 
@@ -0,0 +1 @@
1
+ import{d as l}from"./chunk-FOUGYDLH.js";import{e as g}from"./chunk-MPDSQALK.js";import{a as u}from"./chunk-ZLLER3HP.js";import{existsSync as b,statSync as h}from"node:fs";async function j(m,f){let n=u(r=>f?.logger?.info?.(r)??console.log(r),"log"),{projectPath:s}=m,o=`[cron_auto_accept_suggestions] ${s}`;if(!s)return{skipped:"no-project-path"};if(!b(s)||!h(s).isDirectory())return n(`${o}: project directory no longer exists on this machine \u2014 skipping`),{skipped:"project-path-missing"};let e=await g(`/api/instruction-suggestions/auto-acceptable?projectPath=${encodeURIComponent(s)}`);if(!e.consent.allowed)return n(`${o}: ${e.consent.reason??"no consent"} (${e.consent.source})`),{skipped:"no-consent",reason:e.consent.reason};for(let r of e.refused)n(`${o}: refused "${r.name}" \u2014 ${r.reason}`);if(e.eligible.length===0)return n(`${o}: nothing to adopt`+(e.budget?` (${e.budget.used}/${e.budget.max} used in ${e.budget.windowDays}d)`:"")),{skipped:"nothing-eligible",refused:e.refused.length,adopted:0};let i=0,a=0,d=0,c=0,p=[];for(let r of e.eligible)try{let t=await l({suggestionId:r.id,dir:s,projectPath:s,actor:"auto"});if(t.action==="added")i+=1,p.push(t.name),n(`${o}: adopted "${t.name}" (score ${r.score.toFixed(2)})`);else if(t.action==="redundant"){d+=1;for(let $ of t.messages)n(`${o}: ${$}`)}else a+=1,n(`${o}: "${t.name}" was already in CLAUDE.md`)}catch(t){c+=1,n(`${o}: failed to adopt "${r.name}" \u2014 ${t instanceof Error?t.message:String(t)}`)}return n(`${o}: ${i} adopted, ${a} already present, ${d} already covered in other words, ${c} failed, ${e.refused.length} refused. Undo any of them with \`rulemetric suggestions undo <instruction-id>\`.`),{adopted:i,alreadyPresent:a,redundant:d,failed:c,refused:e.refused.length,names:p}}u(j,"cronAutoAcceptSuggestions");export{j as a};
@@ -0,0 +1,7 @@
1
+ import{a as e}from"./chunk-ZLLER3HP.js";import*as i from"node:fs";import*as a from"node:path";import*as _ from"node:os";function R(){return process.env.RULEMETRIC_CONFIG_DIR||a.join(_.homedir(),".config","rulemetric")}e(R,"getConfigDir");var u;function S(){if(u!==void 0)return u;try{let n=a.join(R(),"env");if(!i.existsSync(n))return u={};let s=i.readFileSync(n,"utf-8"),E=e(h=>s.match(new RegExp(`^${h}=(.+)$`,"m"))?.[1]?.trim(),"read");return u={apiKey:E("RULEMETRIC_API_KEY"),accessToken:E("RULEMETRIC_ACCESS_TOKEN"),apiUrl:E("RULEMETRIC_API_URL"),strictLocal:E("RULEMETRIC_STRICT_LOCAL")},u}catch{return u={}}}e(S,"loadEnvFileAuth");function m(){u=void 0}e(m,"invalidateEnvFileAuthCache");function U(){u=void 0}e(U,"__resetEnvFileAuthCache");function L(n=R()){let s=a.join(n,"auth.json");function E(o){i.mkdirSync(n,{recursive:!0,mode:448}),i.writeFileSync(s,JSON.stringify(o,null,2),{encoding:"utf-8",mode:384})}e(E,"saveToken");function h(){try{let o=i.readFileSync(s,"utf-8"),t=JSON.parse(o);return t&&typeof t=="object"&&"accessToken"in t&&"expiresAt"in t&&"email"in t&&typeof t.accessToken=="string"&&typeof t.expiresAt=="string"?t:null}catch{return null}}e(h,"loadToken");function g(){try{i.unlinkSync(s)}catch{}}e(g,"clearToken");function y(){let o=h();if(!o)return!1;let t=new Date(o.expiresAt).getTime();return Number.isNaN(t)?!1:Date.now()<t}e(y,"isAuthenticated");function k(o=0){let t=h();if(!t?.refreshToken)return!1;let r=new Date(t.expiresAt).getTime();return Number.isNaN(r)?!0:Date.now()>=r-o}e(k,"isRefreshable");function C(o,t){i.mkdirSync(n,{recursive:!0,mode:448});let r=a.join(n,"env"),c="",v="";try{let p=i.readFileSync(r,"utf-8"),d=p.match(/^RULEMETRIC_API_KEY=(.+)$/m);d&&(c=d[1]);let T=p.match(/^RULEMETRIC_API_URL=(.+)$/m);T&&(v=T[1])}catch{}let l=[`RULEMETRIC_ACCESS_TOKEN=${o}`];c&&l.push(`RULEMETRIC_API_KEY=${c}`);let A=t||v||"https://rulemetric.com";l.push(`RULEMETRIC_API_URL=${A}`),i.writeFileSync(r,l.join(`
2
+ `)+`
3
+ `,{encoding:"utf-8",mode:384}),m()}e(C,"saveEnvFile");function I(o,t){i.mkdirSync(n,{recursive:!0,mode:448});let r=a.join(n,"env"),c="",v="";try{let p=i.readFileSync(r,"utf-8"),d=p.match(/^RULEMETRIC_ACCESS_TOKEN=(.+)$/m);d&&(c=d[1]);let T=p.match(/^RULEMETRIC_API_URL=(.+)$/m);T&&(v=T[1])}catch{}let l=[`RULEMETRIC_API_KEY=${o}`];c&&l.push(`RULEMETRIC_ACCESS_TOKEN=${c}`);let A=t||v||"https://rulemetric.com";A&&l.push(`RULEMETRIC_API_URL=${A}`),i.writeFileSync(r,l.join(`
4
+ `)+`
5
+ `,{encoding:"utf-8",mode:384}),m()}e(I,"saveApiKeyToEnv");function x(){let o=a.join(n,"env");try{i.unlinkSync(o)}catch{}m()}e(x,"clearEnvFile");function F(){let o=a.join(n,"env");try{let t=i.readFileSync(o,"utf-8"),r=t.split(`
6
+ `).filter(c=>!c.startsWith("RULEMETRIC_API_KEY=")).join(`
7
+ `);r!==t&&i.writeFileSync(o,r,{encoding:"utf-8",mode:384})}catch{}m()}return e(F,"removeApiKeyFromEnvFile"),{saveToken:E,loadToken:h,clearToken:g,isAuthenticated:y,isRefreshable:k,saveEnvFile:C,saveApiKeyToEnv:I,clearEnvFile:x,removeApiKeyFromEnvFile:F,configDir:n,authFile:s}}e(L,"createAuthStore");function f(){return L()}e(f,"getStore");function K(n){f().saveToken(n)}e(K,"saveToken");function M(){return f().loadToken()}e(M,"loadToken");function P(){f().clearToken()}e(P,"clearToken");function N(){if(process.env.RULEMETRIC_API_KEY||f().isAuthenticated())return!0;let n=S();return!!(n.apiKey||n.accessToken)}e(N,"isAuthenticated");function j(n,s){f().saveEnvFile(n,s)}e(j,"saveEnvFile");function $(n,s){f().saveApiKeyToEnv(n,s)}e($,"saveApiKey");function w(){f().clearEnvFile()}e(w,"clearEnvFile");function O(){f().removeApiKeyFromEnvFile()}e(O,"removeApiKeyFromEnv");function b(){return R()}e(b,"getDefaultConfigDir");var Y=R();export{S as a,U as b,L as c,K as d,M as e,P as f,N as g,j as h,$ as i,w as j,O as k,b as l,Y as m};
@@ -1 +1 @@
1
- import{c as u}from"./chunk-UUZB4IKU.js";import{b as c,e as y,f as m}from"./chunk-QAV4HW7D.js";import{a as n,b as t,i as s,k as p}from"./chunk-JZ5Z2BRO.js";import{a}from"./chunk-ZLLER3HP.js";import{hostname as l}from"node:os";async function R(f,r,h){t();let o=process.env.RULEMETRIC_API_KEY,d=n().apiKey;if(o||d)try{await y("/api/profile");return}catch(e){if(!(e instanceof c)||e.statusCode!==401)return;if(o){r('Your exported RULEMETRIC_API_KEY was rejected (revoked?). Unset it or replace it with a fresh key (`rulemetric auth create-key --name "my-laptop"`).');return}p(),t(),r("Stored API key was rejected (revoked?) \u2014 replacing it with a fresh one.")}let i=`${l()} (auto)`;try{let e=await m("/api/auth/api-keys",{name:i});s(e.key,process.env.RULEMETRIC_API_URL),t(),f(`Created API key "${i}" for hooks + proxy auth (saved to your config).`),u("key_created",{},h)}catch(e){let k=e instanceof Error?e.message:String(e);r(`Could not auto-create an API key (${k}). Hooks/proxy will work via your session token for ABOUT AN HOUR \u2014 the token expires, and capture then stops until a key exists. Run \`rulemetric auth create-key --name "my-laptop"\` (or \`rulemetric auth login\` again) to fix this permanently.`)}}a(R,"ensureDeviceApiKey");export{R as a};
1
+ import{c as u}from"./chunk-CLCRZWAG.js";import{b as c,e as y,f as m}from"./chunk-MPDSQALK.js";import{a as n,b as t,i as s,k as p}from"./chunk-PZNWH4VQ.js";import{a}from"./chunk-ZLLER3HP.js";import{hostname as l}from"node:os";async function R(f,r,h){t();let o=process.env.RULEMETRIC_API_KEY,d=n().apiKey;if(o||d)try{await y("/api/profile");return}catch(e){if(!(e instanceof c)||e.statusCode!==401)return;if(o){r('Your exported RULEMETRIC_API_KEY was rejected (revoked?). Unset it or replace it with a fresh key (`rulemetric auth create-key --name "my-laptop"`).');return}p(),t(),r("Stored API key was rejected (revoked?) \u2014 replacing it with a fresh one.")}let i=`${l()} (auto)`;try{let e=await m("/api/auth/api-keys",{name:i});s(e.key,process.env.RULEMETRIC_API_URL),t(),f(`Created API key "${i}" for hooks + proxy auth (saved to your config).`),u("key_created",{},h)}catch(e){let k=e instanceof Error?e.message:String(e);r(`Could not auto-create an API key (${k}). Hooks/proxy will work via your session token for ABOUT AN HOUR \u2014 the token expires, and capture then stops until a key exists. Run \`rulemetric auth create-key --name "my-laptop"\` (or \`rulemetric auth login\` again) to fix this permanently.`)}}a(R,"ensureDeviceApiKey");export{R as a};
@@ -1 +1 @@
1
- import{c as D}from"./chunk-HOQPVOMF.js";import{b as B}from"./chunk-GIRPEMTW.js";import{a as T}from"./chunk-MODXEGCU.js";import{d as U,f as J}from"./chunk-B3BHB26P.js";import{e as w,f as R}from"./chunk-QAV4HW7D.js";import{b as G,c as H}from"./chunk-3PUOJ6F2.js";import{a as u}from"./chunk-ZLLER3HP.js";import{readFileSync as Y,realpathSync as X}from"node:fs";import y from"node:path";import O from"node:os";function q(s){let o=y.resolve(s);if(o===y.resolve(O.homedir()))return!1;let a=y.parse(o).root;if(o===a)return!1;try{let n=X(O.tmpdir());if(X(o)===n)return!1}catch{}return!0}u(q,"isScorableProjectPath");var Q=5,Z=Number(process.env.RULEMETRIC_MAX_SUGGESTION_PROJECTS??10),tt=48,et=.5,x=400,ot=3,nt=.6,rt=1;function st(s){let o=s.bloated??[],a=new Set([...s.harmful.map(n=>n.id),...s.candidates.map(n=>n.id)]);return o.filter(n=>!a.has(n.id)).slice(0,rt).map(n=>({instructionId:n.id,estimatedTokens:n.estimatedTokens,topProjectId:n.topProjectId??null,score:.55,reason:`Costs ~${n.estimatedTokens} tokens every session and measures neutral across ${n.exposures} exposed session(s) \u2014 enough data to detect an effect, and none found. Consider shortening "${n.name}" rather than removing it.`+(n.containsSafetyLanguage?" CAUTION: it contains guardrail language (destructive-command or credential rules) \u2014 preserve those lines when shortening.":"")}))}u(st,"buildTrimProposals");async function at(s,o,a){let n=[],i=0;for(let d of s)try{await a("/api/instruction-experiments",{instructionId:d.instructionId,projectPath:o,source:"groom"}),i++}catch(g){let m=g instanceof Error?g.message:String(g);n.push({...d,reason:`${d.reason} (not measurable by withholding: ${m})`})}return{nominated:i,unmeasurable:n}}u(at,"nominateRemovals");function it(s){let o=[];for(let n of s.harmful){let i=n.verdict.delta;o.push({instructionId:n.id,score:Math.min(.95,.75+Math.abs(i)),topProjectId:n.topProjectId??null,reason:`Measured harmful: sessions using "${n.name}" scored ${(i*100).toFixed(1)}pp worse across ${n.exposures} exposed session(s). Observational \u2014 review before archiving.`})}let a=new Set(s.harmful.map(n=>n.id));for(let n of s.candidates)a.has(n.id)||o.push({instructionId:n.id,score:nt,topProjectId:n.topProjectId??null,reason:`Unused: "${n.name}" is ${n.reason} (${n.totalExposures} lifetime exposure(s)) but still costs context budget every session.`});return o.slice(0,ot)}u(it,"buildRemovalProposals");async function ct(){let s=y.join(O.homedir(),".config","rulemetric","skills-registry.json");try{let o=Y(s,"utf-8"),a=JSON.parse(o);return Date.now()-new Date(a.generatedAt).getTime()>tt*60*60*1e3}catch{return!0}}u(ct,"checkSkillsRegistryStale");var wt=u(async(s,o)=>{let a=U(),n=a!=="none";n?o.logger.info(`Scoring backend: ${a}`):o.logger.warn("No LLM backend available (claude CLI missing and ANTHROPIC_API_KEY unset); skipping relevance scoring. Removal/trim proposals still run \u2014 they need no LLM.");let i;try{i=(await w("/api/sessions/project-paths?limit="+Z)).projectPaths}catch(t){o.logger.warn(`Failed to fetch project paths: ${t instanceof Error?t.message:String(t)}`);return}if(i.length===0){o.logger.info("No recent project paths; nothing to score");return}let d=new Map;try{let t=await w("/api/projects?limit=200");for(let e of t.projects??[])e.primaryCheckoutPath&&d.set(T(e.primaryCheckoutPath),e.id)}catch(t){o.logger.warn(`Failed to fetch projects for id resolution: ${t instanceof Error?t.message:String(t)}`)}let g=new Map;try{let t=await w(`/api/catalog?limit=200&contentPreview=${x}`);for(let e of t)g.set(e.id,{id:e.id,name:e.name,description:e.description??"",tags:e.tags??[],contentPreview:(e.contentPreview??"").slice(0,x)})}catch(t){o.logger.warn(`Failed to fetch catalog: ${t instanceof Error?t.message:String(t)}`)}try{let t=await w("/api/instructions?limit=100");for(let e of t.instructions??[])g.has(e.id)||g.set(e.id,{id:e.id,name:e.name,description:e.description??"",tags:e.tags??[],contentPreview:(e.content??"").slice(0,x)})}catch(t){o.logger.warn(`Failed to fetch personal instructions: ${t instanceof Error?t.message:String(t)}`)}let m=[],p=[];try{let t=await w("/api/insights/groom-candidates");if(!t.captureHealthy)o.logger.info(`Grooming paused: ${t.reason??"capture unhealthy"}`);else{m=it(t),p=st(t);let e=t.safetyGuarded+t.harmfulSafetyGuarded;o.logger.info(`Removal proposals: ${m.length} (${t.harmful.length} measured-harmful, ${t.candidates.length} never-used, ${e} withheld by the safety allowlist); trim proposals: ${p.length} (${(t.bloated??[]).length} measured-neutral and expensive, ${t.trimSafetyFlagged??0} flagged as containing guardrail language)`)}}catch(t){o.logger.warn(`Failed to fetch groom candidates: ${t instanceof Error?t.message:String(t)}`)}let I=[...g.values()];if(I.length===0&&m.length===0&&p.length===0){o.logger.info("No candidate instructions and nothing to retire; nothing to score");return}o.logger.info(`Scoring ${I.length} candidates across ${i.length} project(s)`);let M=0,l=null,$=new Set;for(let t of i)try{let e=T(t);if(!q(e)){o.logger.info(`Skipping ${e}: not a project directory (home/root)`);continue}let f=B(e),S=n&&f.length>0;f.length===0&&o.logger.info(`${e}: insufficient language signals; removal/trim only`);let v=D(e),V={name:y.basename(e),description:v.description,languages:f,topics:v.topics,dependencies:v.dependencies},k=S?H(I):[];S&&o.logger.info(`Scoring ${I.length} candidates for ${e} in ${k.length} batch(es)`);let E=[],b=0;for(let r of k)try{let c=await J(G(V,r),"",4096);if(!c){b++;continue}let _=c.recommendations??[];for(let P of _)typeof P.instructionId=="string"&&typeof P.score=="number"&&typeof P.reason=="string"&&E.push({instructionId:P.instructionId,score:P.score,reason:P.reason})}catch(c){b++,o.logger.warn(`Batch failed for ${e}: ${c instanceof Error?c.message:String(c)}`)}b>0&&o.logger.warn(`${b}/${k.length} batch(es) failed for ${e} (backend ${a}); suggestions are partial`),S&&E.length===0&&o.logger.warn(`No usable LLM output for ${e} (backend ${a})`);let z=E.filter(r=>r.score>=et).sort((r,c)=>c.score-r.score).slice(0,Q),C=d.get(e),K=l===null||l===e;l===null&&(l=e);let A=u(r=>r.topProjectId?r.topProjectId===C:K,"placeHere"),L=m.filter(A),{nominated:N,unmeasurable:F}=await at(L,e,R);N>0&&o.logger.info(`${e}: ${N} removal candidate(s) nominated for randomised withholding instead of the feed`);let h=[...z.map(r=>({instructionId:r.instructionId,score:r.score,reason:r.reason,kind:"add"})),...F.map(({topProjectId:r,...c})=>({...c,kind:"remove"})),...p.filter(A).map(({estimatedTokens:r,topProjectId:c,..._})=>({..._,kind:"trim"}))];if(h.length===0){o.logger.info(`Nothing to suggest for ${e}`);continue}await R("/api/instruction-suggestions/batch-upsert",{projectPath:e,...C?{projectId:C}:{},suggestions:h}),o.logger.info(`${e}: ${h.filter(r=>r.kind==="add").length} add + ${h.filter(r=>r.kind==="remove").length} remove + ${h.filter(r=>r.kind==="trim").length} trim`);for(let r of h)r.kind!=="add"&&$.add(r.instructionId);let W=new Set(F.map(r=>r.instructionId));for(let r of L)W.has(r.instructionId)||$.add(r.instructionId);M++}catch(e){o.logger.warn(`Failed to score ${t}: ${e instanceof Error?e.message:String(e)}`)}let j=[...m.filter(t=>!$.has(t.instructionId)),...p.filter(t=>!$.has(t.instructionId)).map(({estimatedTokens:t,...e})=>e)];if(j.length>0&&l)try{let t=new Set(p.map(e=>e.instructionId));await R("/api/instruction-suggestions/batch-upsert",{projectPath:l,...d.get(l)?{projectId:d.get(l)}:{},suggestions:j.map(({topProjectId:e,...f})=>({...f,kind:t.has(f.instructionId)?"trim":"remove"}))}),o.logger.info(`Orphan sweep: ${j.length} proposal(s) whose project was not scored this run placed on ${l}`)}catch(t){o.logger.warn(`Orphan sweep failed: ${t instanceof Error?t.message:String(t)}`)}if(await ct())try{await R("/api/instruction-suggestions/mark-stale",{}),o.logger.warn("Skills registry is stale (>48h); marked all suggestions stale")}catch{}o.logger.info(`Done: scored ${M}/${i.length} projects`)},"cronSuggestInstructions");export{q as a,st as b,at as c,it as d,wt as e};
1
+ import{c as D}from"./chunk-HOQPVOMF.js";import{b as B}from"./chunk-GIRPEMTW.js";import{a as T}from"./chunk-MODXEGCU.js";import{d as U,f as J}from"./chunk-B3BHB26P.js";import{e as w,f as R}from"./chunk-MPDSQALK.js";import{b as G,c as H}from"./chunk-E4U6AOTM.js";import{a as u}from"./chunk-ZLLER3HP.js";import{readFileSync as Y,realpathSync as X}from"node:fs";import y from"node:path";import O from"node:os";function q(s){let o=y.resolve(s);if(o===y.resolve(O.homedir()))return!1;let a=y.parse(o).root;if(o===a)return!1;try{let n=X(O.tmpdir());if(X(o)===n)return!1}catch{}return!0}u(q,"isScorableProjectPath");var Q=5,Z=Number(process.env.RULEMETRIC_MAX_SUGGESTION_PROJECTS??10),tt=48,et=.5,x=400,ot=3,nt=.6,rt=1;function st(s){let o=s.bloated??[],a=new Set([...s.harmful.map(n=>n.id),...s.candidates.map(n=>n.id)]);return o.filter(n=>!a.has(n.id)).slice(0,rt).map(n=>({instructionId:n.id,estimatedTokens:n.estimatedTokens,topProjectId:n.topProjectId??null,score:.55,reason:`Costs ~${n.estimatedTokens} tokens every session and measures neutral across ${n.exposures} exposed session(s) \u2014 enough data to detect an effect, and none found. Consider shortening "${n.name}" rather than removing it.`+(n.containsSafetyLanguage?" CAUTION: it contains guardrail language (destructive-command or credential rules) \u2014 preserve those lines when shortening.":"")}))}u(st,"buildTrimProposals");async function at(s,o,a){let n=[],i=0;for(let d of s)try{await a("/api/instruction-experiments",{instructionId:d.instructionId,projectPath:o,source:"groom"}),i++}catch(g){let m=g instanceof Error?g.message:String(g);n.push({...d,reason:`${d.reason} (not measurable by withholding: ${m})`})}return{nominated:i,unmeasurable:n}}u(at,"nominateRemovals");function it(s){let o=[];for(let n of s.harmful){let i=n.verdict.delta;o.push({instructionId:n.id,score:Math.min(.95,.75+Math.abs(i)),topProjectId:n.topProjectId??null,reason:`Measured harmful: sessions using "${n.name}" scored ${(i*100).toFixed(1)}pp worse across ${n.exposures} exposed session(s). Observational \u2014 review before archiving.`})}let a=new Set(s.harmful.map(n=>n.id));for(let n of s.candidates)a.has(n.id)||o.push({instructionId:n.id,score:nt,topProjectId:n.topProjectId??null,reason:`Unused: "${n.name}" is ${n.reason} (${n.totalExposures} lifetime exposure(s)) but still costs context budget every session.`});return o.slice(0,ot)}u(it,"buildRemovalProposals");async function ct(){let s=y.join(O.homedir(),".config","rulemetric","skills-registry.json");try{let o=Y(s,"utf-8"),a=JSON.parse(o);return Date.now()-new Date(a.generatedAt).getTime()>tt*60*60*1e3}catch{return!0}}u(ct,"checkSkillsRegistryStale");var wt=u(async(s,o)=>{let a=U(),n=a!=="none";n?o.logger.info(`Scoring backend: ${a}`):o.logger.warn("No LLM backend available (claude CLI missing and ANTHROPIC_API_KEY unset); skipping relevance scoring. Removal/trim proposals still run \u2014 they need no LLM.");let i;try{i=(await w("/api/sessions/project-paths?limit="+Z)).projectPaths}catch(t){o.logger.warn(`Failed to fetch project paths: ${t instanceof Error?t.message:String(t)}`);return}if(i.length===0){o.logger.info("No recent project paths; nothing to score");return}let d=new Map;try{let t=await w("/api/projects?limit=200");for(let e of t.projects??[])e.primaryCheckoutPath&&d.set(T(e.primaryCheckoutPath),e.id)}catch(t){o.logger.warn(`Failed to fetch projects for id resolution: ${t instanceof Error?t.message:String(t)}`)}let g=new Map;try{let t=await w(`/api/catalog?limit=200&contentPreview=${x}`);for(let e of t)g.set(e.id,{id:e.id,name:e.name,description:e.description??"",tags:e.tags??[],contentPreview:(e.contentPreview??"").slice(0,x)})}catch(t){o.logger.warn(`Failed to fetch catalog: ${t instanceof Error?t.message:String(t)}`)}try{let t=await w("/api/instructions?limit=100");for(let e of t.instructions??[])g.has(e.id)||g.set(e.id,{id:e.id,name:e.name,description:e.description??"",tags:e.tags??[],contentPreview:(e.content??"").slice(0,x)})}catch(t){o.logger.warn(`Failed to fetch personal instructions: ${t instanceof Error?t.message:String(t)}`)}let m=[],p=[];try{let t=await w("/api/insights/groom-candidates");if(!t.captureHealthy)o.logger.info(`Grooming paused: ${t.reason??"capture unhealthy"}`);else{m=it(t),p=st(t);let e=t.safetyGuarded+t.harmfulSafetyGuarded;o.logger.info(`Removal proposals: ${m.length} (${t.harmful.length} measured-harmful, ${t.candidates.length} never-used, ${e} withheld by the safety allowlist); trim proposals: ${p.length} (${(t.bloated??[]).length} measured-neutral and expensive, ${t.trimSafetyFlagged??0} flagged as containing guardrail language)`)}}catch(t){o.logger.warn(`Failed to fetch groom candidates: ${t instanceof Error?t.message:String(t)}`)}let I=[...g.values()];if(I.length===0&&m.length===0&&p.length===0){o.logger.info("No candidate instructions and nothing to retire; nothing to score");return}o.logger.info(`Scoring ${I.length} candidates across ${i.length} project(s)`);let M=0,l=null,$=new Set;for(let t of i)try{let e=T(t);if(!q(e)){o.logger.info(`Skipping ${e}: not a project directory (home/root)`);continue}let f=B(e),S=n&&f.length>0;f.length===0&&o.logger.info(`${e}: insufficient language signals; removal/trim only`);let v=D(e),V={name:y.basename(e),description:v.description,languages:f,topics:v.topics,dependencies:v.dependencies},k=S?H(I):[];S&&o.logger.info(`Scoring ${I.length} candidates for ${e} in ${k.length} batch(es)`);let E=[],b=0;for(let r of k)try{let c=await J(G(V,r),"",4096);if(!c){b++;continue}let _=c.recommendations??[];for(let P of _)typeof P.instructionId=="string"&&typeof P.score=="number"&&typeof P.reason=="string"&&E.push({instructionId:P.instructionId,score:P.score,reason:P.reason})}catch(c){b++,o.logger.warn(`Batch failed for ${e}: ${c instanceof Error?c.message:String(c)}`)}b>0&&o.logger.warn(`${b}/${k.length} batch(es) failed for ${e} (backend ${a}); suggestions are partial`),S&&E.length===0&&o.logger.warn(`No usable LLM output for ${e} (backend ${a})`);let z=E.filter(r=>r.score>=et).sort((r,c)=>c.score-r.score).slice(0,Q),C=d.get(e),K=l===null||l===e;l===null&&(l=e);let A=u(r=>r.topProjectId?r.topProjectId===C:K,"placeHere"),L=m.filter(A),{nominated:N,unmeasurable:F}=await at(L,e,R);N>0&&o.logger.info(`${e}: ${N} removal candidate(s) nominated for randomised withholding instead of the feed`);let h=[...z.map(r=>({instructionId:r.instructionId,score:r.score,reason:r.reason,kind:"add"})),...F.map(({topProjectId:r,...c})=>({...c,kind:"remove"})),...p.filter(A).map(({estimatedTokens:r,topProjectId:c,..._})=>({..._,kind:"trim"}))];if(h.length===0){o.logger.info(`Nothing to suggest for ${e}`);continue}await R("/api/instruction-suggestions/batch-upsert",{projectPath:e,...C?{projectId:C}:{},suggestions:h}),o.logger.info(`${e}: ${h.filter(r=>r.kind==="add").length} add + ${h.filter(r=>r.kind==="remove").length} remove + ${h.filter(r=>r.kind==="trim").length} trim`);for(let r of h)r.kind!=="add"&&$.add(r.instructionId);let W=new Set(F.map(r=>r.instructionId));for(let r of L)W.has(r.instructionId)||$.add(r.instructionId);M++}catch(e){o.logger.warn(`Failed to score ${t}: ${e instanceof Error?e.message:String(e)}`)}let j=[...m.filter(t=>!$.has(t.instructionId)),...p.filter(t=>!$.has(t.instructionId)).map(({estimatedTokens:t,...e})=>e)];if(j.length>0&&l)try{let t=new Set(p.map(e=>e.instructionId));await R("/api/instruction-suggestions/batch-upsert",{projectPath:l,...d.get(l)?{projectId:d.get(l)}:{},suggestions:j.map(({topProjectId:e,...f})=>({...f,kind:t.has(f.instructionId)?"trim":"remove"}))}),o.logger.info(`Orphan sweep: ${j.length} proposal(s) whose project was not scored this run placed on ${l}`)}catch(t){o.logger.warn(`Orphan sweep failed: ${t instanceof Error?t.message:String(t)}`)}if(await ct())try{await R("/api/instruction-suggestions/mark-stale",{}),o.logger.warn("Skills registry is stale (>48h); marked all suggestions stale")}catch{}o.logger.info(`Done: scored ${M}/${i.length} projects`)},"cronSuggestInstructions");export{q as a,st as b,at as c,it as d,wt as e};
@@ -1 +1 @@
1
- import{c as l}from"./chunk-QAV4HW7D.js";import{c as a,l as u}from"./chunk-JZ5Z2BRO.js";import{a as o}from"./chunk-ZLLER3HP.js";var c=120*1e3,t=null;async function k(){if(process.env.RULEMETRIC_API_KEY)return!0;let e=a(u());if(!e.isRefreshable(c))return!0;let r=e.loadToken();return r?.refreshToken?t||(t=f(e,r).finally(()=>{t=null}),t):!0}o(k,"ensureFreshToken");async function f(e,r){let s;try{s=await fetch(`${l()}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:r.refreshToken})})}catch{return!0}if(s.status===401)return e.clearToken(),!1;if(!s.ok)return!0;let n=await s.json().catch(()=>null);if(!n?.accessToken||!n.refreshToken)return!0;let i={accessToken:n.accessToken,refreshToken:n.refreshToken,expiresAt:n.expiresAt??r.expiresAt,email:n.email??r.email};return e.saveToken(i),e.saveEnvFile(i.accessToken),!0}o(f,"doRefresh");export{k as a};
1
+ import{c as l}from"./chunk-MPDSQALK.js";import{c as a,l as u}from"./chunk-PZNWH4VQ.js";import{a as o}from"./chunk-ZLLER3HP.js";var c=120*1e3,t=null;async function k(){if(process.env.RULEMETRIC_API_KEY)return!0;let e=a(u());if(!e.isRefreshable(c))return!0;let r=e.loadToken();return r?.refreshToken?t||(t=f(e,r).finally(()=>{t=null}),t):!0}o(k,"ensureFreshToken");async function f(e,r){let s;try{s=await fetch(`${l()}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:r.refreshToken})})}catch{return!0}if(s.status===401)return e.clearToken(),!1;if(!s.ok)return!0;let n=await s.json().catch(()=>null);if(!n?.accessToken||!n.refreshToken)return!0;let i={accessToken:n.accessToken,refreshToken:n.refreshToken,expiresAt:n.expiresAt??r.expiresAt,email:n.email??r.email};return e.saveToken(i),e.saveEnvFile(i.accessToken),!0}o(f,"doRefresh");export{k as a};
@@ -1,4 +1,4 @@
1
- import{a as C}from"./chunk-AFYZYXQ3.js";import{b as $}from"./chunk-CNOD6HWU.js";import{a as y}from"./chunk-JPUH3V67.js";import{d as f}from"./chunk-TZA4HAVF.js";import{e as h,f as w}from"./chunk-QAV4HW7D.js";import{a as v}from"./chunk-ZLLER3HP.js";async function N(n,i,p){let{conversationId:a,messageId:g,messageContent:r}=n,o=await h(`/api/eval-targets/${i}`),c=await h(`/api/eval-targets/${i}/evals`),e=await h(`/api/eval-conversations/${a}/messages`),t=e.findIndex(l=>l.id===g);if(t>=0&&e.slice(t+1).some(u=>u.role==="assistant"&&(u.type==="results"||u.type==="proposal"||u.type==="generated"||u.type==="text"))){p(`Message ${g} already processed \u2014 skipping (idempotency guard)`);return}let s=v(async(l,u,m)=>{await w(`/api/eval-conversations/${a}/messages/assistant`,{content:l,type:u,data:m})},"postMessage"),d=await _(o,c,e,r,p);p(`Action: ${d.action}`);try{switch(d.action){case"run_evals":await x(o,c,a,s,p);break;case"generate_cases":await k(o,i,a,s,p);break;case"analyze_results":case"propose_changes":await E(o,c,e,r,a,s,p);break;case"respond":await s(d.response,"text");break}}catch(l){let u=l instanceof Error?l.message:String(l);throw await s(`Something went wrong: ${u}`,"text").catch(()=>{}),l}}v(N,"processConversationJob");async function _(n,i,p,a,g){let r=p.slice(-10).map(e=>`${e.role}: ${e.content.slice(0,200)}`).join(`
1
+ import{b as $}from"./chunk-CNOD6HWU.js";import{a as C}from"./chunk-AFYZYXQ3.js";import{a as y}from"./chunk-JPUH3V67.js";import{d as f}from"./chunk-TZA4HAVF.js";import{e as h,f as w}from"./chunk-MPDSQALK.js";import{a as v}from"./chunk-ZLLER3HP.js";async function N(n,i,p){let{conversationId:a,messageId:g,messageContent:r}=n,o=await h(`/api/eval-targets/${i}`),c=await h(`/api/eval-targets/${i}/evals`),e=await h(`/api/eval-conversations/${a}/messages`),t=e.findIndex(l=>l.id===g);if(t>=0&&e.slice(t+1).some(u=>u.role==="assistant"&&(u.type==="results"||u.type==="proposal"||u.type==="generated"||u.type==="text"))){p(`Message ${g} already processed \u2014 skipping (idempotency guard)`);return}let s=v(async(l,u,m)=>{await w(`/api/eval-conversations/${a}/messages/assistant`,{content:l,type:u,data:m})},"postMessage"),d=await _(o,c,e,r,p);p(`Action: ${d.action}`);try{switch(d.action){case"run_evals":await x(o,c,a,s,p);break;case"generate_cases":await k(o,i,a,s,p);break;case"analyze_results":case"propose_changes":await E(o,c,e,r,a,s,p);break;case"respond":await s(d.response,"text");break}}catch(l){let u=l instanceof Error?l.message:String(l);throw await s(`Something went wrong: ${u}`,"text").catch(()=>{}),l}}v(N,"processConversationJob");async function _(n,i,p,a,g){let r=p.slice(-10).map(e=>`${e.role}: ${e.content.slice(0,200)}`).join(`
2
2
  `),o=`You are an eval assistant. Decide what action to take based on the user's message.
3
3
 
4
4
  ## Current State
@@ -1,4 +1,4 @@
1
- import{f as E}from"./chunk-B3BHB26P.js";import{b,e as y,f as k,h as M}from"./chunk-QAV4HW7D.js";import{a as u}from"./chunk-ZLLER3HP.js";var v=50,I=24e3,P=3,R=3,C=40,N=4e3,x=new Set(["fact","decision","correction","convention"]),L=`You are distilling DURABLE, PROJECT-SPECIFIC knowledge from an AI coding session so a future agent working on the SAME project starts smarter.
1
+ import{f as E}from"./chunk-B3BHB26P.js";import{b,e as y,f as k,h as M}from"./chunk-MPDSQALK.js";import{a as u}from"./chunk-ZLLER3HP.js";var v=50,I=24e3,P=3,R=3,C=40,N=4e3,x=new Set(["fact","decision","correction","convention"]),L=`You are distilling DURABLE, PROJECT-SPECIFIC knowledge from an AI coding session so a future agent working on the SAME project starts smarter.
2
2
 
3
3
  Extract ONLY facts / decisions / corrections / conventions that will STILL be true and useful in FUTURE sessions \u2014 architecture facts, deliberate design decisions, corrections of a wrong approach, or project conventions.
4
4
 
@@ -1 +1 @@
1
- import{a as i}from"./chunk-E2NVNLFD.js";import{h as s}from"./chunk-QAV4HW7D.js";import{a as n}from"./chunk-ZLLER3HP.js";async function l(a,c){let{mirrorId:g,evalTargetId:p,config:r}=a,e=n(o=>c.logger.info(o),"log");await i(r,p,e);let t={type:"conversation",conversationId:r.conversationId};return await s(`/api/eval-jobs/${g}/state`,{result:t}).catch(o=>{e(`result persist failed: ${o instanceof Error?o.message:String(o)}`)}),t}n(l,"processConversation");export{l as a};
1
+ import{a as i}from"./chunk-RS4LSJI2.js";import{h as s}from"./chunk-MPDSQALK.js";import{a as n}from"./chunk-ZLLER3HP.js";async function l(a,c){let{mirrorId:g,evalTargetId:p,config:r}=a,e=n(o=>c.logger.info(o),"log");await i(r,p,e);let t={type:"conversation",conversationId:r.conversationId};return await s(`/api/eval-jobs/${g}/state`,{result:t}).catch(o=>{e(`result persist failed: ${o instanceof Error?o.message:String(o)}`)}),t}n(l,"processConversation");export{l as a};
@@ -1 +1 @@
1
- import{b as D,c as j}from"./chunk-6UEFCMR2.js";import{b as B,c as R,d as N,e as z}from"./chunk-NTKO4H2K.js";import{a as G}from"./chunk-JPUH3V67.js";import{c as J}from"./chunk-XRTZU7IZ.js";import{e as f,g as T}from"./chunk-QAV4HW7D.js";import{a as p}from"./chunk-ZLLER3HP.js";function W(r,a,s){return s?r.reviewerModel===s||r.reviewerModel===`${a}:${s}`:r.reviewerEngine===a}p(W,"reviewMatchesReviewer");var C=100;function Z(r){let a=new Set;return r.forEach((s,d)=>{s.method!=="deterministic"&&a.add(d)}),a}p(Z,"llmExpectationIndexes");var w=class extends Error{constructor(s,d){super(d);this.reason=s}static{p(this,"JudgeReviewSkip")}};async function oe(r){let a=r.log??(()=>{}),s=r.warn??a,d=r.targetId,K=r.parallel??3,U=r.timeoutMs??12e4,v=await f(`/api/eval-targets/${d}`),u=(await f(`/api/eval-targets/${d}/annotations?limit=500`)).filter(e=>e.judgeMethod==="llm");if(u.length===0)throw new w("no-labels",`No human labels on "${v.name}" yet \u2014 label some runs in the Review tab first.`);let n;try{n=z({engineFlag:r.engineFlag??"auto",modelFlag:r.modelFlag,availability:N(),judgeModels:[...new Set(u.map(e=>e.judgeModel).filter(e=>e!=null))]})}catch(e){throw new w("no-engine",e instanceof Error?e.message:String(e))}a(`Reviewer: ${n.rationale}`);let c=0,b=u;if(r.skipReviewed){let e=await f(`/api/eval-targets/${d}/judge-reviews`),t=new Set(e.filter(i=>W(i,n.engine,r.modelFlag)).map(i=>`${i.evalRunId}:${i.expectationIndex}`));if(b=u.filter(i=>!t.has(`${i.evalRunId}:${i.expectationIndex}`)),c=u.length-b.length,b.length===0)return{targetName:v.name,reviewer:n,judgeModels:[],reviewerModel:n.model??`${n.engine} (CLI default)`,report:j([],0),persisted:0,alreadyReviewed:c,deferredPartialRuns:0}}let y=new Map;for(let e=0;;e+=C){let t=await f(`/api/eval-targets/${d}/runs?limit=${C}&offset=${e}`);for(let i of t)y.set(i.id,i);if(t.length<C)break}let q=await f(`/api/eval-targets/${d}/evals`),X=new Map(q.map(e=>[e.id,e.prompt])),o=new Map;for(let e of b){let t=o.get(e.evalRunId)??[];t.push(e),o.set(e.evalRunId,t)}let P=new Map;for(let e of u){let t=P.get(e.evalRunId)??new Set;t.add(e.expectationIndex),P.set(e.evalRunId,t)}let x=0;for(let[e]of[...o]){let t=y.get(e)?.grading?.expectations;if(!t)continue;let i=Z(t),g=P.get(e)??new Set;[...i].every(h=>g.has(h))||(o.delete(e),x+=1)}if(x>0&&a(`${x} partially-labeled run(s) deferred \u2014 a run is re-graded once, after all its assertions are labeled.`),o.size===0)return{targetName:v.name,reviewer:n,judgeModels:[],reviewerModel:n.model??`${n.engine} (CLI default)`,report:j([],0),persisted:0,alreadyReviewed:c,deferredPartialRuns:x};if(n.engine==="codex"&&n.model){let e=await J({prompt:"Reply with exactly: OK",model:n.model,timeout:6e4});if(e.error&&B(e.error)){if(n.model===R)throw new w("preflight-failed",`Codex fallback model ${R} is also unrunnable: ${e.error}`);s(`Your codex model "${n.model}" can't run on the installed CLI/account \u2014 falling back to ${R}.`),n={...n,model:R}}else if(e.error)throw new w("preflight-failed",`Codex preflight failed: ${e.error}`)}let S=[...o.values()].flat(),Y=[...new Set(S.map(e=>e.judgeModel).filter(e=>e!=null))];a(`Re-grading ${o.size} annotated run(s) / ${S.length} assertion(s) on "${v.name}"`+(c?` (${c} already reviewed \u2014 skipped)`:"")+".");let $=[],I=0,k=new Set,m=r.limit!=null?[...o.entries()].slice(0,Math.max(1,r.limit)):[...o.entries()];m.length<o.size&&a(`Sampling ${m.length} of ${o.size} annotated runs (limit).`);let H=0,Q=p(async()=>{for(;;){let e=H++;if(e>=m.length)return;let[t,i]=m[e],g=y.get(t),h=g?.grading?.expectations,O=g?.outputs?.transcript,F=g?X.get(g.evalId):void 0;if(!g||!h?.length||!O||!F){I+=i.length,s(`run ${t.slice(0,8)}: missing output/expectations/prompt \u2014 skipped`);continue}let M=await G({prompt:F,output:O,expectations:h.map(l=>l.text),model:n.model??void 0,timeout:U,engine:n.engine});M.judge_model&&k.add(M.judge_model);for(let l of i){let L=h[l.expectationIndex],A=M.expectations[l.expectationIndex];if(!L||!A||L.text!==l.expectationText){I+=1;continue}if(M.judge_model==null&&A.method==="llm"){I+=1;continue}$.push({runId:t,expectationIndex:l.expectationIndex,text:l.expectationText,humanPassed:D(l.verdict,l.judgePassed),judgeAPassed:l.judgePassed,judgeBPassed:A.passed})}a(` ${e+1}/${m.length} re-graded`)}},"workerFn");await Promise.all(Array.from({length:Math.max(1,Math.min(K,m.length))},Q));let V=j($,I),_=[...k][0]??n.model??`${n.engine} (CLI default)`,E=0;if($.length>0)try{E=(await T(`/api/eval-targets/${d}/judge-reviews`,{reviewerEngine:n.engine,reviewerModel:_,verdicts:$.map(t=>({evalRunId:t.runId,expectationIndex:t.expectationIndex,expectationText:t.text,judgePassed:t.judgeAPassed,humanPassed:t.humanPassed,reviewerPassed:t.judgeBPassed}))})).upserted,a(`Persisted ${E} reviewer verdict(s) \u2014 disagreements appear on the Review tab.`)}catch(e){s(`Could not persist reviewer verdicts: ${e instanceof Error?e.message:e}`)}return{targetName:v.name,reviewer:n,judgeModels:Y,reviewerModel:_,report:V,persisted:E,alreadyReviewed:c,deferredPartialRuns:x}}p(oe,"runJudgeReviewPass");export{W as a,Z as b,w as c,oe as d};
1
+ import{b as D,c as j}from"./chunk-6UEFCMR2.js";import{b as B,c as R,d as N,e as z}from"./chunk-NTKO4H2K.js";import{a as G}from"./chunk-JPUH3V67.js";import{c as J}from"./chunk-XRTZU7IZ.js";import{e as f,g as T}from"./chunk-MPDSQALK.js";import{a as p}from"./chunk-ZLLER3HP.js";function W(r,a,s){return s?r.reviewerModel===s||r.reviewerModel===`${a}:${s}`:r.reviewerEngine===a}p(W,"reviewMatchesReviewer");var C=100;function Z(r){let a=new Set;return r.forEach((s,d)=>{s.method!=="deterministic"&&a.add(d)}),a}p(Z,"llmExpectationIndexes");var w=class extends Error{constructor(s,d){super(d);this.reason=s}static{p(this,"JudgeReviewSkip")}};async function oe(r){let a=r.log??(()=>{}),s=r.warn??a,d=r.targetId,K=r.parallel??3,U=r.timeoutMs??12e4,v=await f(`/api/eval-targets/${d}`),u=(await f(`/api/eval-targets/${d}/annotations?limit=500`)).filter(e=>e.judgeMethod==="llm");if(u.length===0)throw new w("no-labels",`No human labels on "${v.name}" yet \u2014 label some runs in the Review tab first.`);let n;try{n=z({engineFlag:r.engineFlag??"auto",modelFlag:r.modelFlag,availability:N(),judgeModels:[...new Set(u.map(e=>e.judgeModel).filter(e=>e!=null))]})}catch(e){throw new w("no-engine",e instanceof Error?e.message:String(e))}a(`Reviewer: ${n.rationale}`);let c=0,b=u;if(r.skipReviewed){let e=await f(`/api/eval-targets/${d}/judge-reviews`),t=new Set(e.filter(i=>W(i,n.engine,r.modelFlag)).map(i=>`${i.evalRunId}:${i.expectationIndex}`));if(b=u.filter(i=>!t.has(`${i.evalRunId}:${i.expectationIndex}`)),c=u.length-b.length,b.length===0)return{targetName:v.name,reviewer:n,judgeModels:[],reviewerModel:n.model??`${n.engine} (CLI default)`,report:j([],0),persisted:0,alreadyReviewed:c,deferredPartialRuns:0}}let y=new Map;for(let e=0;;e+=C){let t=await f(`/api/eval-targets/${d}/runs?limit=${C}&offset=${e}`);for(let i of t)y.set(i.id,i);if(t.length<C)break}let q=await f(`/api/eval-targets/${d}/evals`),X=new Map(q.map(e=>[e.id,e.prompt])),o=new Map;for(let e of b){let t=o.get(e.evalRunId)??[];t.push(e),o.set(e.evalRunId,t)}let P=new Map;for(let e of u){let t=P.get(e.evalRunId)??new Set;t.add(e.expectationIndex),P.set(e.evalRunId,t)}let x=0;for(let[e]of[...o]){let t=y.get(e)?.grading?.expectations;if(!t)continue;let i=Z(t),g=P.get(e)??new Set;[...i].every(h=>g.has(h))||(o.delete(e),x+=1)}if(x>0&&a(`${x} partially-labeled run(s) deferred \u2014 a run is re-graded once, after all its assertions are labeled.`),o.size===0)return{targetName:v.name,reviewer:n,judgeModels:[],reviewerModel:n.model??`${n.engine} (CLI default)`,report:j([],0),persisted:0,alreadyReviewed:c,deferredPartialRuns:x};if(n.engine==="codex"&&n.model){let e=await J({prompt:"Reply with exactly: OK",model:n.model,timeout:6e4});if(e.error&&B(e.error)){if(n.model===R)throw new w("preflight-failed",`Codex fallback model ${R} is also unrunnable: ${e.error}`);s(`Your codex model "${n.model}" can't run on the installed CLI/account \u2014 falling back to ${R}.`),n={...n,model:R}}else if(e.error)throw new w("preflight-failed",`Codex preflight failed: ${e.error}`)}let S=[...o.values()].flat(),Y=[...new Set(S.map(e=>e.judgeModel).filter(e=>e!=null))];a(`Re-grading ${o.size} annotated run(s) / ${S.length} assertion(s) on "${v.name}"`+(c?` (${c} already reviewed \u2014 skipped)`:"")+".");let $=[],I=0,k=new Set,m=r.limit!=null?[...o.entries()].slice(0,Math.max(1,r.limit)):[...o.entries()];m.length<o.size&&a(`Sampling ${m.length} of ${o.size} annotated runs (limit).`);let H=0,Q=p(async()=>{for(;;){let e=H++;if(e>=m.length)return;let[t,i]=m[e],g=y.get(t),h=g?.grading?.expectations,O=g?.outputs?.transcript,F=g?X.get(g.evalId):void 0;if(!g||!h?.length||!O||!F){I+=i.length,s(`run ${t.slice(0,8)}: missing output/expectations/prompt \u2014 skipped`);continue}let M=await G({prompt:F,output:O,expectations:h.map(l=>l.text),model:n.model??void 0,timeout:U,engine:n.engine});M.judge_model&&k.add(M.judge_model);for(let l of i){let L=h[l.expectationIndex],A=M.expectations[l.expectationIndex];if(!L||!A||L.text!==l.expectationText){I+=1;continue}if(M.judge_model==null&&A.method==="llm"){I+=1;continue}$.push({runId:t,expectationIndex:l.expectationIndex,text:l.expectationText,humanPassed:D(l.verdict,l.judgePassed),judgeAPassed:l.judgePassed,judgeBPassed:A.passed})}a(` ${e+1}/${m.length} re-graded`)}},"workerFn");await Promise.all(Array.from({length:Math.max(1,Math.min(K,m.length))},Q));let V=j($,I),_=[...k][0]??n.model??`${n.engine} (CLI default)`,E=0;if($.length>0)try{E=(await T(`/api/eval-targets/${d}/judge-reviews`,{reviewerEngine:n.engine,reviewerModel:_,verdicts:$.map(t=>({evalRunId:t.runId,expectationIndex:t.expectationIndex,expectationText:t.text,judgePassed:t.judgeAPassed,humanPassed:t.humanPassed,reviewerPassed:t.judgeBPassed}))})).upserted,a(`Persisted ${E} reviewer verdict(s) \u2014 disagreements appear on the Review tab.`)}catch(e){s(`Could not persist reviewer verdicts: ${e instanceof Error?e.message:e}`)}return{targetName:v.name,reviewer:n,judgeModels:Y,reviewerModel:_,report:V,persisted:E,alreadyReviewed:c,deferredPartialRuns:x}}p(oe,"runJudgeReviewPass");export{W as a,Z as b,w as c,oe as d};
@@ -1 +1 @@
1
- import{a as s,b as n,c as a,d as g}from"./chunk-3AV3GTMP.js";import{e as o}from"./chunk-QAV4HW7D.js";import{a as e}from"./chunk-ZLLER3HP.js";var i=!1;async function c(){if(process.env.RULEMETRIC_ORG_ID)return;let r=s();if(!(r&&!g(r)))try{let t=await o("/api/profile");if(!t.activeOrgId){a();return}if(r&&t.activeOrgId===r.orgId){n({orgId:r.orgId,orgSlug:r.orgSlug,syncedAt:Date.now()});return}let d=(await o("/api/orgs")).find(l=>l.id===t.activeOrgId);n({orgId:t.activeOrgId,orgSlug:d?.slug,syncedAt:Date.now()})}catch{}}e(c,"syncActiveOrgFromServer");async function p(){i||(i=!0,await c())}e(p,"maybeRefreshActiveOrg");async function v(){i=!0,await c()}e(v,"bootstrapActiveOrg");function O(){i=!1}e(O,"_resetRefreshAttempt");export{p as a,v as b,O as c};
1
+ import{a as s,b as n,c as a,d as g}from"./chunk-3AV3GTMP.js";import{e as o}from"./chunk-MPDSQALK.js";import{a as e}from"./chunk-ZLLER3HP.js";var i=!1;async function c(){if(process.env.RULEMETRIC_ORG_ID)return;let r=s();if(!(r&&!g(r)))try{let t=await o("/api/profile");if(!t.activeOrgId){a();return}if(r&&t.activeOrgId===r.orgId){n({orgId:r.orgId,orgSlug:r.orgSlug,syncedAt:Date.now()});return}let d=(await o("/api/orgs")).find(l=>l.id===t.activeOrgId);n({orgId:t.activeOrgId,orgSlug:d?.slug,syncedAt:Date.now()})}catch{}}e(c,"syncActiveOrgFromServer");async function p(){i||(i=!0,await c())}e(p,"maybeRefreshActiveOrg");async function v(){i=!0,await c()}e(v,"bootstrapActiveOrg");function O(){i=!1}e(O,"_resetRefreshAttempt");export{p as a,v as b,O as c};
@@ -1 +1 @@
1
- import{b as T}from"./chunk-ZXF5NE54.js";import{d as l,e as s,h as E}from"./chunk-NJ5UED3H.js";import{a as g}from"./chunk-ZLLER3HP.js";import{useState as a}from"react";import{Box as c,Text as r,useInput as _}from"ink";import L from"ink-text-input";import G from"ink-select-input";import{jsx as t,jsxs as m}from"react/jsx-runtime";var p=["tool","project","mode","prompt","submit"];function U({launchers:f,defaultProjectPath:w,defaultTool:A,defaultPrompt:D,defaultResumeSessionId:v,focused:i,onSubmit:R}){let[b,C]=a(A??f[0]?.tool??"claude_code"),[u,M]=a(w),[P,O]=a("interactive"),[d,S]=a(D??""),[o,F]=a("tool"),[j,I]=a(!1),[y,h]=a(null),B=d.trim().length>0&&u.trim().length>0&&!j;_((e,x)=>{if(i)if(x.upArrow){let n=p.indexOf(o);n>0&&F(p[n-1])}else if(x.downArrow){let n=p.indexOf(o);n<p.length-1&&F(p[n+1])}else x.return&&o==="submit"&&B?N():o==="mode"&&(e===" "||x.return)&&O(n=>n==="interactive"?"headless":"interactive")});async function N(){I(!0),h(null);try{await R({tool:b,config:{projectPath:u,prompt:d,mode:P,...v?{resumeSessionId:v}:{}}}),S(""),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}finally{I(!1)}}return g(N,"doSubmit"),m(c,{flexDirection:"column",paddingX:1,children:[t(r,{bold:!0,color:l,children:"\u25BC New launch"}),m(c,{children:[t(r,{color:o==="tool"&&i?l:s,children:" Tool: "}),o==="tool"&&i?t(G,{items:f.map(e=>({label:T(e.tool),value:e.tool})),initialIndex:Math.max(0,f.findIndex(e=>e.tool===b)),onSelect:e=>C(e.value)}):t(r,{children:T(b)})]}),m(c,{children:[t(r,{color:o==="project"&&i?l:s,children:" Project: "}),o==="project"&&i?t(L,{value:u,onChange:M}):t(r,{children:u})]}),m(c,{children:[t(r,{color:o==="mode"&&i?l:s,children:" Mode: "}),t(r,{children:P==="interactive"?"(\u2022) interactive ( ) headless":"( ) interactive (\u2022) headless"})]}),m(c,{children:[t(r,{color:o==="prompt"&&i?l:s,children:" Prompt: "}),o==="prompt"&&i?t(L,{value:d,onChange:S}):t(r,{children:d||"(empty)"})]}),t(c,{marginTop:1,children:m(r,{color:o==="submit"&&i?l:s,children:[B?" [ Submit ]":" [ Submit (disabled) ]",j?" \u2026submitting":""]})}),y&&m(r,{color:E,children:[" \u2717 ",y]})]})}g(U,"NewLaunchForm");export{U as a};
1
+ import{d as l,e as s,h as E}from"./chunk-NJ5UED3H.js";import{b as T}from"./chunk-ZXF5NE54.js";import{a as g}from"./chunk-ZLLER3HP.js";import{useState as a}from"react";import{Box as c,Text as r,useInput as _}from"ink";import L from"ink-text-input";import G from"ink-select-input";import{jsx as t,jsxs as m}from"react/jsx-runtime";var p=["tool","project","mode","prompt","submit"];function U({launchers:f,defaultProjectPath:w,defaultTool:A,defaultPrompt:D,defaultResumeSessionId:v,focused:i,onSubmit:R}){let[b,C]=a(A??f[0]?.tool??"claude_code"),[u,M]=a(w),[P,O]=a("interactive"),[d,S]=a(D??""),[o,F]=a("tool"),[j,I]=a(!1),[y,h]=a(null),B=d.trim().length>0&&u.trim().length>0&&!j;_((e,x)=>{if(i)if(x.upArrow){let n=p.indexOf(o);n>0&&F(p[n-1])}else if(x.downArrow){let n=p.indexOf(o);n<p.length-1&&F(p[n+1])}else x.return&&o==="submit"&&B?N():o==="mode"&&(e===" "||x.return)&&O(n=>n==="interactive"?"headless":"interactive")});async function N(){I(!0),h(null);try{await R({tool:b,config:{projectPath:u,prompt:d,mode:P,...v?{resumeSessionId:v}:{}}}),S(""),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}finally{I(!1)}}return g(N,"doSubmit"),m(c,{flexDirection:"column",paddingX:1,children:[t(r,{bold:!0,color:l,children:"\u25BC New launch"}),m(c,{children:[t(r,{color:o==="tool"&&i?l:s,children:" Tool: "}),o==="tool"&&i?t(G,{items:f.map(e=>({label:T(e.tool),value:e.tool})),initialIndex:Math.max(0,f.findIndex(e=>e.tool===b)),onSelect:e=>C(e.value)}):t(r,{children:T(b)})]}),m(c,{children:[t(r,{color:o==="project"&&i?l:s,children:" Project: "}),o==="project"&&i?t(L,{value:u,onChange:M}):t(r,{children:u})]}),m(c,{children:[t(r,{color:o==="mode"&&i?l:s,children:" Mode: "}),t(r,{children:P==="interactive"?"(\u2022) interactive ( ) headless":"( ) interactive (\u2022) headless"})]}),m(c,{children:[t(r,{color:o==="prompt"&&i?l:s,children:" Prompt: "}),o==="prompt"&&i?t(L,{value:d,onChange:S}):t(r,{children:d||"(empty)"})]}),t(c,{marginTop:1,children:m(r,{color:o==="submit"&&i?l:s,children:[B?" [ Submit ]":" [ Submit (disabled) ]",j?" \u2026submitting":""]})}),y&&m(r,{color:E,children:[" \u2717 ",y]})]})}g(U,"NewLaunchForm");export{U as a};
@@ -1 +1 @@
1
- import{a as i}from"./chunk-PQN2GAG4.js";import{a as f}from"./chunk-ZLLER3HP.js";import{useEffect as J,useState as u,useCallback as m,useRef as s}from"react";var y=5e3;function T(a=20){let[d,b]=u([]),[g,l]=u(null),[h,p]=u(!0),r=s(!1),e=s(null),c=s(0),t=m(async()=>{let o=++c.current;try{let n=await i({limit:a});if(r.current||o!==c.current)return;b(n),l(null)}catch(n){if(r.current||o!==c.current)return;l(n instanceof Error?n.message:String(n))}finally{if(r.current||o!==c.current)return;p(!1),e.current=setTimeout(()=>{t()},y)}},[a]),L=m(()=>{e.current&&clearTimeout(e.current),t()},[t]);return J(()=>(r.current=!1,t(),()=>{r.current=!0,e.current&&clearTimeout(e.current)}),[t]),{jobs:d,error:g,loading:h,refetch:L}}f(T,"useLaunchJobs");export{T as a};
1
+ import{a as i}from"./chunk-7FWIIVMC.js";import{a as f}from"./chunk-ZLLER3HP.js";import{useEffect as J,useState as u,useCallback as m,useRef as s}from"react";var y=5e3;function T(a=20){let[d,b]=u([]),[g,l]=u(null),[h,p]=u(!0),r=s(!1),e=s(null),c=s(0),t=m(async()=>{let o=++c.current;try{let n=await i({limit:a});if(r.current||o!==c.current)return;b(n),l(null)}catch(n){if(r.current||o!==c.current)return;l(n instanceof Error?n.message:String(n))}finally{if(r.current||o!==c.current)return;p(!1),e.current=setTimeout(()=>{t()},y)}},[a]),L=m(()=>{e.current&&clearTimeout(e.current),t()},[t]);return J(()=>(r.current=!1,t(),()=>{r.current=!0,e.current&&clearTimeout(e.current)}),[t]),{jobs:d,error:g,loading:h,refetch:L}}f(T,"useLaunchJobs");export{T as a};
@@ -1 +1 @@
1
- import{a as T}from"./chunk-5RBLIVBF.js";import{a as S}from"./chunk-XFAFMYIP.js";import{b as A}from"./chunk-CNOD6HWU.js";import{e as x}from"./chunk-L2CFSMBC.js";import{a as C}from"./chunk-JPUH3V67.js";import{d as M}from"./chunk-TZA4HAVF.js";import{e as k,f as E,h as p}from"./chunk-QAV4HW7D.js";import{a as w}from"./chunk-ZLLER3HP.js";async function W(v,f){let{mirrorId:i,evalTargetId:g,config:o}=v,a=w(e=>f.logger.info(e),"log"),s=await k(`/api/eval-targets/${g}`),$=await k(`/api/eval-targets/${g}/evals`);if($.length===0&&o.generateIfEmpty){a("No eval cases on target \u2014 generating from content via local LLM...");let e=await A({content:s.content,name:s.name});if(e===null)throw new Error("Case generation requires an LLM backend (claude CLI on PATH or ANTHROPIC_API_KEY) \u2014 none available on this worker.");let n=[];for(let t of e)n.push(await E(`/api/eval-targets/${g}/evals`,t));$=n,a(`Generated ${n.length} eval case(s)`)}if($.length===0)throw new T("No evals defined for target");let G=o.runsPerEval??1,R=o.timeout??12e4,j=o.iteration??1,y=new Set;if(f.job.attempts>1)for(let n=0;;n+=100){let t=await k(`/api/eval-targets/${g}/runs?jobId=${i}&limit=100&offset=${n}`);for(let r of t)y.add(`${r.evalId}|${r.configuration}|${r.runNumber}|${r.iteration}`);if(t.length<100)break}let _=[{name:"with_target",content:s.content}];o.skipBaseline||_.push({name:"without_target"});let d=[];for(let e of $)for(let n of _)for(let t=1;t<=G;t++)y.has(`${e.id}|${n.name}|${t}|${j}`)||d.push({eval_:e,configuration:n.name,targetContent:n.content,runNumber:t});y.size>0&&a(`Resuming attempt ${f.job.attempts}: ${y.size} run(s) already persisted, ${d.length} remaining`);let l=d.length,u=0,m=Math.min(o.parallel??1,4);await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:0,current:null,message:`Starting ${l} eval runs (concurrency: ${m})...`}});let b=[];async function I(e){let n=`${e.configuration} \xB7 ${e.eval_.name} \xB7 run#${e.runNumber}`;a(`[${u+1}/${l}] ${n}`);let t=x({targetType:s.type,targetContent:e.targetContent,targetName:s.name});t.leakedFiles.length&&a(`\u26A0 CONTAMINATED ${n}: ${t.leakedFiles.join(", ")} survived the strip`);try{let r=await M({prompt:e.eval_.prompt,targetContent:t.systemPrompt,workDir:t.workDir,timeout:R,model:o.model}),c={};return!o.skipGrading&&e.eval_.expectations.length>0&&!r.error&&(c=await C({prompt:e.eval_.prompt,output:r.output,expectations:e.eval_.expectations,model:o.graderModel??o.model,timeout:R})),{jobId:i,evalId:e.eval_.id,evalTargetId:s.id,evalTargetVersion:s.version,configuration:e.configuration,runNumber:e.runNumber,iteration:j,status:r.error?"failed":"completed",outputs:{...r.error?{error:r.error}:{transcript:r.output,...r.model?{model:r.model}:{}},methodology:t.methodology,delivery:t.delivery,isolated:t.isWorktree,...t.leakedFiles.length?{leakedFiles:t.leakedFiles}:{}},timing:{duration_ms:r.durationMs,total_tokens:r.totalTokens},grading:c,worktree:t.isWorktree?!0:void 0}}finally{t.cleanup()}}if(w(I,"processItem"),m<=1)for(let e of d){let n=`${e.configuration} \xB7 ${e.eval_.name} \xB7 run#${e.runNumber}`;await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:n,message:`Executing ${n}...`}});let t=await I(e);await E("/api/eval-runs",t),b.push(t),u++,await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:n,message:`Completed ${n}`}})}else{a(`Running ${l} evals with concurrency=${m} (worktree isolation)`);for(let e=0;e<d.length;e+=m){let n=d.slice(e,e+m),t=`batch ${Math.floor(e/m)+1}/${Math.ceil(d.length/m)}`;await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:t,message:`Executing ${t} (${n.length} parallel)...`}});let r=await Promise.all(n.map(I));for(let c of r)await E("/api/eval-runs",c),b.push(c),u++;await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:t,message:`Completed ${t}`}})}}let P=J(b),h;if(!o.skipGrading&&b.some(e=>e.grading&&Object.keys(e.grading).length>0))try{a(`Running meta-judge for job ${i}...`);let e=$.map(n=>{let r=b.filter(c=>c.evalId===n.id&&c.configuration==="with_target")[0];return{evalName:n.name,prompt:n.prompt,expectations:n.expectations,grading:r?.grading?r.grading:null,output:r?.outputs?.transcript?.slice(0,500)}});h=await S({targetName:s.name,evalResults:e,model:o.graderModel??o.model,timeout:6e4}),a(`Meta-judge: quality=${h.quality_score}/5, issues=${h.issues.length}`)}catch(e){a(`Meta-judge failed (non-fatal): ${e instanceof Error?e.message:String(e)}`)}let N=h?{...P,meta_judgement:h}:P;return a(`Job ${i} completed: ${u}/${l} runs`),await p(`/api/eval-jobs/${i}/state`,{result:N}).catch(e=>{a(`result persist failed: ${e instanceof Error?e.message:String(e)}`)}),N}w(W,"processEval");function J(v){let f=v.filter(a=>a.status==="completed"),i=v.filter(a=>a.status==="failed"),g=f.filter(a=>{let s=a.grading;return s&&Object.keys(s).length>0}),o=g.length>0?g.reduce((a,s)=>a+(s.grading?.summary?.pass_rate??0),0)/g.length:null;return{total:v.length,completed:f.length,failed:i.length,avgPassRate:o}}w(J,"buildSummary");export{W as a};
1
+ import{a as T}from"./chunk-5RBLIVBF.js";import{a as S}from"./chunk-XFAFMYIP.js";import{b as A}from"./chunk-CNOD6HWU.js";import{e as x}from"./chunk-DN2T3FXN.js";import{a as C}from"./chunk-JPUH3V67.js";import{d as M}from"./chunk-TZA4HAVF.js";import{e as k,f as E,h as p}from"./chunk-MPDSQALK.js";import{a as w}from"./chunk-ZLLER3HP.js";async function W(v,f){let{mirrorId:i,evalTargetId:g,config:o}=v,a=w(e=>f.logger.info(e),"log"),s=await k(`/api/eval-targets/${g}`),$=await k(`/api/eval-targets/${g}/evals`);if($.length===0&&o.generateIfEmpty){a("No eval cases on target \u2014 generating from content via local LLM...");let e=await A({content:s.content,name:s.name});if(e===null)throw new Error("Case generation requires an LLM backend (claude CLI on PATH or ANTHROPIC_API_KEY) \u2014 none available on this worker.");let n=[];for(let t of e)n.push(await E(`/api/eval-targets/${g}/evals`,t));$=n,a(`Generated ${n.length} eval case(s)`)}if($.length===0)throw new T("No evals defined for target");let G=o.runsPerEval??1,R=o.timeout??12e4,j=o.iteration??1,y=new Set;if(f.job.attempts>1)for(let n=0;;n+=100){let t=await k(`/api/eval-targets/${g}/runs?jobId=${i}&limit=100&offset=${n}`);for(let r of t)y.add(`${r.evalId}|${r.configuration}|${r.runNumber}|${r.iteration}`);if(t.length<100)break}let _=[{name:"with_target",content:s.content}];o.skipBaseline||_.push({name:"without_target"});let d=[];for(let e of $)for(let n of _)for(let t=1;t<=G;t++)y.has(`${e.id}|${n.name}|${t}|${j}`)||d.push({eval_:e,configuration:n.name,targetContent:n.content,runNumber:t});y.size>0&&a(`Resuming attempt ${f.job.attempts}: ${y.size} run(s) already persisted, ${d.length} remaining`);let l=d.length,u=0,m=Math.min(o.parallel??1,4);await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:0,current:null,message:`Starting ${l} eval runs (concurrency: ${m})...`}});let b=[];async function I(e){let n=`${e.configuration} \xB7 ${e.eval_.name} \xB7 run#${e.runNumber}`;a(`[${u+1}/${l}] ${n}`);let t=x({targetType:s.type,targetContent:e.targetContent,targetName:s.name});t.leakedFiles.length&&a(`\u26A0 CONTAMINATED ${n}: ${t.leakedFiles.join(", ")} survived the strip`);try{let r=await M({prompt:e.eval_.prompt,targetContent:t.systemPrompt,workDir:t.workDir,timeout:R,model:o.model}),c={};return!o.skipGrading&&e.eval_.expectations.length>0&&!r.error&&(c=await C({prompt:e.eval_.prompt,output:r.output,expectations:e.eval_.expectations,model:o.graderModel??o.model,timeout:R})),{jobId:i,evalId:e.eval_.id,evalTargetId:s.id,evalTargetVersion:s.version,configuration:e.configuration,runNumber:e.runNumber,iteration:j,status:r.error?"failed":"completed",outputs:{...r.error?{error:r.error}:{transcript:r.output,...r.model?{model:r.model}:{}},methodology:t.methodology,delivery:t.delivery,isolated:t.isWorktree,...t.leakedFiles.length?{leakedFiles:t.leakedFiles}:{}},timing:{duration_ms:r.durationMs,total_tokens:r.totalTokens},grading:c,worktree:t.isWorktree?!0:void 0}}finally{t.cleanup()}}if(w(I,"processItem"),m<=1)for(let e of d){let n=`${e.configuration} \xB7 ${e.eval_.name} \xB7 run#${e.runNumber}`;await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:n,message:`Executing ${n}...`}});let t=await I(e);await E("/api/eval-runs",t),b.push(t),u++,await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:n,message:`Completed ${n}`}})}else{a(`Running ${l} evals with concurrency=${m} (worktree isolation)`);for(let e=0;e<d.length;e+=m){let n=d.slice(e,e+m),t=`batch ${Math.floor(e/m)+1}/${Math.ceil(d.length/m)}`;await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:t,message:`Executing ${t} (${n.length} parallel)...`}});let r=await Promise.all(n.map(I));for(let c of r)await E("/api/eval-runs",c),b.push(c),u++;await p(`/api/eval-jobs/${i}/progress`,{status:"running",progress:{total:l,completed:u,current:t,message:`Completed ${t}`}})}}let P=J(b),h;if(!o.skipGrading&&b.some(e=>e.grading&&Object.keys(e.grading).length>0))try{a(`Running meta-judge for job ${i}...`);let e=$.map(n=>{let r=b.filter(c=>c.evalId===n.id&&c.configuration==="with_target")[0];return{evalName:n.name,prompt:n.prompt,expectations:n.expectations,grading:r?.grading?r.grading:null,output:r?.outputs?.transcript?.slice(0,500)}});h=await S({targetName:s.name,evalResults:e,model:o.graderModel??o.model,timeout:6e4}),a(`Meta-judge: quality=${h.quality_score}/5, issues=${h.issues.length}`)}catch(e){a(`Meta-judge failed (non-fatal): ${e instanceof Error?e.message:String(e)}`)}let N=h?{...P,meta_judgement:h}:P;return a(`Job ${i} completed: ${u}/${l} runs`),await p(`/api/eval-jobs/${i}/state`,{result:N}).catch(e=>{a(`result persist failed: ${e instanceof Error?e.message:String(e)}`)}),N}w(W,"processEval");function J(v){let f=v.filter(a=>a.status==="completed"),i=v.filter(a=>a.status==="failed"),g=f.filter(a=>{let s=a.grading;return s&&Object.keys(s).length>0}),o=g.length>0?g.reduce((a,s)=>a+(s.grading?.summary?.pass_rate??0),0)/g.length:null;return{total:v.length,completed:f.length,failed:i.length,avgPassRate:o}}w(J,"buildSummary");export{W as a};
@@ -1,2 +1,2 @@
1
- import{c as E,o as m}from"./chunk-7DFNBRLY.js";import{a as d}from"./chunk-QAV4HW7D.js";import{a as c}from"./chunk-ZLLER3HP.js";import*as p from"node:fs";import*as u from"node:path";import*as _ from"node:os";function T(){if(process.env.RULEMETRIC_API_KEY||process.env.RULEMETRIC_ACCESS_TOKEN)return;let s=u.join(_.homedir(),".config","rulemetric","env");C(s)||C(u.join(process.cwd(),".env.local"))}c(T,"ensureEnv");function C(s){try{let t=p.readFileSync(s,"utf-8");for(let n of t.split(`
1
+ import{c as E,o as m}from"./chunk-7DFNBRLY.js";import{a as d}from"./chunk-MPDSQALK.js";import{a as c}from"./chunk-ZLLER3HP.js";import*as p from"node:fs";import*as u from"node:path";import*as _ from"node:os";function T(){if(process.env.RULEMETRIC_API_KEY||process.env.RULEMETRIC_ACCESS_TOKEN)return;let s=u.join(_.homedir(),".config","rulemetric","env");C(s)||C(u.join(process.cwd(),".env.local"))}c(T,"ensureEnv");function C(s){try{let t=p.readFileSync(s,"utf-8");for(let n of t.split(`
2
2
  `)){let e=n.trim();if(!e||e.startsWith("#"))continue;let o=e.indexOf("=");if(o<0)continue;let r=e.slice(0,o).trim(),i=e.slice(o+1).trim();process.env[r]||(process.env[r]=i)}return!!(process.env.RULEMETRIC_API_KEY||process.env.RULEMETRIC_ACCESS_TOKEN)}catch{return!1}}c(C,"loadEnvFile");T();async function I(s){let t={totalSessions:0,totalCalls:0,totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUSD:0,providers:{}},n=await m(s);t.providers={};for(let a of n)t.providers[a.provider]=(t.providers[a.provider]||0)+1;let e=new E,o=n.filter(a=>a.provider==="claude");for(let a of o)try{let h=p.readdirSync(a.path).filter(f=>f.endsWith(".jsonl"));t.totalSessions+=h.length;for(let f of h){let v=p.readFileSync(u.join(a.path,f),"utf-8"),R=e.parse(v);for(let l of R.events)l.tokenUsage&&(t.totalCalls++,t.totalInputTokens+=l.tokenUsage.input,t.totalOutputTokens+=l.tokenUsage.output,t.totalCacheReadTokens+=l.tokenUsage.cacheRead??0,t.totalCacheWriteTokens+=l.tokenUsage.cacheWrite??0)}}catch{}let r=15,i=75;return t.totalCostUSD=Math.round((t.totalInputTokens/1e6*r+t.totalOutputTokens/1e6*i+t.totalCacheReadTokens/1e6*(r*.1)+t.totalCacheWriteTokens/1e6*(r*1.25))*100)/100,t}c(I,"loadLocalStats");async function U(s){let t=process.env.RULEMETRIC_API_URL??d,n=process.env.RULEMETRIC_API_KEY,e=process.env.RULEMETRIC_ACCESS_TOKEN,o=n??e;if(!o)return null;let r=new URLSearchParams;s&&r.set("projectPath",s);try{let i=await fetch(`${t}/api/insights/compute?${r}`,{headers:{Authorization:`Bearer ${o}`},signal:AbortSignal.timeout(5e3)});return i.ok?await i.json():null}catch{return null}}c(U,"loadApiInsights");async function g(s){let t=process.env.RULEMETRIC_API_URL??d,n=process.env.RULEMETRIC_API_KEY??process.env.RULEMETRIC_ACCESS_TOKEN;if(!n)return null;let e=new URLSearchParams;s&&e.set("projectPath",s);try{let o=await fetch(`${t}/api/insights/linked-instructions?${e}`,{headers:{Authorization:`Bearer ${n}`},signal:AbortSignal.timeout(5e3)});return o.ok?await o.json():null}catch{return null}}c(g,"loadLinkedInstructions");export{I as a,U as b,g as c};
@@ -1 +1 @@
1
- import{e as c,f as d}from"./chunk-QAV4HW7D.js";import{a as m}from"./chunk-ZLLER3HP.js";async function f(g,p){let r=m(e=>p?.logger?.info?.(e)??console.log(e),"log"),{projectPath:s}=g,i=`[cron_instruction_training] ${s}`;if(!s)return{skipped:"no-project-path"};let n=await d("/api/instruction-experiments/settle",{projectPath:s}),o=n.settled.map(e=>e.outcome),a=o.filter(e=>e==="graduated").length;for(let e of n.settled)r(`${i}: experiment ${e.experimentId} \u2192 ${e.outcome}`);n.examined>0&&r(`${i}: examined ${n.examined} running experiment(s) \u2014 ${n.settled.length} settled (${a} graduated), ${n.stillRunning} still gathering`);let t=await c(`/api/instruction-suggestions/trialable?projectPath=${encodeURIComponent(s)}`);for(let e of t.refused)r(`${i}: not trialling "${e.name}" \u2014 ${e.reason}`);if(t.candidates.length===0)return r(`${i}: no new trial started (${t.running}/${t.limits.maxConcurrent} running, ${t.slots} slot(s) free)`),{examined:n.examined,settled:n.settled.length,graduated:a,nominated:0,running:t.running,outcomes:o};let u=0;for(let e of t.candidates)try{await d("/api/instruction-experiments",{instructionId:e.instructionId,projectPath:s,source:"trial"}),u+=1,r(`${i}: now measuring "${e.name}" (score ${e.score.toFixed(2)})`)}catch(l){r(`${i}: could not measure "${e.name}" \u2014 ${l instanceof Error?l.message:String(l)}`)}return{examined:n.examined,settled:n.settled.length,graduated:a,nominated:u,running:t.running+u,outcomes:o}}m(f,"cronInstructionTraining");export{f as a};
1
+ import{e as c,f as d}from"./chunk-MPDSQALK.js";import{a as m}from"./chunk-ZLLER3HP.js";async function f(g,p){let r=m(e=>p?.logger?.info?.(e)??console.log(e),"log"),{projectPath:s}=g,i=`[cron_instruction_training] ${s}`;if(!s)return{skipped:"no-project-path"};let n=await d("/api/instruction-experiments/settle",{projectPath:s}),o=n.settled.map(e=>e.outcome),a=o.filter(e=>e==="graduated").length;for(let e of n.settled)r(`${i}: experiment ${e.experimentId} \u2192 ${e.outcome}`);n.examined>0&&r(`${i}: examined ${n.examined} running experiment(s) \u2014 ${n.settled.length} settled (${a} graduated), ${n.stillRunning} still gathering`);let t=await c(`/api/instruction-suggestions/trialable?projectPath=${encodeURIComponent(s)}`);for(let e of t.refused)r(`${i}: not trialling "${e.name}" \u2014 ${e.reason}`);if(t.candidates.length===0)return r(`${i}: no new trial started (${t.running}/${t.limits.maxConcurrent} running, ${t.slots} slot(s) free)`),{examined:n.examined,settled:n.settled.length,graduated:a,nominated:0,running:t.running,outcomes:o};let u=0;for(let e of t.candidates)try{await d("/api/instruction-experiments",{instructionId:e.instructionId,projectPath:s,source:"trial"}),u+=1,r(`${i}: now measuring "${e.name}" (score ${e.score.toFixed(2)})`)}catch(l){r(`${i}: could not measure "${e.name}" \u2014 ${l instanceof Error?l.message:String(l)}`)}return{examined:n.examined,settled:n.settled.length,graduated:a,nominated:u,running:t.running+u,outcomes:o}}m(f,"cronInstructionTraining");export{f as a};
@@ -1 +1 @@
1
- import{b as o,f as a}from"./chunk-QAV4HW7D.js";import{a as n}from"./chunk-ZLLER3HP.js";function c(e){return e==null?e??null:e instanceof Date?e.toISOString():e}n(c,"serializeDate");async function d(e){let r={provider:e.provider,plan:e.plan,limitType:e.limitType,value:e.value,unit:e.unit,comparator:e.comparator,resetsAt:c(e.resetsAt),sourceType:e.sourceType,sourceUrl:e.sourceUrl,sourceEvidence:e.sourceEvidence,confidence:e.confidence,observedAt:c(e.observedAt)};return a("/api/internal/research/observe",r)}n(d,"postObservation");async function f(e){let r=0,i=0,s=[];for(let u of e)try{await d(u),r++}catch(t){i++;let p=t instanceof o?`HTTP ${t.statusCode}: ${t.message}`:String(t);s.length<5&&s.push(p)}return{posted:r,failed:i,errors:s}}n(f,"postObservations");export{d as a,f as b};
1
+ import{b as o,f as a}from"./chunk-MPDSQALK.js";import{a as n}from"./chunk-ZLLER3HP.js";function c(e){return e==null?e??null:e instanceof Date?e.toISOString():e}n(c,"serializeDate");async function d(e){let r={provider:e.provider,plan:e.plan,limitType:e.limitType,value:e.value,unit:e.unit,comparator:e.comparator,resetsAt:c(e.resetsAt),sourceType:e.sourceType,sourceUrl:e.sourceUrl,sourceEvidence:e.sourceEvidence,confidence:e.confidence,observedAt:c(e.observedAt)};return a("/api/internal/research/observe",r)}n(d,"postObservation");async function f(e){let r=0,i=0,s=[];for(let u of e)try{await d(u),r++}catch(t){i++;let p=t instanceof o?`HTTP ${t.statusCode}: ${t.message}`:String(t);s.length<5&&s.push(p)}return{posted:r,failed:i,errors:s}}n(f,"postObservations");export{d as a,f as b};
@@ -0,0 +1,17 @@
1
+ import{a as M,b as A,c as N,d as j}from"./chunk-4PWGV2OW.js";import{a as S}from"./chunk-5RBLIVBF.js";import{c as z,d as O,f as b}from"./chunk-B3BHB26P.js";import{e as $,f as v,h as f}from"./chunk-MPDSQALK.js";import{a as E}from"./chunk-E4U6AOTM.js";import{a as _}from"./chunk-ZLLER3HP.js";async function Z(c,d){let{mirrorId:r,projectPath:e,projectId:a,config:p}=c,s=_(t=>d.logger.info(t),"log");if(p?.sessionId)return L({mirrorId:r,sessionId:p.sessionId},s);s(`Processing insights job ${r}...`),await f(`/api/insights-jobs/${r}/progress`,{status:"running",progress:{step:"reading_data"}});try{let{repaired:t}=await v("/api/sessions/repair-analyzed-at",{});t>0&&s(` Repaired analyzed_at on ${t} orphan session(s).`)}catch(t){s(` Warning: analyzed_at repair failed: ${t instanceof Error?t.message:String(t)}`)}let o=await H(e,a);if(!o)throw new S("No session data found \u2014 ensure sessions are captured and enriched.");s(` Found ${o.stats.sessions} sessions, generating recommendations...`);let g=20,u=200;if(O()!=="none"){let t=0,i=0;try{for(;t<u;){let y=await $(`/api/sessions?hasAnalysis=false&limit=${g}&offset=${i}`);if(y.length===0)break;s(` Generating facets for ${y.length} un-analyzed sessions (drained ${t} so far)...`);for(let h of y){if(t>=u)break;try{let m=await $(`/api/sessions/${h.id}/events?limit=100`);if(m.length<2){t++,i++;continue}let C=m.filter(k=>k.eventType==="user_message"||k.eventType==="human").map(k=>k.content?.slice(0,200)??"").filter(Boolean).join(`
2
+ ---
3
+ `);if(!C){t++,i++;continue}let I=await b(j,C,4096);if(I){let k=m.filter(P=>P.eventType==="user_message"||P.eventType==="human").length;await f(`/api/sessions/${h.id}/enrich`,{analysis:{source:"generated_facets",...I},analyzedEventCount:m.length,analyzedTurnCount:k}),s(` Generated facets for session ${h.id} (${h.tool})`)}else i++;t++}catch(m){s(` Failed to generate facets for session ${h.id}: ${m instanceof Error?m.message:String(m)}`),t++,i++}}if(y.length<g)break}}catch(y){s(` Warning: facet generation failed after ${t} sessions: ${y instanceof Error?y.message:String(y)}`)}}let n=await F(e,s);n&&s(` Generator memory: ${n.split(`
4
+ `).length} lines of prior-advice context`);let l={},w=A.length+1;for(let t=0;t<A.length;t++){let i=A[t];s(` [${t+1}/${w}] Generating ${i.name}...`);try{await f(`/api/insights-jobs/${r}/progress`,{status:"running",progress:{step:i.name,current:t+1,total:w,partial:{...l}}})}catch(m){s(` Warning: progress update failed for ${i.name}: ${m instanceof Error?m.message:String(m)}`)}s(` Running LLM prompt for ${i.name}...`);let y=i.usesGeneratorMemory&&n?`${o.summary}
5
+ ${n}`:o.summary,h=await b(i.prompt,y,i.maxTokens);h?(l[i.name]=h,s(` Got result for ${i.name}`)):s(` No result for ${i.name} (LLM returned null)`)}s(` [${w}/${w}] Generating at_a_glance...`),await f(`/api/insights-jobs/${r}/progress`,{status:"running",progress:{step:"at_a_glance",current:w,total:w,partial:{...l}}});let G=[o.summary,l.what_works?`
6
+ ## What Works
7
+ ${JSON.stringify(l.what_works)}`:"",l.friction_analysis?`
8
+ ## Friction
9
+ ${JSON.stringify(l.friction_analysis)}`:"",l.suggestions?`
10
+ ## Suggestions
11
+ ${JSON.stringify(l.suggestions)}`:"",l.on_the_horizon?`
12
+ ## On the Horizon
13
+ ${JSON.stringify(l.on_the_horizon)}`:""].join(`
14
+ `),R=await b(N,G,8192);R&&(l.at_a_glance=R),s(" Uploading results..."),s(` Done! Recommendations generated for job ${r}`),E(l);let T={recommendations:l};return await f(`/api/insights-jobs/${r}/state`,{result:T}).catch(t=>{s(`result persist failed: ${t instanceof Error?t.message:String(t)}`)}),await J(l,e,s),T}_(Z,"processInsights");async function J(c,d,r){if(d)try{let e=c.suggestions,a=Array.isArray(e?.claude_md_additions)?e.claude_md_additions.filter(n=>typeof n?.addition=="string"&&n.addition.trim().length>=12).map(n=>({addition:String(n.addition).trim(),why:String(n.why??"")})):[],p=Array.isArray(c.recommended_skills)?c.recommended_skills.filter(n=>typeof n?.skillId=="string"&&n.skillId.length>0).map(n=>({skillId:String(n.skillId),reason:String(n.reason??"")})):[],s=Array.isArray(e?.features_to_try)?e.features_to_try.filter(n=>typeof n?.feature=="string"&&n.feature.trim().length>=2).map(n=>({feature:String(n.feature).trim(),one_liner:String(n.one_liner??""),why_for_you:String(n.why_for_you??""),example_code:String(n.example_code??"")})):[],o=[...Array.isArray(e?.usage_patterns)?e.usage_patterns.map(n=>({title:String(n.title??"").trim(),lead:String(n.suggestion??""),detail:String(n.detail??""),copyable_prompt:String(n.copyable_prompt??""),origin:"usage_pattern"})):[],...Array.isArray(c.on_the_horizon?.opportunities)?c.on_the_horizon.opportunities.map(n=>({title:String(n.title??"").trim(),lead:String(n.whats_possible??""),detail:String(n.how_to_try??""),copyable_prompt:String(n.copyable_prompt??""),origin:"opportunity"})):[]].filter(n=>n.title.length>=2);if(a.length===0&&p.length===0&&s.length===0&&o.length===0)return;let g=await v("/api/insights/recommendations/nominate",{projectPath:d,additions:a.slice(0,20),skills:p.slice(0,20),features:s.slice(0,20),advice:o.slice(0,40)}),u=g.additionsRejected??[];r(` ${g.nominated} recommendation(s) nominated into the suggestion feed (${g.additionsCreated} new instruction(s)`+((g.featuresCreated??0)>0?`, ${g.featuresCreated} feature proposal(s)`:"")+((g.adviceCreated??0)>0?`, ${g.adviceCreated} pattern/opportunity`:"")+(g.skillsUnresolved>0?`, ${g.skillsUnresolved} skill slug(s) unresolved`:"")+(u.length>0?`, ${u.length} rejected as unfilled templates`:"")+")");for(let n of u)r(` rejected "${n.name}" \u2014 unfilled placeholder(s): ${n.placeholders.join(", ")}`)}catch(e){r(` nomination skipped: ${e instanceof Error?e.message:String(e)}`)}}_(J,"nominateRecommendations");async function L(c,d){let{mirrorId:r,sessionId:e}=c;d(`Analyzing session ${e} via tool CLI...`),await f(`/api/insights-jobs/${r}/progress`,{status:"running",progress:{step:"fetching_session"}});let a=await $(`/api/sessions/${e}`);if(a.analysis&&a.analysis.source==="session_analysis")return d(` Session ${e} already analyzed \u2014 skipping (idempotency guard)`),{sessionId:e,skipped:!0,reason:"already_analyzed"};let p=await $(`/api/sessions/${e}/events?limit=100`);if(p.length<2)throw new S("Session has too few events to analyze");let s=p.filter(u=>u.eventType==="user_message"||u.eventType==="human").map(u=>u.content?.slice(0,200)??"").filter(Boolean).join(`
15
+ ---
16
+ `);if(!s)throw new S("No user messages found in session");await f(`/api/insights-jobs/${r}/progress`,{status:"running",progress:{step:"running_analysis",tool:a.tool}});let o=await z(a.tool,j,s);if(!o)throw new Error(`Analysis failed \u2014 ${a.tool} CLI returned no result`);let g=p.filter(u=>u.eventType==="user_message"||u.eventType==="human").length;return await f(`/api/sessions/${e}/enrich`,{analysis:{source:"session_analysis",tool:a.tool,...o},analyzedEventCount:p.length,analyzedTurnCount:g}),d(` Session ${e} analyzed via ${a.tool}`),{sessionId:e,tool:a.tool,facets:o}}_(L,"processSessionAnalysisInline");async function F(c,d,r=$){try{let e=await r(`/api/insights/recommendations/history?projectPath=${encodeURIComponent(c??"")}`);return!e||!Array.isArray(e.dismissed)||!Array.isArray(e.repeated)?"":M(e)}catch(e){return d(` Warning: generator memory unavailable (${e instanceof Error?e.message:String(e)}) \u2014 generating without it`),""}}_(F,"fetchGeneratorMemory");async function H(c,d){try{let r=new URLSearchParams;d?r.set("projectId",d):c&&r.set("projectPath",c);let e=await $(`/api/insights/compute?${r}`);if(!e||e.total_sessions===0)return null;let a=Object.entries(e.tool_counts??{}).sort((s,o)=>o[1]-s[1]).slice(0,10).map(([s,o])=>`${s}: ${o}`).join(", ");return{summary:[`Sessions: ${e.total_sessions}, Messages: ${e.total_messages}, Hours: ${Math.round(e.total_duration_hours)}`,`Top tools: ${a}`,e.goal_categories&&Object.keys(e.goal_categories).length>0?`Goals: ${JSON.stringify(e.goal_categories)}`:"",e.friction&&Object.keys(e.friction).length>0?`Friction: ${JSON.stringify(e.friction)}`:"",e.outcomes&&Object.keys(e.outcomes).length>0?`Outcomes: ${JSON.stringify(e.outcomes)}`:"",e.projects&&Object.keys(e.projects).length>0?`Projects: ${JSON.stringify(e.projects)}`:""].filter(Boolean).join(`
17
+ `),stats:{sessions:e.total_sessions,totalMessages:e.total_messages,totalHours:e.total_duration_hours,toolCounts:e.tool_counts,goalCounts:e.goal_categories,frictionCounts:e.friction}}}catch{return null}}_(H,"buildDataSummaryFromApi");export{Z as a,F as b};
@@ -1,4 +1,4 @@
1
- import{d as b,f as y}from"./chunk-B3BHB26P.js";import{e as M,f as w}from"./chunk-QAV4HW7D.js";import{a as u}from"./chunk-ZLLER3HP.js";var $={anthropic:["https://platform.claude.com/docs/en/about-claude/pricing.md"],openai:["https://platform.openai.com/docs/pricing"]},R=.7,v=16e3,x=["You extract LLM API pricing from a provider pricing page.","You will be given the page text in <data> tags and, in this system prompt,","a list of model ids to find. For EACH requested model id, return its","published USD price per 1,000,000 tokens.","","Rules:","- Only report a model if you can find its rate ON THE PAGE. If it is not on"," the page, set found=false and omit the numbers \u2014 never guess from memory.","- inputPerM and outputPerM are the standard (non-batch, non-priority) rates.","- cacheReadPerM: the cached/discounted-input rate if published, else omit.","- For Anthropic models ONLY, if cache-write rates are not explicitly listed,"," compute them as cacheWrite5mPerM = inputPerM * 1.25 and"," cacheWrite1hPerM = inputPerM * 2.0. For all other providers, omit them.","- confidence is 0..1: how sure you are the numbers are correct for THIS id.","- contextWindow in tokens if stated, else omit.","","Respond with ONLY a JSON object of the form:",'{"rates":[{"modelId":"...","found":true,"confidence":0.9,"inputPerM":5,"outputPerM":25,"cacheReadPerM":0.5,"contextWindow":1000000}]}'].join(`
1
+ import{d as b,f as y}from"./chunk-B3BHB26P.js";import{e as M,f as w}from"./chunk-MPDSQALK.js";import{a as u}from"./chunk-ZLLER3HP.js";var $={anthropic:["https://platform.claude.com/docs/en/about-claude/pricing.md"],openai:["https://platform.openai.com/docs/pricing"]},R=.7,v=16e3,x=["You extract LLM API pricing from a provider pricing page.","You will be given the page text in <data> tags and, in this system prompt,","a list of model ids to find. For EACH requested model id, return its","published USD price per 1,000,000 tokens.","","Rules:","- Only report a model if you can find its rate ON THE PAGE. If it is not on"," the page, set found=false and omit the numbers \u2014 never guess from memory.","- inputPerM and outputPerM are the standard (non-batch, non-priority) rates.","- cacheReadPerM: the cached/discounted-input rate if published, else omit.","- For Anthropic models ONLY, if cache-write rates are not explicitly listed,"," compute them as cacheWrite5mPerM = inputPerM * 1.25 and"," cacheWrite1hPerM = inputPerM * 2.0. For all other providers, omit them.","- confidence is 0..1: how sure you are the numbers are correct for THIS id.","- contextWindow in tokens if stated, else omit.","","Respond with ONLY a JSON object of the form:",'{"rates":[{"modelId":"...","found":true,"confidence":0.9,"inputPerM":5,"outputPerM":25,"cacheReadPerM":0.5,"contextWindow":1000000}]}'].join(`
2
2
  `);async function C(f){try{let n=await fetch(f,{headers:{accept:"text/plain, text/markdown, text/html"}});if(!n.ok)return null;let i=await n.text();return i.length>v?i.slice(0,v):i}catch{return null}}u(C,"fetchPage");var L=u(async(f,n)=>{let i=await M("/api/pricing/coverage"),I=[...i.unpriced,...i.stale],m=new Map;for(let r of I)m.set(`${r.provider}::${r.modelId}`,r);let a=[...m.values()];if(a.length===0)return n.logger.info("[cron-refresh-pricing] coverage clean \u2014 nothing unpriced or stale"),{status:"clean",checked:i.unpriced.length+i.stale.length};if(b()==="none")return n.logger.warn(`[cron-refresh-pricing] ${a.length} model(s) need pricing but no LLM backend (install the claude CLI or set ANTHROPIC_API_KEY) \u2014 skipping`),{status:"no-llm",pending:a.length};let d=new Map;for(let r of a){let o=d.get(r.provider)??[];o.push(r.modelId),d.set(r.provider,o)}let t={written:0,unchanged:0,flagged:0,rejected:0,skipped:0},c=[];for(let[r,o]of d){let h=$[r];if(!h){n.logger.warn(`[cron-refresh-pricing] no pricing source configured for provider '${r}' (${o.length} model(s)) \u2014 skipping`),t.skipped+=o.length;continue}let p="",l="";for(let e of h){let s=await C(e);s&&(p+=`
3
3
 
4
4
  === ${e} ===
@@ -1,2 +1,2 @@
1
- import{c as f}from"./chunk-6QKI756T.js";import{a as l}from"./chunk-5RBLIVBF.js";import{b as g,e as k}from"./chunk-QAV4HW7D.js";import{a as m}from"./chunk-ZLLER3HP.js";async function C(w,i={}){let R=i.removeWorktreeFn??f,t=i.log??(e=>process.stderr.write(`[process_run_cleanup] ${e}
1
+ import{c as f}from"./chunk-6QKI756T.js";import{a as l}from"./chunk-5RBLIVBF.js";import{b as g,e as k}from"./chunk-MPDSQALK.js";import{a as m}from"./chunk-ZLLER3HP.js";async function C(w,i={}){let R=i.removeWorktreeFn??f,t=i.log??(e=>process.stderr.write(`[process_run_cleanup] ${e}
2
2
  `)),j=i.getRunDetail??(async e=>{try{return await k(`/api/runs/${e}`)}catch(r){if(r instanceof g&&r.statusCode===404)return null;throw r}}),{runId:o}=w,n=await j(o);if(!n)throw new l(`Run ${o} not found`);if(!n.run.projectPath)throw new l(`Run ${o} has no projectPath; cannot resolve a repo root for worktree cleanup`);let a=n.run.projectPath,$=n.sessions.filter(e=>e.endedAt!=null),s=[],u=0,c=0,p=0,d=0,h=new Set;for(let e of $)if(!(!e.projectPath||e.projectPath===a)&&!h.has(e.projectPath)){h.add(e.projectPath);try{let r=await R({repoRoot:a,worktreePath:e.projectPath});r.removed?(u++,s.push({sessionId:e.id,worktreePath:e.projectPath,status:"removed"}),t(`removed worktree ${e.projectPath} (session ${e.id})`)):r.reason==="dirty"?(c++,s.push({sessionId:e.id,worktreePath:e.projectPath,status:"skipped-dirty"}),t(`skipped dirty worktree ${e.projectPath} (session ${e.id}) \u2014 uncommitted changes`)):(p++,s.push({sessionId:e.id,worktreePath:e.projectPath,status:"absent"}),t(`worktree absent ${e.projectPath} (session ${e.id})`))}catch(r){let P=r instanceof Error?r.message:String(r);d++,s.push({sessionId:e.id,worktreePath:e.projectPath,status:"error",error:P.slice(0,1e3)}),t(`error removing worktree ${e.projectPath} (session ${e.id}): ${P}`)}}return t(`run ${o} cleanup: removed=${u} skippedDirty=${c} absent=${p} errored=${d}`),{runId:o,repoRoot:a,removed:u,skippedDirty:c,absent:p,errored:d,worktrees:s}}m(C,"processRunCleanup");export{C as a};
@@ -1 +1 @@
1
- import{b as l}from"./chunk-6QKI756T.js";import{a as p}from"./chunk-5RBLIVBF.js";import{h}from"./chunk-QAV4HW7D.js";import{a as c}from"./chunk-ZLLER3HP.js";async function g(t){if(!t.worktree?.create)return t;let{branch:e,baseRef:s}=t.worktree,n=await l({repoRoot:t.projectPath,branch:e,baseRef:s});return{...t,projectPath:n.path,gitBranch:n.branch}}c(g,"resolveWorktreeForLaunch");async function L(t,e){let{mirrorId:s,tool:n}=t,{config:r}=t,a=c(o=>e.logger.info(o),"log");if(e.job.attempts>1)throw new p(`process_launch is not safe to retry (attempt ${e.job.attempts}). Re-launch manually.`);r=await g(r),r.worktree?.create&&a(`Worktree resolved: ${r.projectPath} (branch ${r.gitBranch})`),a(`Launching ${n}...`);let{getLauncher:f}=await import("./dist-FAVALJ5C.js"),i=await f(n).launch(r);a(`Launch completed: sessionId=${i.sessionId}`);let u={...i,worktreePath:r.worktree?.create?r.projectPath:void 0,runId:r.runId};return await h(`/api/launch-jobs/${s}/state`,{result:u}).catch(o=>{a(`result persist failed: ${o instanceof Error?o.message:String(o)}`)}),u}c(L,"processLaunch");export{g as a,L as b};
1
+ import{b as l}from"./chunk-6QKI756T.js";import{a as p}from"./chunk-5RBLIVBF.js";import{h}from"./chunk-MPDSQALK.js";import{a as c}from"./chunk-ZLLER3HP.js";async function g(t){if(!t.worktree?.create)return t;let{branch:e,baseRef:s}=t.worktree,n=await l({repoRoot:t.projectPath,branch:e,baseRef:s});return{...t,projectPath:n.path,gitBranch:n.branch}}c(g,"resolveWorktreeForLaunch");async function L(t,e){let{mirrorId:s,tool:n}=t,{config:r}=t,a=c(o=>e.logger.info(o),"log");if(e.job.attempts>1)throw new p(`process_launch is not safe to retry (attempt ${e.job.attempts}). Re-launch manually.`);r=await g(r),r.worktree?.create&&a(`Worktree resolved: ${r.projectPath} (branch ${r.gitBranch})`),a(`Launching ${n}...`);let{getLauncher:f}=await import("./dist-FAVALJ5C.js"),i=await f(n).launch(r);a(`Launch completed: sessionId=${i.sessionId}`);let u={...i,worktreePath:r.worktree?.create?r.projectPath:void 0,runId:r.runId};return await h(`/api/launch-jobs/${s}/state`,{result:u}).catch(o=>{a(`result persist failed: ${o instanceof Error?o.message:String(o)}`)}),u}c(L,"processLaunch");export{g as a,L as b};
@@ -1,4 +1,4 @@
1
- import{a as R,g as v,h as T,j as I,m as C}from"./chunk-3QXRLIGC.js";import{e as d}from"./chunk-QWCEZEDO.js";import{d as g}from"./chunk-NTKO4H2K.js";import{e as _}from"./chunk-QAV4HW7D.js";import{g as m,l as k}from"./chunk-JZ5Z2BRO.js";import{a as i}from"./chunk-ZLLER3HP.js";import{execSync as j}from"node:child_process";import{existsSync as p,readFileSync as y}from"node:fs";import{homedir as f}from"node:os";import{join as a}from"node:path";var P=["install","auth","hooks","worker"],O=["judge"],M=[...P,...O];function $(){return{projectPath:process.cwd(),configDir:k()}}i($,"defaultContext");var A=a(f(),".mitmproxy","mitmproxy-ca-cert.pem");function S(e){if(!e)return"";if(e.length<=8)return"*".repeat(e.length);let t=e.slice(0,4),n=e.slice(-4);return`${t}${"*".repeat(Math.max(4,e.length-8))}${n}`}i(S,"maskToken");function te(e,t){let n=e===null?[]:e.replace(/\n$/,"").split(`
1
+ import{a as R,g as v,h as T,j as I,m as C}from"./chunk-3QXRLIGC.js";import{e as d}from"./chunk-QWCEZEDO.js";import{d as g}from"./chunk-NTKO4H2K.js";import{e as _}from"./chunk-MPDSQALK.js";import{g as m,l as k}from"./chunk-PZNWH4VQ.js";import{a as i}from"./chunk-ZLLER3HP.js";import{execSync as j}from"node:child_process";import{existsSync as p,readFileSync as y}from"node:fs";import{homedir as f}from"node:os";import{join as a}from"node:path";var P=["install","auth","hooks","worker"],O=["judge"],M=[...P,...O];function $(){return{projectPath:process.cwd(),configDir:k()}}i($,"defaultContext");var A=a(f(),".mitmproxy","mitmproxy-ca-cert.pem");function S(e){if(!e)return"";if(e.length<=8)return"*".repeat(e.length);let t=e.slice(0,4),n=e.slice(-4);return`${t}${"*".repeat(Math.max(4,e.length-8))}${n}`}i(S,"maskToken");function te(e,t){let n=e===null?[]:e.replace(/\n$/,"").split(`
2
2
  `),o=t===null?[]:t.replace(/\n$/,"").split(`
3
3
  `),s=[],u=Math.max(n.length,o.length);for(let c=0;c<u;c++){let l=n[c],r=o[c];l===r?s.push(` ${l}`):(l!==void 0&&s.push(`-${l}`),r!==void 0&&s.push(`+${r}`))}return s.join(`
4
4
  `)}i(te,"renderDiff");function x(e,t){let n=a(e,"env");if(!p(n))return null;try{let s=y(n,"utf-8").match(new RegExp(`^${t}=(.+)$`,"m"));return s?s[1]:null}catch{return null}}i(x,"readEnvValue");async function b(){if(!m())return!1;try{return(await Promise.race([_("/api/setup/status"),new Promise((t,n)=>setTimeout(()=>n(new Error("setup/status timeout")),2500))]))?.workerActive===!0}catch{return!1}}i(b,"workerActive");function E(e,t){let n=a(e,".claude",t),o={},s=null;if(p(n))try{s=y(n,"utf-8").replace(/\n$/,""),o=JSON.parse(s)}catch{o={}}return{settings:o,before:s}}i(E,"readProjectSettings");function D(e){let{settings:t,before:n}=E(e,"settings.local.json");return v(t),{before:n,after:JSON.stringify(t,null,2)}}i(D,"projectHooksSettings");function N(e){let{settings:t,before:n}=E(e,"settings.local.json"),o={...t.env??{}};return o.HTTPS_PROXY=`http://localhost:${d}`,o.NO_PROXY=I,o.NODE_EXTRA_CA_CERTS=A,{before:n,after:JSON.stringify({...t,env:o},null,2)}}i(N,"projectProxyEnvSettings");function U(e){let{settings:t,before:n}=E(e,"settings.json");if(n===null)return null;let{removed:o}=C(t,d);return o?{before:n,after:JSON.stringify(t,null,2)}:null}i(U,"projectSharedSettingsMigration");var Y=a(f(),"Library","LaunchAgents","com.rulemetric.worker.plist"),G=a(f(),".config","systemd","user","rulemetric-worker.service");function h(e){j(e,{stdio:"inherit"})}i(h,"runCommand");var L=[{id:"install",title:"Install the CLI",command:"npm install -g @rulemetric/cli",async detect(){return m()||await b()},async plan(){return{id:"install",title:"Install the CLI",command:"npm install -g @rulemetric/cli",artifacts:[{path:"npm install -g @rulemetric/cli",kind:"command",before:null,after:"rulemetric --version # verifies the binary is on PATH"}]}},async apply(){h("npm install -g @rulemetric/cli")}},{id:"auth",title:"Authenticate",command:"rulemetric auth login",async detect(){return m()},async plan(e){let t=a(e.configDir,"env"),n=null;if(p(t))try{n=X(y(t,"utf-8"))}catch{n="(unreadable)"}let o=x(e.configDir,"RULEMETRIC_ACCESS_TOKEN"),u=[`RULEMETRIC_ACCESS_TOKEN=${S(o||"<token-from-login>")}`],c=x(e.configDir,"RULEMETRIC_API_KEY");c&&u.push(`RULEMETRIC_API_KEY=${S(c)}`);let l=process.env.RULEMETRIC_API_URL;l&&u.push(`RULEMETRIC_API_URL=${l}`);let r=u.join(`
@@ -1,2 +1,2 @@
1
- import{a as v,b as u,e as y,g as d}from"../../chunk-YFQ4FOAS.js";import{a as h}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import"../../chunk-JZ5Z2BRO.js";import{a as p}from"../../chunk-ZLLER3HP.js";import{Args as k,Flags as o}from"@oclif/core";import{existsSync as T}from"node:fs";import{homedir as P}from"node:os";import{join as I}from"node:path";var A=I(P(),".gemini","antigravity-ide","brain"),g=class x extends h{static{p(this,"AntigravityBackfill")}static description="Backfill historical events from an Antigravity conversation transcript into a RuleMetric session. Useful for seeding a conversation that existed before hooks were installed \u2014 the live hook intentionally only captures forward.";static examples=["<%= config.bin %> antigravity backfill 26fd215d-f43b-4ea5-b177-dc2c0e696f97 --session 158db9aa-68ee-43fc-961b-f3a180578694","<%= config.bin %> antigravity backfill 26fd215d-f43b-4ea5-b177-dc2c0e696f97 --dry-run"];static args={conversationId:k.string({description:"Antigravity conversationId (UUID) \u2014 the directory name under ~/.gemini/antigravity-ide/brain/",required:!0})};static flags={session:o.string({char:"s",description:"RuleMetric session UUID to POST events into. If omitted, resolved from the hook tmp file ($TMPDIR/rulemetric/<conversationId>) \u2014 fails if neither is present."}),transcript:o.string({description:"Path to the transcript.jsonl file. Defaults to ~/.gemini/antigravity-ide/brain/<conversationId>/.system_generated/logs/transcript.jsonl"}),"after-step":o.integer({description:"Only emit records with step_index > this value. Default: read from existing state file, else -1 (everything)."}),limit:o.integer({description:"Cap on the number of records to process this run."}),"dry-run":o.boolean({default:!1,description:"Classify records without POSTing. Reports counts only."}),"save-state":o.boolean({default:!0,allowNo:!0,description:"After backfill, persist the highest step_index so the live hook resumes from there."})};async run(){let{args:b,flags:e}=await this.parse(x),t=b.conversationId;d.loadEnvFile(),process.env.RULEMETRIC_API_URL||this.error("RULEMETRIC_API_URL is not set. Configure it via env or ~/.config/rulemetric/env.");let l=e.transcript??I(A,t,".system_generated","logs","transcript.jsonl");T(l)||this.error(`Transcript not found: ${l}`);let m=e.session??d.resolveRwSessionId(t);m||this.error(`No RuleMetric session resolved. Pass --session <uuid>, or run the Antigravity hook at least once so $TMPDIR/rulemetric/${t} is populated.`);let n=e["after-step"];n===void 0&&(n=d.load(t)?.lastStepIdx??-1);let i=v(l,n);e.limit!==void 0&&i.length>e.limit&&(i=i.slice(0,e.limit));let R=u(l);if(this.log(`Conversation ${t}: transcript max step = ${R}, after-step = ${n}, records to process = ${i.length}`),i.length===0){this.log("Nothing to backfill.");return}if(e["dry-run"]){let r=0,a=0,c={};for(let S of i){let f=(await import("../../lib/antigravity-transcript.js")).classifyRecord(S,0);f?(r++,c[f.eventType]=(c[f.eventType]??0)+1):a++}this.log(`Dry run: would emit ${r}, skip ${a}. By eventType: ${JSON.stringify(c)}`);return}let w=Date.now(),s=await y(i,m,t,n,{onProgress:p(({attempted:r,total:a})=>{(r%100===0||r===a)&&process.stderr.write(` \u2026${r}/${a}
1
+ import{a as v,b as u,e as y,g as d}from"../../chunk-FM4LTGMI.js";import{a as h}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import"../../chunk-PZNWH4VQ.js";import{a as p}from"../../chunk-ZLLER3HP.js";import{Args as k,Flags as o}from"@oclif/core";import{existsSync as T}from"node:fs";import{homedir as P}from"node:os";import{join as I}from"node:path";var A=I(P(),".gemini","antigravity-ide","brain"),g=class x extends h{static{p(this,"AntigravityBackfill")}static description="Backfill historical events from an Antigravity conversation transcript into a RuleMetric session. Useful for seeding a conversation that existed before hooks were installed \u2014 the live hook intentionally only captures forward.";static examples=["<%= config.bin %> antigravity backfill 26fd215d-f43b-4ea5-b177-dc2c0e696f97 --session 158db9aa-68ee-43fc-961b-f3a180578694","<%= config.bin %> antigravity backfill 26fd215d-f43b-4ea5-b177-dc2c0e696f97 --dry-run"];static args={conversationId:k.string({description:"Antigravity conversationId (UUID) \u2014 the directory name under ~/.gemini/antigravity-ide/brain/",required:!0})};static flags={session:o.string({char:"s",description:"RuleMetric session UUID to POST events into. If omitted, resolved from the hook tmp file ($TMPDIR/rulemetric/<conversationId>) \u2014 fails if neither is present."}),transcript:o.string({description:"Path to the transcript.jsonl file. Defaults to ~/.gemini/antigravity-ide/brain/<conversationId>/.system_generated/logs/transcript.jsonl"}),"after-step":o.integer({description:"Only emit records with step_index > this value. Default: read from existing state file, else -1 (everything)."}),limit:o.integer({description:"Cap on the number of records to process this run."}),"dry-run":o.boolean({default:!1,description:"Classify records without POSTing. Reports counts only."}),"save-state":o.boolean({default:!0,allowNo:!0,description:"After backfill, persist the highest step_index so the live hook resumes from there."})};async run(){let{args:b,flags:e}=await this.parse(x),t=b.conversationId;d.loadEnvFile(),process.env.RULEMETRIC_API_URL||this.error("RULEMETRIC_API_URL is not set. Configure it via env or ~/.config/rulemetric/env.");let l=e.transcript??I(A,t,".system_generated","logs","transcript.jsonl");T(l)||this.error(`Transcript not found: ${l}`);let m=e.session??d.resolveRwSessionId(t);m||this.error(`No RuleMetric session resolved. Pass --session <uuid>, or run the Antigravity hook at least once so $TMPDIR/rulemetric/${t} is populated.`);let n=e["after-step"];n===void 0&&(n=d.load(t)?.lastStepIdx??-1);let i=v(l,n);e.limit!==void 0&&i.length>e.limit&&(i=i.slice(0,e.limit));let R=u(l);if(this.log(`Conversation ${t}: transcript max step = ${R}, after-step = ${n}, records to process = ${i.length}`),i.length===0){this.log("Nothing to backfill.");return}if(e["dry-run"]){let r=0,a=0,c={};for(let S of i){let f=(await import("../../lib/antigravity-transcript.js")).classifyRecord(S,0);f?(r++,c[f.eventType]=(c[f.eventType]??0)+1):a++}this.log(`Dry run: would emit ${r}, skip ${a}. By eventType: ${JSON.stringify(c)}`);return}let w=Date.now(),s=await y(i,m,t,n,{onProgress:p(({attempted:r,total:a})=>{(r%100===0||r===a)&&process.stderr.write(` \u2026${r}/${a}
2
2
  `)},"onProgress")}),$=((Date.now()-w)/1e3).toFixed(1);this.log(`Backfill complete in ${$}s. attempted=${s.attempted} emitted=${s.emitted} skipped=${s.skipped} failed=${s.failed} highestStepIdx=${s.highestStepIdx}`),e["save-state"]?(d.save(t,{lastStepIdx:s.highestStepIdx}),this.log(`State saved \u2192 live hook will resume from step_index > ${s.highestStepIdx}.`)):this.log("State NOT saved (--no-save-state). Live hook will re-emit any new records from after-step.")}};export{g as default};
@@ -1 +1 @@
1
- import{a as n}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import{f as r}from"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import{i as o,l as s}from"../../chunk-JZ5Z2BRO.js";import{a}from"../../chunk-ZLLER3HP.js";import*as c from"node:path";import{Flags as l}from"@oclif/core";var t=class g extends n{static{a(this,"AuthCreateKey")}static description="Create a long-lived API key for CLI and proxy authentication";static examples=['<%= config.bin %> auth create-key --name "laptop"','<%= config.bin %> auth create-key --name "ci token" --no-save'];static flags={name:l.string({char:"n",description:"Name for this key",required:!0}),save:l.boolean({char:"s",description:"Save key to ~/.config/rulemetric/env for hooks/proxy",default:!0,allowNo:!0})};async run(){let{flags:i}=await this.parse(g),e=await r("/api/auth/api-keys",{name:i.name});this.log(""),this.log("API key created successfully:"),this.log(""),this.log(` Name: ${e.name}`),this.log(` Key: ${e.key}`),this.log(` Prefix: ${e.keyPrefix}`),this.log(""),this.warn("Save this key now \u2014 it will not be shown again."),i.save&&(o(e.key,process.env.RULEMETRIC_API_URL),this.log(""),this.log(`Key saved to ${c.join(s(),"env")} (RULEMETRIC_API_KEY)`),this.log("Hooks and proxy will use this key automatically."))}};export{t as default};
1
+ import{a as n}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import{f as r}from"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import{i as o,l as s}from"../../chunk-PZNWH4VQ.js";import{a}from"../../chunk-ZLLER3HP.js";import*as c from"node:path";import{Flags as l}from"@oclif/core";var t=class g extends n{static{a(this,"AuthCreateKey")}static description="Create a long-lived API key for CLI and proxy authentication";static examples=['<%= config.bin %> auth create-key --name "laptop"','<%= config.bin %> auth create-key --name "ci token" --no-save'];static flags={name:l.string({char:"n",description:"Name for this key",required:!0}),save:l.boolean({char:"s",description:"Save key to ~/.config/rulemetric/env for hooks/proxy",default:!0,allowNo:!0})};async run(){let{flags:i}=await this.parse(g),e=await r("/api/auth/api-keys",{name:i.name});this.log(""),this.log("API key created successfully:"),this.log(""),this.log(` Name: ${e.name}`),this.log(` Key: ${e.key}`),this.log(` Prefix: ${e.keyPrefix}`),this.log(""),this.warn("Save this key now \u2014 it will not be shown again."),i.save&&(o(e.key,process.env.RULEMETRIC_API_URL),this.log(""),this.log(`Key saved to ${c.join(s(),"env")} (RULEMETRIC_API_KEY)`),this.log("Hooks and proxy will use this key automatically."))}};export{t as default};
@@ -1,4 +1,4 @@
1
- import{a as f}from"../../chunk-BPP7AEFW.js";import{a as w}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import{c}from"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import{b as n}from"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import{b as r,d as a}from"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import{b as m,d,h as u,i as g}from"../../chunk-JZ5Z2BRO.js";import{a as l}from"../../chunk-ZLLER3HP.js";import{Flags as p}from"@oclif/core";var h=class y extends w{static{l(this,"AuthLogin")}static description="Log in to RuleMetric";static examples=["<%= config.bin %> auth login","<%= config.bin %> auth login -e user@example.com"];static flags={email:p.string({char:"e",description:"Email address"}),password:p.string({char:"p",description:"Password (for non-interactive use)"}),"api-key":p.string({description:"Authenticate with an API key from https://rulemetric.com/connect (required for Google/GitHub sign-ins, which have no password)",exclusive:["password"]})};async run(){let{flags:s}=await this.parse(y);if(s["api-key"]){await this.loginWithApiKey(s["api-key"]);return}let e=s.email,t=s.password;if(!e||!t){process.stdin.isTTY||this.error("Missing credentials in a non-interactive shell. Pass --email/-e and --password/-p, or set RULEMETRIC_API_KEY (create a key at https://rulemetric.com/connect).");let{input:o,password:k}=await import("@inquirer/prompts");this.log("Signed up with Google or GitHub? You have no password \u2014 press Ctrl-C and run:"),this.log(" rulemetric auth login --api-key <key> (create one at https://rulemetric.com/connect)"),this.log(""),e||(e=await o({message:"Email:"})),t||(t=await k({message:"Password:"}))}let i;try{i=await a("/auth/login",{method:"POST",body:{email:e,password:t},timeoutMs:2e4})}catch(o){throw o instanceof r&&o.statusCode===401&&this.error(`Invalid email or password.
1
+ import{a as f}from"../../chunk-R4SSIFKY.js";import{a as w}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import{c}from"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import{b as n}from"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import{b as r,d as a}from"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import{b as m,d,h as u,i as g}from"../../chunk-PZNWH4VQ.js";import{a as l}from"../../chunk-ZLLER3HP.js";import{Flags as p}from"@oclif/core";var h=class y extends w{static{l(this,"AuthLogin")}static description="Log in to RuleMetric";static examples=["<%= config.bin %> auth login","<%= config.bin %> auth login -e user@example.com"];static flags={email:p.string({char:"e",description:"Email address"}),password:p.string({char:"p",description:"Password (for non-interactive use)"}),"api-key":p.string({description:"Authenticate with an API key from https://rulemetric.com/connect (required for Google/GitHub sign-ins, which have no password)",exclusive:["password"]})};async run(){let{flags:s}=await this.parse(y);if(s["api-key"]){await this.loginWithApiKey(s["api-key"]);return}let e=s.email,t=s.password;if(!e||!t){process.stdin.isTTY||this.error("Missing credentials in a non-interactive shell. Pass --email/-e and --password/-p, or set RULEMETRIC_API_KEY (create a key at https://rulemetric.com/connect).");let{input:o,password:k}=await import("@inquirer/prompts");this.log("Signed up with Google or GitHub? You have no password \u2014 press Ctrl-C and run:"),this.log(" rulemetric auth login --api-key <key> (create one at https://rulemetric.com/connect)"),this.log(""),e||(e=await o({message:"Email:"})),t||(t=await k({message:"Password:"}))}let i;try{i=await a("/auth/login",{method:"POST",body:{email:e,password:t},timeoutMs:2e4})}catch(o){throw o instanceof r&&o.statusCode===401&&this.error(`Invalid email or password.
2
2
 
3
3
  If you signed up with Google or GitHub, you have no password \u2014 that is why this cannot work. Create an API key at https://rulemetric.com/connect, then run:
4
4
  rulemetric auth login --api-key <key>`),o}let v=i.expiresAt??new Date(Date.now()+3600*1e3).toISOString();d({accessToken:i.accessToken,refreshToken:i.refreshToken,expiresAt:v,email:i.email}),u(i.accessToken,process.env.RULEMETRIC_API_URL),await n(),await f(this.log.bind(this),this.warn.bind(this),this.config.version),c("auth_login",{},this.config.version),this.log(`Logged in as ${i.email}`)}async loginWithApiKey(s){let e=s.trim();e||this.error("Empty --api-key. Create one at https://rulemetric.com/connect"),process.env.RULEMETRIC_API_KEY=e;try{await a("/api/setup/status",{timeoutMs:2e4})}catch(t){throw delete process.env.RULEMETRIC_API_KEY,t instanceof r&&(t.statusCode===401||t.statusCode===403)&&this.error("That API key was rejected. Check you copied it whole (it is shown only once at creation) or mint a new one at https://rulemetric.com/connect"),t}g(e,process.env.RULEMETRIC_API_URL),m(),await n(),c("auth_login",{method:"api_key"},this.config.version),this.log(`Authenticated with API key ${e.slice(0,11)}...`),this.log("Verify any time with: rulemetric auth status")}};export{h as default};
@@ -1 +1 @@
1
- import{a as s}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import{f as i,j as r}from"../../chunk-JZ5Z2BRO.js";import{a as o}from"../../chunk-ZLLER3HP.js";var e=class t extends s{static{o(this,"AuthLogout")}static description="Log out of RuleMetric";static examples=["<%= config.bin %> auth logout"];async run(){await this.parse(t),i(),r(),this.log("Logged out successfully.")}};export{e as default};
1
+ import{a as s}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import{f as i,j as r}from"../../chunk-PZNWH4VQ.js";import{a as o}from"../../chunk-ZLLER3HP.js";var e=class t extends s{static{o(this,"AuthLogout")}static description="Log out of RuleMetric";static examples=["<%= config.bin %> auth logout"];async run(){await this.parse(t),i(),r(),this.log("Logged out successfully.")}};export{e as default};
@@ -1,4 +1,4 @@
1
- import{a as k}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import{e as n,i as c}from"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import"../../chunk-JZ5Z2BRO.js";import{a as s}from"../../chunk-ZLLER3HP.js";import{Args as y}from"@oclif/core";var a=class m extends k{static{s(this,"AuthRevokeKey")}static description="Revoke an API key (run with no argument to list active keys)";static examples=["<%= config.bin %> auth revoke-key","<%= config.bin %> auth revoke-key rm_abc12345",'<%= config.bin %> auth revoke-key "my-laptop (auto)"'];static args={id:y.string({description:"API key ID, prefix (rm_xxxxxxxx), or name"})};async run(){let{args:o}=await this.parse(m),r=(await n("/api/auth/api-keys")).filter(e=>!e.revokedAt);if(!o.id){if(r.length===0){this.log("No active API keys.");return}this.log(`Active API keys \u2014 pass an id, prefix, or name to revoke one:
1
+ import{a as k}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import{e as n,i as c}from"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import"../../chunk-PZNWH4VQ.js";import{a as s}from"../../chunk-ZLLER3HP.js";import{Args as y}from"@oclif/core";var a=class m extends k{static{s(this,"AuthRevokeKey")}static description="Revoke an API key (run with no argument to list active keys)";static examples=["<%= config.bin %> auth revoke-key","<%= config.bin %> auth revoke-key rm_abc12345",'<%= config.bin %> auth revoke-key "my-laptop (auto)"'];static args={id:y.string({description:"API key ID, prefix (rm_xxxxxxxx), or name"})};async run(){let{args:o}=await this.parse(m),r=(await n("/api/auth/api-keys")).filter(e=>!e.revokedAt);if(!o.id){if(r.length===0){this.log("No active API keys.");return}this.log(`Active API keys \u2014 pass an id, prefix, or name to revoke one:
2
2
  `);for(let e of r)this.log(` ${e.id} ${e.keyPrefix}... ${e.name}`);return}let i=o.id,t=r.filter(e=>e.id===i||e.name===i||i.startsWith("rm_")&&i.startsWith(e.keyPrefix));t.length===0&&this.error(`No active API key matches "${i}". Run \`rulemetric auth revoke-key\` with no argument to list keys.`),t.length>1&&this.error(`"${i}" matches ${t.length} keys \u2014 use the exact key ID:
3
3
  `+t.map(e=>` ${e.id} ${e.keyPrefix}... ${e.name}`).join(`
4
4
  `)),await c(`/api/auth/api-keys/${t[0].id}`),this.log(`API key ${t[0].keyPrefix}... ("${t[0].name}") revoked.`)}};export{a as default};
@@ -1 +1 @@
1
- import{a as g}from"../../chunk-BPP7AEFW.js";import{a as h}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import{c as d}from"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import{b as l}from"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import{b as m,d as p}from"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import{d as n,h as c}from"../../chunk-JZ5Z2BRO.js";import{a as o}from"../../chunk-ZLLER3HP.js";import{Flags as u}from"@oclif/core";var t=class f extends h{static{o(this,"AuthSignup")}static description="Create a RuleMetric account from the CLI";static examples=["<%= config.bin %> auth signup","<%= config.bin %> auth signup -e user@example.com"];static flags={email:u.string({char:"e",description:"Email address"}),password:u.string({char:"p",description:"Password (min 8 chars; for non-interactive use)"})};async run(){let{flags:a}=await this.parse(f),i=a.email,r=a.password;if(!i||!r){process.stdin.isTTY||this.error("Missing credentials in a non-interactive shell. Pass --email/-e and --password/-p.");let{input:s,password:v}=await import("@inquirer/prompts");i||(i=await s({message:"Email:"})),r||(r=await v({message:"Password (min 8 chars):"}))}let e;try{e=await p("/auth/signup",{method:"POST",body:{email:i,password:r},timeoutMs:2e4})}catch(s){throw s instanceof m&&s.statusCode===409&&this.error(`An account with ${i} already exists. Run: rulemetric auth login -e ${i}`),s}if(e.confirmationRequired||!e.accessToken||!e.refreshToken){this.log(`Account created for ${e.email}.`),this.log("Check your email and click the confirmation link, then run:"),this.log(` rulemetric auth login -e ${e.email}`);return}let w=e.expiresAt??new Date(Date.now()+3600*1e3).toISOString();n({accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:w,email:e.email}),c(e.accessToken,process.env.RULEMETRIC_API_URL),await l(),await g(this.log.bind(this),this.warn.bind(this),this.config.version),d("auth_signup",{},this.config.version),this.log(`Signed up and logged in as ${e.email}`)}};export{t as default};
1
+ import{a as g}from"../../chunk-R4SSIFKY.js";import{a as h}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import{c as d}from"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import{b as l}from"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import{b as m,d as p}from"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import{d as n,h as c}from"../../chunk-PZNWH4VQ.js";import{a as o}from"../../chunk-ZLLER3HP.js";import{Flags as u}from"@oclif/core";var t=class f extends h{static{o(this,"AuthSignup")}static description="Create a RuleMetric account from the CLI";static examples=["<%= config.bin %> auth signup","<%= config.bin %> auth signup -e user@example.com"];static flags={email:u.string({char:"e",description:"Email address"}),password:u.string({char:"p",description:"Password (min 8 chars; for non-interactive use)"})};async run(){let{flags:a}=await this.parse(f),i=a.email,r=a.password;if(!i||!r){process.stdin.isTTY||this.error("Missing credentials in a non-interactive shell. Pass --email/-e and --password/-p.");let{input:s,password:v}=await import("@inquirer/prompts");i||(i=await s({message:"Email:"})),r||(r=await v({message:"Password (min 8 chars):"}))}let e;try{e=await p("/auth/signup",{method:"POST",body:{email:i,password:r},timeoutMs:2e4})}catch(s){throw s instanceof m&&s.statusCode===409&&this.error(`An account with ${i} already exists. Run: rulemetric auth login -e ${i}`),s}if(e.confirmationRequired||!e.accessToken||!e.refreshToken){this.log(`Account created for ${e.email}.`),this.log("Check your email and click the confirmation link, then run:"),this.log(` rulemetric auth login -e ${e.email}`);return}let w=e.expiresAt??new Date(Date.now()+3600*1e3).toISOString();n({accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:w,email:e.email}),c(e.accessToken,process.env.RULEMETRIC_API_URL),await l(),await g(this.log.bind(this),this.warn.bind(this),this.config.version),d("auth_signup",{},this.config.version),this.log(`Signed up and logged in as ${e.email}`)}};export{t as default};
@@ -1 +1 @@
1
- import{a as c}from"../../chunk-W2MV25SB.js";import{a as g}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import{a,e as l,l as t}from"../../chunk-JZ5Z2BRO.js";import{a as r}from"../../chunk-ZLLER3HP.js";import*as u from"node:path";var o=class h extends g{static{r(this,"AuthStatus")}static description="Show current authentication status";static examples=["<%= config.bin %> auth status"];async run(){await this.parse(h);let e=l(),i=process.env.RULEMETRIC_API_KEY,s=a().apiKey;if(i||s){let m=i||s,p=i?"RULEMETRIC_API_KEY env var":u.join(t(),"env");this.log(`Authenticated via API key ${m.slice(0,11)}... (${p})`),e&&this.log(`Logged in as: ${e.email}`),this.log(`Config: ${t()}`);return}if(!e){this.log("Not logged in. Run `rulemetric auth login` to authenticate.");return}let n=new Date(e.expiresAt).getTime();if(Number.isNaN(n)||Date.now()>=n){this.log("Session expired. Run `rulemetric auth login` to re-authenticate.");return}this.log(`Logged in as: ${e.email}`),this.log(`Session expires: ${c(e.expiresAt)}`),this.log(`Config: ${t()}`)}};export{o as default};
1
+ import{a as c}from"../../chunk-W2MV25SB.js";import{a as g}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import{a,e as l,l as t}from"../../chunk-PZNWH4VQ.js";import{a as r}from"../../chunk-ZLLER3HP.js";import*as u from"node:path";var o=class h extends g{static{r(this,"AuthStatus")}static description="Show current authentication status";static examples=["<%= config.bin %> auth status"];async run(){await this.parse(h);let e=l(),i=process.env.RULEMETRIC_API_KEY,s=a().apiKey;if(i||s){let m=i||s,p=i?"RULEMETRIC_API_KEY env var":u.join(t(),"env");this.log(`Authenticated via API key ${m.slice(0,11)}... (${p})`),e&&this.log(`Logged in as: ${e.email}`),this.log(`Config: ${t()}`);return}if(!e){this.log("Not logged in. Run `rulemetric auth login` to authenticate.");return}let n=new Date(e.expiresAt).getTime();if(Number.isNaN(n)||Date.now()>=n){this.log("Session expired. Run `rulemetric auth login` to re-authenticate.");return}this.log(`Logged in as: ${e.email}`),this.log(`Session expires: ${c(e.expiresAt)}`),this.log(`Config: ${t()}`)}};export{o as default};
@@ -1,2 +1,2 @@
1
- import{a as f,b as k,c as S,d as x,e as R,f as n,g as y}from"../../chunk-SHYP27B7.js";import{b as C,c as w,f as v,g as b}from"../../chunk-QXPYGN7I.js";import{a as u}from"../../chunk-KHWG7ZG4.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-UUZB4IKU.js";import"../../chunk-EQHKCGSX.js";import"../../chunk-VA5DPQB4.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-QAV4HW7D.js";import"../../chunk-3PUOJ6F2.js";import{l as m}from"../../chunk-JZ5Z2BRO.js";import{a as h}from"../../chunk-ZLLER3HP.js";import{existsSync as O}from"node:fs";import{Flags as c}from"@oclif/core";var g=class E extends u{static{h(this,"CaptureScope")}static description="Show or set which projects RuleMetric captures \u2014 the Codex sweep and hook-driven sessions each have their own scope";static examples=["<%= config.bin %> <%= command.id %>","<%= config.bin %> <%= command.id %> --add ~/work/client-a --add ~/work/client-b","<%= config.bin %> <%= command.id %> --tool hooks --add ~/work/client-a","<%= config.bin %> <%= command.id %> --tool hooks --off","<%= config.bin %> <%= command.id %> --remove ~/work/client-a","<%= config.bin %> <%= command.id %> --off","<%= config.bin %> <%= command.id %> --all"];static flags={tool:c.string({description:'Which capture path to edit: "codex" (the worker transcript sweep, the default) or "hooks" (Claude Code / Cursor / Copilot / Antigravity hook sessions).',options:["codex","hooks"],default:"codex"}),add:c.string({description:"Capture sessions under this path (repeatable). Implies an allowlist.",multiple:!0}),remove:c.string({description:"Stop capturing under this path (repeatable).",multiple:!0}),off:c.boolean({description:"Turn this capture path off entirely.",exclusive:["all"]}),all:c.boolean({description:"Capture every project (the default).",exclusive:["off"]}),clear:c.boolean({description:"Remove this scope, restoring the default."})};async run(){let{flags:o}=await this.parse(E),s=m(),d=f(s);if(!((o.add?.length??0)>0||(o.remove?.length??0)>0||o.off||o.all||o.clear)){await this.show(s,d);return}for(let t of[...o.add??[],...o.remove??[]])R(t)||this.error(`Not an absolute path: ${t}
1
+ import{a as f,b as k,c as S,d as x,e as R,f as n,g as y}from"../../chunk-SHYP27B7.js";import{b as C,c as w,f as v,g as b}from"../../chunk-QXPYGN7I.js";import{a as u}from"../../chunk-FAOSXPRO.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-CLCRZWAG.js";import"../../chunk-RE7DDQ3O.js";import"../../chunk-SV7FDAKW.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-MPDSQALK.js";import"../../chunk-E4U6AOTM.js";import{l as m}from"../../chunk-PZNWH4VQ.js";import{a as h}from"../../chunk-ZLLER3HP.js";import{existsSync as O}from"node:fs";import{Flags as c}from"@oclif/core";var g=class E extends u{static{h(this,"CaptureScope")}static description="Show or set which projects RuleMetric captures \u2014 the Codex sweep and hook-driven sessions each have their own scope";static examples=["<%= config.bin %> <%= command.id %>","<%= config.bin %> <%= command.id %> --add ~/work/client-a --add ~/work/client-b","<%= config.bin %> <%= command.id %> --tool hooks --add ~/work/client-a","<%= config.bin %> <%= command.id %> --tool hooks --off","<%= config.bin %> <%= command.id %> --remove ~/work/client-a","<%= config.bin %> <%= command.id %> --off","<%= config.bin %> <%= command.id %> --all"];static flags={tool:c.string({description:'Which capture path to edit: "codex" (the worker transcript sweep, the default) or "hooks" (Claude Code / Cursor / Copilot / Antigravity hook sessions).',options:["codex","hooks"],default:"codex"}),add:c.string({description:"Capture sessions under this path (repeatable). Implies an allowlist.",multiple:!0}),remove:c.string({description:"Stop capturing under this path (repeatable).",multiple:!0}),off:c.boolean({description:"Turn this capture path off entirely.",exclusive:["all"]}),all:c.boolean({description:"Capture every project (the default).",exclusive:["off"]}),clear:c.boolean({description:"Remove this scope, restoring the default."})};async run(){let{flags:o}=await this.parse(E),s=m(),d=f(s);if(!((o.add?.length??0)>0||(o.remove?.length??0)>0||o.off||o.all||o.clear)){await this.show(s,d);return}for(let t of[...o.add??[],...o.remove??[]])R(t)||this.error(`Not an absolute path: ${t}
2
2
  Use an absolute path or ~/\u2026 \u2014 relative paths cannot be matched against a session's cwd.`);for(let t of o.add??[]){let a=x(t);O(a)||this.warn(`${a} does not exist yet \u2014 added anyway, but nothing will match until it does.`)}let e;try{e=k(s)}catch(t){o.clear||this.error(t instanceof Error?t.message:String(t));let a=y(s);this.warn(`${f(s)} was not valid JSON \u2014 saved it to ${a} and starting fresh.`),e={}}let i=o.tool??"codex",r=void 0,l=!1;if(o.clear&&({config:e}=n(e,{op:"clear"},r,i)),o.off&&({config:e}=n(e,{op:"mode",mode:"off"},r,i)),o.all&&({config:e}=n(e,{op:"mode",mode:"all"},r,i)),o.remove?.length){let t=n(e,{op:"remove",roots:o.remove},r,i);e=t.config,l=t.emptiedToOff}o.add?.length&&({config:e}=n(e,{op:"add",roots:o.add},r,i)),S(s,e),l&&(this.log(`Removed the last root \u2014 ${i==="hooks"?"hook":"Codex"} capture is now OFF rather than silently capturing everything.`),this.log("Use --all to go back to capturing every project.")),await this.show(s,d),this.log(""),this.log(i==="hooks"?"Takes effect on the next hook fire. No restart needed.":"Takes effect on the next sweep (within ~30s). No restart needed.")}async show(o,s){let d=await C({configDir:o}),p=await w({configDir:o}),e=h((i,r,l,t)=>{if(this.log(`${i}: ${l}`),r.roots.length)for(let a of r.roots)this.log(` \u2022 ${a}`);r.error&&(this.log(" This scope is FAILING CLOSED \u2014 nothing is being captured on this path."),this.log(` Fix the file, or run \`rulemetric capture scope ${i==="Hook capture"?"--tool hooks ":""}--clear\` to start over.`)),r.source==="env"&&this.log(` Set by environment variable, which outranks the config file (${t}).`)},"print");e("Codex capture",d,v(d),"RULEMETRIC_CODEX_CAPTURE / RULEMETRIC_CODEX_ROOTS"),e("Hook capture",p,b(p),"RULEMETRIC_HOOKS_CAPTURE / RULEMETRIC_HOOKS_ROOTS"),this.log(`Config: ${s}`)}};export{g as default};