@rulemetric/cli 0.7.30 → 0.7.32

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 (95) hide show
  1. package/dist/chunk-3DLVY7LD.js +1 -0
  2. package/dist/{chunk-CS2OQ3GC.js → chunk-3FJT6LL4.js} +1 -1
  3. package/dist/{chunk-UUMW6X2W.js → chunk-3VYV6ZYB.js} +1 -1
  4. package/dist/{chunk-DUP232AH.js → chunk-5W55CRBJ.js} +1 -1
  5. package/dist/{chunk-MDPN46EY.js → chunk-6QKI756T.js} +1 -1
  6. package/dist/{chunk-KAWNGQS2.js → chunk-7AZKPX2J.js} +1 -1
  7. package/dist/{chunk-35ZDT2VL.js → chunk-7W6KET2A.js} +8 -8
  8. package/dist/{chunk-ULRVMH7O.js → chunk-AIEM6VXO.js} +1 -1
  9. package/dist/{chunk-ZW5TAV3L.js → chunk-BSJBNOJT.js} +1 -1
  10. package/dist/{chunk-PRDYXO6Z.js → chunk-BZUIMHHT.js} +2 -2
  11. package/dist/{chunk-JAPCCEKF.js → chunk-CYKELSHS.js} +1 -1
  12. package/dist/{chunk-M4YF7YO7.js → chunk-DAGDGAPU.js} +1 -1
  13. package/dist/chunk-DTMLVFNM.js +1 -0
  14. package/dist/{chunk-XA4KSQEC.js → chunk-G6XGDHGC.js} +1 -1
  15. package/dist/chunk-JEBHSV2M.js +5 -0
  16. package/dist/chunk-JGYCLDYF.js +1 -0
  17. package/dist/chunk-JR4CWY3J.js +1 -0
  18. package/dist/{chunk-MSTF7A7D.js → chunk-L5ORQB25.js} +1 -1
  19. package/dist/{chunk-4O7MJUPH.js → chunk-LETTPEG4.js} +1 -1
  20. package/dist/{chunk-T4P2NV3P.js → chunk-LEXVC7VH.js} +1 -1
  21. package/dist/chunk-MODFTCZY.js +6 -0
  22. package/dist/{chunk-3BVHPQZW.js → chunk-OPUI7CM2.js} +1 -1
  23. package/dist/{chunk-CBP7QZAN.js → chunk-OVZZUI33.js} +1 -1
  24. package/dist/{chunk-HL755A5U.js → chunk-OZQV5CDT.js} +1 -1
  25. package/dist/chunk-Q76LGSIU.js +24 -0
  26. package/dist/{chunk-WYF5BIQW.js → chunk-QH7PCQHM.js} +1 -1
  27. package/dist/{chunk-DO3KHK2X.js → chunk-UR6GZGFK.js} +1 -1
  28. package/dist/{chunk-K25S2MGU.js → chunk-V5MJ4ICC.js} +1 -1
  29. package/dist/chunk-VLXCQ2DC.js +31 -0
  30. package/dist/{chunk-BUWWFHGO.js → chunk-W2MOTOQE.js} +1 -1
  31. package/dist/{chunk-6UTJGOBA.js → chunk-WEF5LPGS.js} +1 -1
  32. package/dist/chunk-WKXTY5AM.js +1 -0
  33. package/dist/{chunk-OSIP6FUD.js → chunk-ZAWAPLIE.js} +1 -1
  34. package/dist/chunk-ZERPMWRT.js +8 -0
  35. package/dist/{chunk-QQ2UPNBC.js → chunk-ZWKKFAIX.js} +1 -1
  36. package/dist/commands/auth/login.js +4 -1
  37. package/dist/commands/diagnostics.js +1 -1
  38. package/dist/commands/evals/agent.js +1 -1
  39. package/dist/commands/evals/auto-run.js +1 -1
  40. package/dist/commands/evals/benchmark.js +1 -1
  41. package/dist/commands/evals/optimize.js +1 -1
  42. package/dist/commands/evals/refine-cases.js +1 -1
  43. package/dist/commands/evals/run.js +1 -1
  44. package/dist/commands/evals/validate-judge.js +1 -1
  45. package/dist/commands/gateway/ensure.js +1 -1
  46. package/dist/commands/hooks/install.js +1 -1
  47. package/dist/commands/hooks/uninstall.js +1 -1
  48. package/dist/commands/sessions/list.js +1 -1
  49. package/dist/commands/setup.js +1 -1
  50. package/dist/dashboard/Dashboard.js +1 -1
  51. package/dist/dashboard/data.js +1 -1
  52. package/dist/{dist-BC6GMBXV.js → dist-FAVALJ5C.js} +1 -1
  53. package/dist/lib/agent-loop.js +1 -1
  54. package/dist/lib/codex-exec.js +1 -1
  55. package/dist/lib/editor-proxy-pins.js +1 -1
  56. package/dist/lib/eval-benchmark.js +1 -1
  57. package/dist/lib/eval-candidate-run.js +1 -0
  58. package/dist/lib/eval-case-generator.js +1 -1
  59. package/dist/lib/eval-conversation-handler.js +1 -1
  60. package/dist/lib/eval-grader.js +1 -1
  61. package/dist/lib/eval-run-batch.js +1 -1
  62. package/dist/lib/handlers/cron-eval-autorun.js +1 -1
  63. package/dist/lib/handlers/cron-instruction-evolution.js +1 -0
  64. package/dist/lib/handlers/cron-refresh-pricing.js +1 -1
  65. package/dist/lib/handlers/cron-suggest-instructions.js +1 -1
  66. package/dist/lib/handlers/distill-memories.js +1 -1
  67. package/dist/lib/handlers/process-announcement.js +1 -1
  68. package/dist/lib/handlers/process-changelog.js +1 -1
  69. package/dist/lib/handlers/process-conversation.js +1 -1
  70. package/dist/lib/handlers/process-eval.js +1 -1
  71. package/dist/lib/handlers/process-insights.js +1 -1
  72. package/dist/lib/handlers/process-judge-review.js +1 -1
  73. package/dist/lib/handlers/process-launch.js +1 -1
  74. package/dist/lib/handlers/process-memory-ab.js +1 -1
  75. package/dist/lib/handlers/process-run-cleanup.js +1 -1
  76. package/dist/lib/handlers/process-session-goal.js +1 -1
  77. package/dist/lib/hooks-config.js +1 -1
  78. package/dist/lib/instruction-proposer.js +1 -0
  79. package/dist/lib/judge-review-runner.js +1 -1
  80. package/dist/lib/llm-client.js +1 -1
  81. package/dist/lib/manual-tasks.js +1 -1
  82. package/dist/lib/optimize-compare.js +1 -1
  83. package/dist/lib/reviewer-detect.js +1 -1
  84. package/dist/lib/setup-steps.js +1 -1
  85. package/dist/lib/worktree.js +1 -1
  86. package/oclif.manifest.json +14 -3
  87. package/package.json +7 -7
  88. package/dist/chunk-2JRDG4LJ.js +0 -31
  89. package/dist/chunk-35ST2BX7.js +0 -5
  90. package/dist/chunk-4HZWSFSY.js +0 -24
  91. package/dist/chunk-6N6NTMOR.js +0 -1
  92. package/dist/chunk-KZ65LEUH.js +0 -1
  93. package/dist/chunk-SMGSLY5N.js +0 -7
  94. package/dist/chunk-X2ILN3KP.js +0 -1
  95. /package/dist/{chunk-5DIOZDDZ.js → chunk-7DFNBRLY.js} +0 -0
@@ -1 +1 @@
1
- import{b as D,c as j}from"./chunk-6UEFCMR2.js";import{a as G}from"./chunk-KAWNGQS2.js";import{c as J}from"./chunk-K25S2MGU.js";import{b as B,c as R,d as N,e as z}from"./chunk-3BVHPQZW.js";import{e as f,g as T}from"./chunk-H2ORWIEY.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{a as G}from"./chunk-7AZKPX2J.js";import{c as J}from"./chunk-V5MJ4ICC.js";import{b as B,c as R,d as N,e as z}from"./chunk-OPUI7CM2.js";import{e as f,g as T}from"./chunk-H2ORWIEY.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};
@@ -0,0 +1,24 @@
1
+ import{f as E}from"./chunk-MODFTCZY.js";import{b,e as y,f as k,h as M}from"./chunk-H2ORWIEY.js";import{a as u}from"./chunk-ZLLER3HP.js";var j=50,I=24e3,v=3,P=3,R=40,C=4e3,N=new Set(["fact","decision","correction","convention"]),x=`You are distilling DURABLE, PROJECT-SPECIFIC knowledge from an AI coding session so a future agent working on the SAME project starts smarter.
2
+
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
+
5
+ Do NOT extract:
6
+ - what the user asked for in THIS session, or the step-by-step actions taken
7
+ - anything specific to this one task that will not recur
8
+ - anything already covered by the existing memories listed below
9
+
10
+ Existing memories for this project (do NOT duplicate these):
11
+ {{EXISTING}}
12
+
13
+ Prefer FEWER, higher-quality memories \u2014 most sessions yield 0-2, many yield 0. A weak or redundant memory is worse than none.
14
+
15
+ Each memory has: "kind" (one of: fact, decision, correction, convention), a short "title" (<= 120 chars), and a 1-3 sentence "body".
16
+
17
+ Return STRICT JSON: {"memories": [{"kind": "...", "title": "...", "body": "..."}]} \u2014 use an empty array if nothing durable was learned.`;function A(e){return e.toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}u(A,"normalizeTitle");function L(e,n,f=P){let l=Array.isArray(e?.memories)?e.memories:[],g=new Set(n.map(A)),d=[];for(let m of l){if(d.length>=f)break;if(!m||typeof m!="object")continue;let o=m,r=typeof o.kind=="string"?o.kind.trim().toLowerCase():"",s=typeof o.title=="string"?o.title.trim():"",p=typeof o.body=="string"?o.body.trim():"";if(!N.has(r)||!s||!p||s.length>300||p.length>C)continue;let a=A(s);!a||g.has(a)||(g.add(a),d.push({kind:r,title:s,body:p}))}return d}u(L,"selectNewMemories");async function O(e,n){await M(`/api/sessions/${e}/enrich`,{analysis:{distilledAt:n}})}u(O,"stampDistilledViaApi");async function F(e,n={}){let f=n.llm??E,l=n.now??Date.now,g=n.getSession??(async t=>{try{return await y(`/api/sessions/${t}`)}catch(i){if(i instanceof b&&i.statusCode===404)return null;throw i}}),d=n.getTurns??((t,i)=>y(`/api/sessions/${t}/events?limit=${i}&sort=desc&eventType=user_message,assistant_response&hasContent=true`)),m=n.getExistingTitles??(async(t,i)=>(await y(`/api/memories?projectId=${t}&status=active&limit=${i}`)).map(_=>_.title)),o=n.createMemory??(async t=>{await k("/api/memories",{kind:t.kind,title:t.title,body:t.body,projectId:t.projectId,source:"distilled"})}),r=n.stamp??O,s=await g(e.sessionId);if(!s)return{skipped:"not_found"};if((s.analysis??{}).distilledAt)return{skipped:"already_distilled"};if(!s.projectId)return await r(e.sessionId,new Date(l()).toISOString()),{skipped:"no_project"};let a=s.projectId,S=(await d(e.sessionId,j)).reverse().map(t=>`${t.eventType==="user_message"?"USER":"ASSISTANT"}: ${t.content}`);if(S.length<v)return await r(e.sessionId,new Date(l()).toISOString()),{skipped:"too_short"};let c=S.join(`
18
+
19
+ `);if(c.length>I){let t=c.slice(0,Math.floor(I*.45)),i=c.slice(c.length-Math.floor(I*.45));c=`${t}
20
+
21
+ [... middle of session omitted ...]
22
+
23
+ ${i}`}let h=await m(a,R),D=x.replace("{{EXISTING}}",h.length?h.map(t=>`- ${t}`).join(`
24
+ `):"(none yet)"),T=await f(D,c,700);if(T===null)throw new Error("distill_memories: LLM backend unavailable or returned unparseable output");let w=L(T,h);for(let t of w)await o({...t,projectId:a});return await r(e.sessionId,new Date(l()).toISOString()),{created:w.length,candidates:w.length}}u(F,"distillMemories");export{L as a,F as b};
@@ -1 +1 @@
1
- import{a as l}from"./chunk-X2ILN3KP.js";import{a as r}from"./chunk-ZLLER3HP.js";var u=r(n=>{let t=n.grading.summary?.pass_rate;return typeof t=="number"?t:null},"passRateOf"),a=r(n=>(u(n)??0)>=1,"fullPass");function f(n,t){let i=new Map(n.filter(e=>u(e)!=null).map(e=>[e.evalName,e])),o=[];for(let e of t){if(u(e)==null)continue;let s=i.get(e.evalName);s&&o.push({withScore:a(e)?1:0,withoutScore:a(s)?1:0})}return o}r(f,"pairVersionResults");function d(n,t){let i=f(n,t);return i.length===0?null:l(i,{baseline:"prior-version"})}r(d,"buildVersionVerdict");function m(n,t,i){let o=`v${i} vs v${t}`;if(!n.sufficient)return`${o}: ${n.insufficientReason??"insufficient data"} \u2014 no effect claimed`;let e=n.delta>=0?"+":"",s=`95% CI ${(n.ci.lower*100).toFixed(0)}\u2013${(n.ci.upper*100).toFixed(0)}%`,c=n.significant?"significant":"not significant";return`${o}: ${e}${(n.delta*100).toFixed(0)}% pass rate (${s}, n=${n.nWith} paired, ${c})`}r(m,"formatVersionVerdict");export{f as a,d as b,m as c};
1
+ import{a as l}from"./chunk-WKXTY5AM.js";import{a as r}from"./chunk-ZLLER3HP.js";var u=r(n=>{let t=n.grading.summary?.pass_rate;return typeof t=="number"?t:null},"passRateOf"),a=r(n=>(u(n)??0)>=1,"fullPass");function f(n,t){let i=new Map(n.filter(e=>u(e)!=null).map(e=>[e.evalName,e])),o=[];for(let e of t){if(u(e)==null)continue;let s=i.get(e.evalName);s&&o.push({withScore:a(e)?1:0,withoutScore:a(s)?1:0})}return o}r(f,"pairVersionResults");function d(n,t){let i=f(n,t);return i.length===0?null:l(i,{baseline:"prior-version"})}r(d,"buildVersionVerdict");function m(n,t,i){let o=`v${i} vs v${t}`;if(!n.sufficient)return`${o}: ${n.insufficientReason??"insufficient data"} \u2014 no effect claimed`;let e=n.delta>=0?"+":"",s=`95% CI ${(n.ci.lower*100).toFixed(0)}\u2013${(n.ci.upper*100).toFixed(0)}%`,c=n.significant?"significant":"not significant";return`${o}: ${e}${(n.delta*100).toFixed(0)}% pass rate (${s}, n=${n.nWith} paired, ${c})`}r(m,"formatVersionVerdict");export{f as a,d as b,m as c};
@@ -1,4 +1,4 @@
1
- import{d as b,f as y}from"./chunk-SMGSLY5N.js";import{e as M,f as w}from"./chunk-H2ORWIEY.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-MODFTCZY.js";import{e as M,f as w}from"./chunk-H2ORWIEY.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,3 +1,3 @@
1
- import{a as w}from"./chunk-SMGSLY5N.js";import{a as r}from"./chunk-ZLLER3HP.js";import{spawn as k}from"node:child_process";import{mkdtempSync as v,readFileSync as M,rmSync as S}from"node:fs";import{tmpdir as $}from"node:os";import{join as P}from"node:path";var D=r(o=>`codex:${o}`,"codexModelId");function R(o,i){return["exec","--sandbox","read-only","--skip-git-repo-check","--ephemeral","--model",o,"--output-last-message",i,"-"]}r(R,"buildCodexArgs");async function j(o){let{prompt:i,systemPrompt:l,model:c,timeout:u=12e4,workDir:b=process.cwd()}=o,T=l?`${l}
1
+ import{a as w}from"./chunk-MODFTCZY.js";import{a as r}from"./chunk-ZLLER3HP.js";import{spawn as k}from"node:child_process";import{mkdtempSync as v,readFileSync as M,rmSync as S}from"node:fs";import{tmpdir as $}from"node:os";import{join as P}from"node:path";var D=r(o=>`codex:${o}`,"codexModelId");function R(o,i){return["exec","--sandbox","read-only","--skip-git-repo-check","--ephemeral","--model",o,"--output-last-message",i,"-"]}r(R,"buildCodexArgs");async function j(o){let{prompt:i,systemPrompt:l,model:c,timeout:u=12e4,workDir:b=process.cwd()}=o,T=l?`${l}
2
2
 
3
3
  ${i}`:i,m=w("codex");if(!m)return{output:"",exitCode:null,durationMs:0,error:"Codex CLI not found on PATH, well-known install dirs, or the node bin dir \u2014 is it installed?"};let p=v(P($(),"rulemetric-codex-")),a=P(p,"last-message.txt"),h=Date.now();return new Promise(E=>{let s={...process.env};delete s.HTTPS_PROXY;let y=["/opt/homebrew/bin","/usr/local/bin"],x=(s.PATH??"").split(":").filter(Boolean),f=y.filter(e=>!x.includes(e));f.length&&(s.PATH=[...x,...f].join(":"));let t=k(m,R(c,a),{cwd:b,env:s,stdio:["pipe","pipe","pipe"]}),g="";t.stdout.on("data",()=>{}),t.stderr.on("data",e=>{g+=e.toString()});let n=r(e=>{S(p,{recursive:!0,force:!0}),E({...e,durationMs:Date.now()-h})},"finish"),C=setTimeout(()=>{t.kill("SIGTERM"),n({output:"",exitCode:null,error:`codex exec timed out after ${u}ms`})},u);t.on("error",e=>{clearTimeout(C),n({output:"",exitCode:null,error:`failed to spawn codex: ${e.message} (is the Codex CLI installed?)`})}),t.on("close",e=>{clearTimeout(C);let d="";try{d=M(a,"utf8").trim()}catch{}if(e!==0||d===""){n({output:d,exitCode:e,error:`codex exec failed (exit ${e}): ${g.trim().slice(-500)||"no last message produced"}`});return}n({output:d,exitCode:e,model:D(c)})}),t.stdin.write(T),t.stdin.end()})}r(j,"executeCodexEval");export{D as a,R as b,j as c};
@@ -0,0 +1,31 @@
1
+ import{f as x}from"./chunk-I2DZGJRR.js";import{a as r}from"./chunk-ZLLER3HP.js";import{execSync as h}from"node:child_process";import{existsSync as c,mkdirSync as y,readFileSync as p,writeFileSync as a,unlinkSync as S,copyFileSync as $}from"node:fs";import{homedir as f}from"node:os";import{join as i,dirname as N}from"node:path";function q(t,e=f()){let o=["claude_code"];return c(i(e,".codex"))&&o.push("codex"),c(i(t,".cursor"))&&o.push("cursor"),c(i(t,".github"))&&o.push("copilot_agent"),c(i(t,".agents"))&&o.push("antigravity"),o}r(q,"detectInstalledTools");function U(t){let e=t?`PATH="${t}:$PATH" `:"",o=r(n=>({command:`${e}rulemetric hooks run ${n}`}),"cmd");return{version:1,hooks:{sessionStart:[o("session-start")],beforeSubmitPrompt:[o("user-prompt")],afterFileEdit:[o("post-tool-use")],beforeShellExecution:[o("post-tool-use")],afterShellExecution:[o("post-tool-use")],beforeMCPExecution:[o("post-tool-use")],afterMCPExecution:[o("post-tool-use")],afterAgentResponse:[o("assistant-response")],stop:[o("post-tool-use")],sessionEnd:[o("session-end")]}}}r(U,"generateCursorHooksConfig");function L(t){let e=t?`PATH="${t}:$PATH" `:"",o=r(n=>({type:"command",bash:`${e}rulemetric hooks run ${n}`}),"cmd");return{version:1,hooks:{sessionStart:[o("session-start")],userPromptSubmitted:[o("user-prompt")],postToolUse:[o("post-tool-use")],sessionEnd:[o("session-end")]}}}r(L,"generateCopilotHooksConfig");function B(t){let e=t?`PATH="${t}:$PATH" `:"",o=r(n=>({type:"command",command:`${e}rulemetric hooks run ${n}`}),"mk");return{SessionStart:[{hooks:[o("session-start")]}],UserPromptSubmit:[{hooks:[o("user-prompt")]}],PostToolUse:[{matcher:".*",hooks:[o("post-tool-use")]}],SessionEnd:[{hooks:[o("session-end")]}]}}r(B,"generateClaudeCodeHooksConfig");function J(t){if(!c(t))return{settings:{},recoveredBackup:null};let e=p(t,"utf-8");try{return{settings:JSON.parse(e),recoveredBackup:null}}catch{let o=`${t}.corrupt.bak`;return a(o,e),{settings:{},recoveredBackup:o}}}r(J,"readClaudeSettings");function b(t,e){y(N(t),{recursive:!0});let o=null;return c(t)&&(o=`${t}.bak`,$(t,o)),a(t,JSON.stringify(e,null,2)+`
2
+ `),{backupPath:o}}r(b,"writeClaudeSettingsWithBackup");function k(t){if(!c(t))return{};let e=p(t,"utf-8");try{return JSON.parse(e)}catch{try{a(`${t}.corrupt.bak`,e)}catch{}return null}}r(k,"readMergeableJson");function Q(t,e){let o=B(e),n=t.hooks??{};for(let[s,u]of Object.entries(o)){let l=n[s]??[];l.some(m=>m?.hooks?.some(d=>typeof d?.command=="string"&&d.command.includes("rulemetric")))||(n[s]=[...l,...u])}t.hooks=n}r(Q,"mergeClaudeCodeHooks");function Z(t){if(!t.hooks||typeof t.hooks!="object")return!1;let e=t.hooks;return Object.values(e).some(o=>Array.isArray(o)&&o.some(n=>n?.hooks?.some(s=>typeof s?.command=="string"&&s.command.includes("rulemetric"))))}r(Z,"hasRulemetricClaudeHooks");function D(t){if(!t.hooks||typeof t.hooks!="object")return!1;let e=t.hooks,o=0;for(let n of Object.keys(e)){let s=e[n];if(!Array.isArray(s))continue;let u=s.filter(l=>{let g=l?.hooks?.some(m=>typeof m?.command=="string"&&m.command.includes("rulemetric"));return g&&(o+=1),!g});u.length===0?delete e[n]:e[n]=u}return Object.keys(e).length===0&&delete t.hooks,o>0}r(D,"removeClaudeCodeHooks");var X="localhost,127.0.0.1,*.supabase.co,*.supabase.in";function tt(t,e){return i(t,e?"settings.json":"settings.local.json")}r(tt,"claudeSettingsInstallPath");function M(t,e){let o=t.env;if(!o||typeof o!="object")return!1;let n=!1,s=o.HTTPS_PROXY;(s===`http://localhost:${e}`||s===`http://127.0.0.1:${e}`)&&(delete o.HTTPS_PROXY,n=!0),o.NO_PROXY===X&&(delete o.NO_PROXY,n=!0);let u=o.NODE_EXTRA_CA_CERTS;return typeof u=="string"&&u.includes(".mitmproxy")&&u.endsWith("mitmproxy-ca-cert.pem")&&(delete o.NODE_EXTRA_CA_CERTS,n=!0),n&&Object.keys(o).length===0&&delete t.env,n}r(M,"removeRulemetricProxyEnv");function C(t,e){let o=D(t),n=M(t,e),s=x(t);return{removedHooks:o,removedProxyEnv:n,removedStatusline:s,removed:o||n||s}}r(C,"removeRulemetricMachineState");function et(t,e){let o={migrated:!1,backupPath:null,removedHooks:!1,removedProxyEnv:!1,removedStatusline:!1,removed:!1};if(!c(t))return o;let n;try{n=JSON.parse(p(t,"utf-8"))}catch{return o}let s=C(n,e);if(!s.removed)return o;let{backupPath:u}=b(t,n);return{...s,migrated:!0,backupPath:u}}r(et,"migrateSharedClaudeSettings");function ot(t,e){let o=[];for(let n of["settings.json","settings.local.json"]){let s=i(t,n);if(!c(s))continue;let{settings:u,recoveredBackup:l}=J(s),g=C(u,e);g.removed&&b(s,u),o.push({...g,configPath:s,fileName:n,recoveredBackup:l,changed:g.removed})}return o}r(ot,"cleanClaudeSettingsFiles");function R(t,e){if(!c(t))return null;let o=i(t,"hooks.json"),n=U(e),s=k(o);if(s===null)return null;let u=s,l={...u.hooks??{}},g=r(d=>typeof d=="object"&&d!==null&&"command"in d&&typeof d.command=="string"&&d.command.includes("rulemetric"),"isRulemetricHook");for(let[d,w]of Object.entries(n.hooks)){let j=(l[d]??[]).filter(_=>!g(_));l[d]=[...j,...w]}let m={version:u.version??n.version,hooks:l};return a(o,JSON.stringify(m,null,2)+`
3
+ `),o}r(R,"writeCursorHooksToDir");function nt(t,e){return R(i(t,".cursor"),e)}r(nt,"writeCursorHooks");function rt(t,e=f()){let o=i(e,".cursor");return c(o)?R(o,t):null}r(rt,"writeCursorUserHooks");function st(t,e){let o=i(t,".github");if(!c(o))return null;let n=i(o,"hooks");y(n,{recursive:!0});let s=i(n,"rulemetric.json"),u=L(e);return a(s,JSON.stringify(u,null,2)+`
4
+ `),s}r(st,"writeCopilotHooks");function A(t){if(!c(t))return!1;let e;try{e=JSON.parse(p(t,"utf-8"))}catch{return!1}if(!e.hooks)return!1;let o=!1;for(let[n,s]of Object.entries(e.hooks)){let u=s.filter(l=>{if(typeof l!="object"||l===null||!("command"in l))return!0;let g=l.command;return typeof g=="string"&&g.includes("rulemetric")?(o=!0,!1):!0});u.length===0?delete e.hooks[n]:e.hooks[n]=u}return o&&a(t,JSON.stringify(e,null,2)+`
5
+ `),o}r(A,"removeCursorHooksFromFile");function it(t){return A(i(t,".cursor","hooks.json"))}r(it,"removeCursorHooks");function ut(){return A(i(f(),".cursor","hooks.json"))}r(ut,"removeCursorUserHooks");function ct(t,e,o){let n=i(t,".cursor");if(!c(n))return!1;let s=i(n,"settings.json"),u=k(s);return u===null?!1:(u["http.proxy"]=`http://localhost:${e}`,u["http.proxyStrictSSL"]=c(o),a(s,JSON.stringify(u,null,2)+`
6
+ `),!0)}r(ct,"writeCursorProxyConfig");function lt(t,e,o){let n=i(t,".vscode");if(!c(n))return!1;let s=i(n,"settings.json"),u=k(s);if(u===null)return!1;u["http.proxy"]=`http://localhost:${e}`,u["http.proxyStrictSSL"]=c(o);let l=u["github.copilot.advanced"]??{};return l["debug.overrideProxyUrl"]=`http://localhost:${e}`,u["github.copilot.advanced"]=l,a(s,JSON.stringify(u,null,2)+`
7
+ `),!0}r(lt,"writeVSCodeProxyConfig");function at(t){let e=i(t,".vscode","settings.json");if(!c(e))return!1;let o;try{o=JSON.parse(p(e,"utf-8"))}catch{return!1}let n=!1;o["http.proxy"]&&(delete o["http.proxy"],delete o["http.proxyStrictSSL"],n=!0);let s=o["github.copilot.advanced"];return s?.["debug.overrideProxyUrl"]&&(delete s["debug.overrideProxyUrl"],Object.keys(s).length===0&&delete o["github.copilot.advanced"],n=!0),n&&a(e,JSON.stringify(o,null,2)+`
8
+ `),n}r(at,"removeVSCodeProxyConfig");function gt(t){let e=i(t,".github","hooks","rulemetric.json");return c(e)?(S(e),!0):!1}r(gt,"removeCopilotHooks");var H="com.rulemetric.env";function P(){return i(f(),"Library","LaunchAgents",`${H}.plist`)}r(P,"getLaunchAgentPath");function ft(t,e){if(process.platform!=="darwin")return!1;let o=`http://localhost:${t}`;try{h(`launchctl setenv HTTPS_PROXY ${o}`,{stdio:"pipe"}),c(e)&&h(`launchctl setenv NODE_EXTRA_CA_CERTS ${e}`,{stdio:"pipe"})}catch{return!1}let n=P(),s=i(f(),"Library","LaunchAgents");y(s,{recursive:!0});let u=c(e)?`launchctl setenv NODE_EXTRA_CA_CERTS ${e};`:"",l=`if nc -z -w 1 127.0.0.1 ${t} 2>/dev/null; then launchctl setenv HTTPS_PROXY ${o};${u} else launchctl unsetenv HTTPS_PROXY; launchctl unsetenv NODE_EXTRA_CA_CERTS; fi`,g=`<?xml version="1.0" encoding="UTF-8"?>
9
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
10
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
11
+ <plist version="1.0">
12
+ <dict>
13
+ <key>Label</key>
14
+ <string>${H}</string>
15
+ <key>ProgramArguments</key>
16
+ <array>
17
+ <string>/bin/sh</string>
18
+ <string>-c</string>
19
+ <string>${l}</string>
20
+ </array>
21
+ <key>RunAtLoad</key>
22
+ <true/>
23
+ </dict>
24
+ </plist>
25
+ `;return a(n,g),!0}r(ft,"installMacOSProxyEnv");function dt(){if(process.platform!=="darwin")return!1;let t=!1;try{h("launchctl unsetenv HTTPS_PROXY",{stdio:"pipe"}),h("launchctl unsetenv NODE_EXTRA_CA_CERTS",{stdio:"pipe"})}catch{}let e=P();return c(e)&&(S(e),t=!0),t}r(dt,"uninstallMacOSProxyEnv");function O(){return process.platform==="darwin"?i(f(),"Library","Application Support","Code","User","settings.json"):process.platform==="win32"?i(process.env.APPDATA??"","Code","User","settings.json"):i(f(),".config","Code","User","settings.json")}r(O,"getVSCodeUserSettingsPath");function pt(t){let e=O();if(!c(i(e,"..")))return!1;let o=k(e);return o===null||o["http.proxy"]&&!o["http.proxy"].includes("localhost")?!1:(o["http.proxy"]=`http://localhost:${t}`,o["http.proxyStrictSSL"]=!1,a(e,JSON.stringify(o,null,2)+`
26
+ `),!0)}r(pt,"writeVSCodeUserProxyConfig");function mt(){let t=O();if(!c(t))return!1;let e;try{e=JSON.parse(p(t,"utf-8"))}catch{return!1}return e["http.proxy"]?.includes("localhost")?(delete e["http.proxy"],delete e["http.proxyStrictSSL"],a(t,JSON.stringify(e,null,2)+`
27
+ `),!0):!1}r(mt,"removeVSCodeUserProxyConfig");function T(){return process.platform==="darwin"?i(f(),"Library","Application Support","Cursor","User","settings.json"):process.platform==="win32"?i(process.env.APPDATA??"","Cursor","User","settings.json"):i(f(),".config","Cursor","User","settings.json")}r(T,"getCursorUserSettingsPath");function kt(t){let e=T();if(!c(i(e,"..")))return!1;let o=k(e);return o===null||o["http.proxy"]&&!o["http.proxy"].includes("localhost")?!1:(o["http.proxy"]=`http://localhost:${t}`,o["http.proxyStrictSSL"]=!1,a(e,JSON.stringify(o,null,2)+`
28
+ `),!0)}r(kt,"writeCursorUserProxyConfig");function ht(){let t=T();if(!c(t))return!1;let e;try{e=JSON.parse(p(t,"utf-8"))}catch{return!1}return e["http.proxy"]?.includes("localhost")?(delete e["http.proxy"],delete e["http.proxyStrictSSL"],a(t,JSON.stringify(e,null,2)+`
29
+ `),!0):!1}r(ht,"removeCursorUserProxyConfig");function F(){let t=process.execPath,e=process.argv[1];return e&&e.endsWith("run.js")?`${t} ${e}`:"rulemetric"}r(F,"getRulemetricCommand");function Y(){let t=F(),e=r(o=>({type:"command",command:`RULEMETRIC_HOOK_TOOL=antigravity ${t} hooks run ${o}`,timeout:30}),"mk");return{rulemetric:{enabled:!0,SessionStart:[{hooks:[e("session-start")]}],PostToolUse:[{matcher:".*",hooks:[e("post-tool-use")]}],SessionEnd:[{hooks:[e("session-end")]}]}}}r(Y,"generateAntigravityHooksConfig");function E(t){let e=i(t,"hooks.json"),o=k(e);if(o===null)return null;let n=Y(),s={...o,rulemetric:n.rulemetric};return y(t,{recursive:!0}),a(e,JSON.stringify(s,null,2)+`
30
+ `),e}r(E,"writeAntigravityHooksToDir");function yt(t){return E(i(t,".agents"))}r(yt,"writeAntigravityHooks");function vt(t=f()){let e=i(t,".gemini");return c(e)?E(i(e,"config")):null}r(vt,"writeAntigravityUserHooks");function v(t){if(!c(t))return!1;let e;try{e=JSON.parse(p(t,"utf-8"))}catch{return!1}if(!("rulemetric"in e))return!1;if(delete e.rulemetric,Object.keys(e).length===0)try{S(t)}catch{}else a(t,JSON.stringify(e,null,2)+`
31
+ `);return!0}r(v,"removeAntigravityHooksFromFile");function St(t){return v(i(t,".agents","hooks.json"))}r(St,"removeAntigravityHooks");function xt(){let t=v(i(f(),".gemini","config","hooks.json")),e=v(i(f(),".gemini","hooks.json"));return t||e}r(xt,"removeAntigravityUserHooks");export{q as a,U as b,L as c,B as d,J as e,b as f,Q as g,Z as h,D as i,X as j,tt as k,M as l,C as m,et as n,ot as o,nt as p,rt as q,st as r,it as s,ut as t,ct as u,lt as v,at as w,gt as x,ft as y,dt as z,O as A,pt as B,mt as C,T as D,kt as E,ht as F,Y as G,yt as H,vt as I,St as J,xt as K};
@@ -1 +1 @@
1
- import{b as l}from"./chunk-MDPN46EY.js";import{a as p}from"./chunk-5RBLIVBF.js";import{h}from"./chunk-H2ORWIEY.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-BC6GMBXV.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-H2ORWIEY.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,2 +1,2 @@
1
- import{b as B}from"./chunk-N7TGRFVZ.js";import{a as R}from"./chunk-5RBLIVBF.js";import{a as v,g as d,h as n,i as m,j as U}from"./chunk-KZ65LEUH.js";import{a as $}from"./chunk-ZLLER3HP.js";import{and as L,asc as j,eq as l,gt as q,isNotNull as F,sql as O}from"drizzle-orm";var _=100,C=10;async function G(I,s={}){let t=s.db??U(),D=s.sendEmail??B,p=s.log??(o=>process.stderr.write(`[process_announcement] ${o}
1
+ import{b as B}from"./chunk-N7TGRFVZ.js";import{a as v,f as d,g as n,h as m,i as U}from"./chunk-3DLVY7LD.js";import{a as R}from"./chunk-5RBLIVBF.js";import{a as $}from"./chunk-ZLLER3HP.js";import{and as L,asc as j,eq as l,gt as q,isNotNull as F,sql as O}from"drizzle-orm";var _=100,C=10;async function G(I,s={}){let t=s.db??U(),D=s.sendEmail??B,p=s.log??(o=>process.stderr.write(`[process_announcement] ${o}
2
2
  `)),b=s.webBaseUrl??process.env.RULEMETRIC_WEB_URL??process.env.WEB_URL??"https://rulemetric.com",{announcementId:r}=I,[i]=await t.select().from(d).where(l(d.id,r)).limit(1);if(!i)throw new R(`Announcement ${r} not found`);if(i.status!=="queued"&&i.status!=="sending")throw new R(`Announcement ${r} is in status='${i.status}'; expected 'queued' or 'sending'.`);await t.update(d).set({status:"sending",updatedAt:new Date}).where(l(d.id,r)),p(`Sending announcement ${r} (${i.subject??""})`);let w=0,f=0,h=0,y=0,k=null;try{for(;;){let c=await t.select({userId:m.userId,email:v.email,displayName:v.displayName,unsubscribeToken:m.unsubscribeToken}).from(m).innerJoin(v,l(v.id,m.userId)).where(L(l(m.productAnnouncements,!0),F(v.email),k?q(m.userId,k):void 0)).orderBy(j(m.userId)).limit(_);if(c.length===0)break;k=c[c.length-1].userId;for(let A=0;A<c.length;A+=C){let P=c.slice(A,A+C),S=await Promise.allSettled(P.map(g=>W({recipient:g,announcement:i,webBaseUrl:b,sendEmail:D,db:t})));for(let g=0;g<S.length;g++){let u=S[g];if(u.status==="fulfilled")u.value.ok==="sent"?w++:u.value.ok==="skipped"?h++:(f++,u.value.provider==="noop"&&y++,p(` recipient ${P[g].userId}: send failed \u2014 ${u.value.error}`));else{f++;let T=u.reason instanceof Error?u.reason.message:String(u.reason);p(` recipient ${P[g].userId}: send failed \u2014 ${T}`)}}}if(c.length<_)break}y>0&&p(`WARNING: ${y} recipient(s) hit the noop email provider and were recorded as FAILED \u2014 no email provider is configured on this worker (set RESEND_API_KEY in ~/.config/rulemetric/env and reinstall the service)`);let o=await t.select({status:n.status,count:O`count(*)::int`}).from(n).where(l(n.announcementId,r)).groupBy(n.status),e={};for(let c of o)e[c.status]=c.count;let a=e.sent??0,E=e.failed??0,N=a===0&&E>0?"failed":"sent",x=E>0?`${E} of ${a+E} recipient(s) failed; see announcement_deliveries`:null;return await t.update(d).set({status:N,recipientCount:a,...N==="sent"?{sentAt:new Date}:{},error:x,updatedAt:new Date}).where(l(d.id,r)),p(`Done: status=${N} sent=${a} failed=${E} (this attempt: sent=${w} failed=${f} skipped=${h})`),{sent:w,failed:f,skipped:h}}catch(o){let e=o instanceof Error?o.message:String(o);throw await t.update(d).set({status:"failed",error:e.slice(0,1e3),updatedAt:new Date}).where(l(d.id,r)).catch(()=>{}),o}}$(G,"processAnnouncement");function K(I){return I.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}$(K,"escapeHtml");async function W(I){let{recipient:s,announcement:t,webBaseUrl:D,sendEmail:p,db:b}=I;if(!s.email)return{ok:"skipped",reason:"no-email"};let r=await b.insert(n).values({announcementId:t.id,userId:s.userId,email:s.email,status:"pending"}).onConflictDoNothing({target:[n.announcementId,n.userId]}).returning({id:n.id});if(r.length===0)return{ok:"skipped",reason:"already-claimed"};let i=r[0].id,w=D.replace(/\/$/,""),f=encodeURIComponent(s.unsubscribeToken),h=`${w}/unsubscribe/${f}`,y=s.displayName?.trim().split(/\s+/)[0]||"there",k=t.htmlBody.replaceAll("{{unsubscribe_url}}",h).replaceAll("{{recipient_name}}",K(y)),o=t.textBody.replaceAll("{{unsubscribe_url}}",h).replaceAll("{{recipient_name}}",y);try{let e=await p({to:s.email,subject:t.subject,html:k,text:o,fromName:"RuleMetric",idempotencyKey:i,headers:{"List-Unsubscribe":`<${w}/api/unsubscribe/${f}>`,"List-Unsubscribe-Post":"List-Unsubscribe=One-Click"}});if(e.provider==="noop"){let a="no email provider configured (RESEND_API_KEY unset on the worker)";return await b.update(n).set({status:"failed",error:a}).where(l(n.id,i)),{ok:"failed",error:a,provider:e.provider}}return await b.update(n).set({status:"sent",providerId:e.id,sentAt:new Date}).where(l(n.id,i)),{ok:"sent",providerId:e.id,provider:e.provider}}catch(e){let a=e instanceof Error?e.message:String(e);return await b.update(n).set({status:"failed",error:a.slice(0,1e3)}).where(l(n.id,i)).catch(()=>{}),{ok:"failed",error:a}}}$(W,"sendOne");export{G as a};
@@ -0,0 +1 @@
1
+ import{a as i}from"./chunk-ZLLER3HP.js";function F(n,t){let e=n,o=t,r=e+o;if(r===0)return{pValue:1,nDiscordant:0};let c=Math.min(e,o),l=Math.pow(.5,r),u=l;for(let s=1;s<=c;s++)l*=(r-s+1)/s,u+=l;return{pValue:Math.min(1,2*u),nDiscordant:r}}i(F,"mcnemarExact");function O(n,t,e=10){return{sufficient:n>=e&&t>=e,minN:e,nWith:n,nWithout:t,shortfall:{with:Math.max(0,e-n),without:Math.max(0,e-t)}}}i(O,"assessSufficiency");function M(n){let t=n>>>0;return()=>{t=t+1831565813|0;let e=Math.imul(t^t>>>15,1|t);return e=e+Math.imul(e^e>>>7,61|e)^e,((e^e>>>14)>>>0)/4294967296}}i(M,"seededRandom");function T(n,t){let e=n.length;if(e===1)return n[0];let o=(e-1)*t,r=Math.floor(o),c=Math.ceil(o);return r===c?n[r]:n[r]+(o-r)*(n[c]-n[r])}i(T,"sortedQuantile");function k(n,t={}){let e=n.length;if(e===0)return{estimate:0,lower:0,upper:0,iterations:0};let o=t.iterations??1e4,r=t.ciLevel??.95,c=M(t.seed??1),l=n.reduce((a,m)=>a+m,0)/e,u=new Array(o);for(let a=0;a<o;a++){let m=0;for(let h=0;h<e;h++)m+=n[c()*e|0];u[a]=m/e}u.sort((a,m)=>a-m);let s=(1-r)/2;return{estimate:l,lower:T(u,s),upper:T(u,1-s),iterations:o}}i(k,"pairedBootstrapCI");function L(n,t={}){let e=n.filter(d=>d.withScores.length>0&&d.withoutScores.length>0);if(e.length===0)return{estimate:0,lower:0,upper:0,pValue:1,iterations:0};let o=i(d=>d.reduce((p,g)=>p+g,0)/d.length,"mean"),r=e.map(d=>d.withScores.length*d.withoutScores.length/(d.withScores.length+d.withoutScores.length)),c=r.reduce((d,p)=>d+p,0),l=i(d=>d.reduce((p,g,w)=>p+r[w]*g,0)/c,"combine"),u=l(e.map(d=>o(d.withScores)-o(d.withoutScores))),s=t.iterations??1e4,a=t.ciLevel??.95,m=M(t.seed??1),h=new Array(s),S=0,A=0;for(let d=0;d<s;d++){let p=e.map(w=>{let $=0;for(let v=0;v<w.withScores.length;v++)$+=w.withScores[m()*w.withScores.length|0];let y=0;for(let v=0;v<w.withoutScores.length;v++)y+=w.withoutScores[m()*w.withoutScores.length|0];return $/w.withScores.length-y/w.withoutScores.length}),g=l(p);h[d]=g,g<=0&&S++,g>=0&&A++}h.sort((d,p)=>d-p);let b=(1-a)/2;return{estimate:u,lower:T(h,b),upper:T(h,1-b),pValue:Math.min(1,2*Math.min(S,A)/s),iterations:s}}i(L,"stratifiedBootstrapCI");function H(n,t){let e=n.length,o=t.length;if(e===0||o===0)return 0;let r=[...n.map(a=>({t:a,exposed:!0})),...t.map(a=>({t:a,exposed:!1}))].sort((a,m)=>a.t-m.t),c=0,l=0;for(;l<r.length;){let a=l;for(;a+1<r.length&&r[a+1].t===r[l].t;)a++;let m=(l+1+a+1)/2;for(let h=l;h<=a;h++)r[h].exposed&&(c+=m);l=a+1}let s=(c-e*(e+1)/2)/(e*o);return Math.abs(s-.5)}i(H,"cohortTimeSeparation");var C=.35,N=900*1e3;function U(n,t,e=C,o=N){if(n.length===0||t.length===0)return!1;let r=[...n,...t];return Math.max(...r)-Math.min(...r)<o?!1:H(n,t)>e}i(U,"isTimeSeparated");var G=i(n=>n===0||n===1,"isBinary");function J(n,t,e){return n.every(r=>r[t]!=null&&r[e]!=null)?n.reduce((r,c)=>r+(c[t]-c[e]),0)/n.length:null}i(J,"meanPairDelta");function V(n,t={}){let e=t.baseline??"no-rule",o=t.minN??10,r=n.length,c=n.map(d=>d.withScore-d.withoutScore),l=r===0?0:c.reduce((d,p)=>d+p,0)/r,u=k(c,{seed:t.seed,iterations:t.iterations}),s={lower:u.lower,upper:u.upper},a=n.every(d=>G(d.withScore)&&G(d.withoutScore)),m=null;if(a&&r>0){let d=0,p=0;for(let g of n)g.withScore===1&&g.withoutScore===0?d++:g.withScore===0&&g.withoutScore===1&&p++;m=F(d,p).pValue}let{sufficient:h}=O(r,r,o),S=s.lower>0||s.upper<0,b={mode:"controlled",baseline:e,delta:l,ci:s,pValue:m,significant:h&&S,sufficient:h,nWith:r,nWithout:r,costDelta:J(n,"withCost","withoutCost"),latencyDelta:J(n,"withLatency","withoutLatency"),confounded:!1};return h||(b.insufficientReason=`insufficient data: need >= ${o} paired tasks per cohort, have ${r}`),b}i(V,"buildControlledVerdict");var de=2;function W(n,t={}){let e=t.minN??10,o=t.minPerStratum??de,r=t.maxTimeSeparation??C,c=t.minStratumSpanMs??N,l=n.filter(f=>f.withScores.length>=o&&f.withoutScores.length>=o),u=l.filter(f=>f.withTimes!=null&&f.withoutTimes!=null&&U(f.withTimes,f.withoutTimes,r,c)),s=new Set(u.map(f=>f.key)),a=l.filter(f=>!s.has(f.key)),m=n.filter(f=>f.withScores.length>0&&f.withoutScores.length>0&&(f.withScores.length<o||f.withoutScores.length<o)).length,h=a.reduce((f,x)=>f+x.withScores.length,0),S=a.reduce((f,x)=>f+x.withoutScores.length,0),A=L(a,{seed:t.seed,iterations:t.iterations}),b={lower:A.lower,upper:A.upper},d=A.estimate,p=a.length>0&&h>=e&&S>=e,g=a.length>0?A.pValue:null,w=p&&(b.lower>0||b.upper<0),$=n.reduce((f,x)=>f+x.withScores.length+x.withoutScores.length,0),y=$>0?(h+S)/$:0,v={mode:"observational",baseline:t.baseline??"no-rule",delta:d,ci:b,pValue:g,significant:w,sufficient:p,nWith:h,nWithout:S,costDelta:null,latencyDelta:null,confounded:!0,strata:a.length,strataDroppedForTimeSeparation:u.length,coverage:y};if(!p){let f=m>0?` (${m} project(s) had both cohorts but fewer than ${o} sessions in one of them)`:"",x=u.length>0?` ${u.length} project-month(s) held both cohorts but their sessions are separated in time (exposure predicts when a session ran), so the difference within them is a calendar difference, not a treatment effect`:"";v.insufficientReason=a.length===0?u.length>0?`insufficient data: no comparable cohort.${x}${f}`:`insufficient data: no project has >= ${o} exposed AND >= ${o} unexposed sessions to compare within${f}`:`insufficient data: need >= ${e} sessions per cohort across comparable projects, have ${h} exposed / ${S} unexposed${f}${x?`.${x}`:""}`}return v}i(W,"buildStratifiedVerdict");var _=1.959963984540054;function z(n,t,e=_){if(t===0)return{lower:0,upper:1};let o=n/t,r=e*e,c=1+r/t,l=(o+r/(2*t))/c,u=e/c*Math.sqrt(o*(1-o)/t+r/(4*t*t));return{lower:Math.max(0,l-u),upper:Math.min(1,l+u)}}i(z,"wilsonInterval");function Q(n){let t=new Map;for(let e of n){let o=t.get(e.stratum);o||(o={key:e.stratum,withScores:[],withoutScores:[],withTimes:[],withoutTimes:[]},t.set(e.stratum,o)),(e.exposed?o.withScores:o.withoutScores).push(e.score),e.time!=null&&(e.exposed?o.withTimes:o.withoutTimes).push(e.time)}for(let e of t.values())(e.withTimes.length!==e.withScores.length||e.withoutTimes.length!==e.withoutScores.length)&&(delete e.withTimes,delete e.withoutTimes);return[...t.values()]}i(Q,"toStrata");var R=.05;function K(n,t={}){let e=t.trialIndex??0,o=t.seed??1,r=t.exposedFraction??.5,c=t.effect??0,l=M(o+e*2),u=n.map(s=>{let a=l()<r;return{stratum:s.stratum,score:a?s.score+c:s.score,exposed:a,time:s.time}});return W(Q(u),{seed:o+e*2+1,iterations:t.iterations??500,minN:t.minN,minPerStratum:t.minPerStratum})}i(K,"runCalibrationTrial");function q(n,t={}){let e=t.trials??200,o=[];for(let r=0;r<e;r++)o.push(K(n,{...t,trialIndex:r}));return D(o,t.effect??0)}i(q,"calibrate");function D(n,t){let e=0,o=0,r=0,c=0;for(let s of n)s.sufficient&&(e++,s.significant&&o++,r+=s.delta,c=Math.max(c,Math.abs(s.delta)));let l=e>0?o/e:0,u=z(o,e,_);return{trials:n.length,evaluated:e,insufficient:n.length-e,significantTrials:o,significantRate:l,significantRateCi:u,meanDelta:e>0?r/e:0,maxAbsDelta:c,alpha:R,effect:t,calibrated:t===0&&e>0&&u.lower<=R&&R<=u.upper}}i(D,"summarizeTrials");function I(n,t={}){return q(n,{...t,effect:0})}i(I,"aaCalibration");function Y(n,t,e={}){return q(n,{...e,effect:t})}i(Y,"powerCheck");var te=[{ym:"2026-03",n:122,mean:.287},{ym:"2026-04",n:50,mean:.07},{ym:"2026-05",n:267,mean:.089},{ym:"2026-06",n:61,mean:.201},{ym:"2026-07",n:162,mean:.071}],B=662;function Z(n=2){let t=[];for(let e of te){let o=Math.round(e.n*e.mean);for(let r=0;r<e.n;r++)t.push({stratum:`proj-${r%n}|${e.ym}`,score:r<o?1:0})}if(n===2&&t.length!==B)throw new Error(`realisticCanaryCorpus: expected ${B} sessions, built ${t.length}`);return t}i(Z,"realisticCanaryCorpus");function ne(n=600){return Array.from({length:n},(t,e)=>({stratum:"only",score:e%4===0?1:0}))}i(ne,"flatCanaryCorpus");var oe=50,re=4,P={min:.2,max:.7};function he(n,t){let e=M(t),o=P.max-P.min;return Array.from({length:n},()=>P.min+e()*o)}i(he,"caseDifficulties");function ee(n,t,e){let o=0;for(let r=0;r<t;r++)e()<n&&o++;return o/t}i(ee,"passRate");function ie(n={}){let t=n.trialIndex??0,e=n.seed??1,o=n.cases??oe,r=n.assertions??re,c=n.effect??0,l=he(o,e),u=M(e+t*2),s=l.map(a=>({withScore:ee(a+c,r,u),withoutScore:ee(a,r,u)}));return V(s,{baseline:"prior-version",seed:e+t*2+1,iterations:n.iterations??500,minN:n.minN})}i(ie,"runControlledCalibrationTrial");function X(n={}){let t=n.trials??200,e=[];for(let o=0;o<t;o++)e.push(ie({...n,trialIndex:o}));return D(e,n.effect??0)}i(X,"controlledCalibration");function ae(n={}){return X({...n,effect:0})}i(ae,"controlledAaCalibration");function se(n,t={}){return X({...t,effect:n})}i(se,"controlledPowerCheck");var ce={maxSignificantRate:.15,maxMeanAbsDelta:.02,maxWorstCaseDelta:.15,powerProbeEffect:.2,minPower:.9,minPowerMeanDelta:.15};function E(n,t,e){let o=e.filter(r=>!r.ok).map(r=>r.why);return{name:n,passed:o.length===0,detail:o.length===0?`${n}: ok (rate=${t.significantRate.toFixed(3)}, meanDelta=${t.meanDelta.toFixed(4)}, evaluated=${t.evaluated}/${t.trials})`:`${n}: ${o.join("; ")}`,result:t}}i(E,"check");function me(n={}){let t=n.trials??200,e=n.powerTrials??200,o=ce,r=[],c=I(ne(),{trials:t,seed:11});r.push(E("aa-flat",c,[{ok:c.calibrated,why:`\u03B1=${R} outside rate CI [${c.significantRateCi.lower.toFixed(3)}, ${c.significantRateCi.upper.toFixed(3)}]`},{ok:c.significantRate<o.maxSignificantRate,why:`false-positive rate ${c.significantRate.toFixed(3)} \u2265 ${o.maxSignificantRate}`},{ok:Math.abs(c.meanDelta)<o.maxMeanAbsDelta,why:`mean delta ${c.meanDelta.toFixed(4)} not centred on zero`}]));let l=I(Z(),{trials:t,seed:23});r.push(E("aa-realistic",l,[{ok:l.calibrated,why:`\u03B1=${R} outside rate CI [${l.significantRateCi.lower.toFixed(3)}, ${l.significantRateCi.upper.toFixed(3)}]`},{ok:l.significantRate<o.maxSignificantRate,why:`false-positive rate ${l.significantRate.toFixed(3)} \u2265 ${o.maxSignificantRate}`},{ok:Math.abs(l.meanDelta)<o.maxMeanAbsDelta,why:`mean delta ${l.meanDelta.toFixed(4)} not centred on zero`},{ok:l.maxAbsDelta<o.maxWorstCaseDelta,why:`worst single-trial delta ${l.maxAbsDelta.toFixed(3)} \u2265 ${o.maxWorstCaseDelta}`}]));let u=Y(Z(),o.powerProbeEffect,{trials:e,seed:5});r.push(E("power-observational",u,[{ok:u.significantRate>o.minPower,why:`detects +${o.powerProbeEffect} only ${u.significantRate.toFixed(3)} of the time`},{ok:u.meanDelta>o.minPowerMeanDelta,why:`measured mean delta ${u.meanDelta.toFixed(3)} understates the injected +${o.powerProbeEffect}`}]));let s=ae({trials:t,seed:31});r.push(E("aa-controlled",s,[{ok:s.calibrated,why:`\u03B1=${R} outside rate CI [${s.significantRateCi.lower.toFixed(3)}, ${s.significantRateCi.upper.toFixed(3)}]`},{ok:s.significantRate<o.maxSignificantRate,why:`false-positive rate ${s.significantRate.toFixed(3)} \u2265 ${o.maxSignificantRate}`},{ok:Math.abs(s.meanDelta)<o.maxMeanAbsDelta,why:`mean delta ${s.meanDelta.toFixed(4)} not centred on zero`}]));let a=se(o.powerProbeEffect,{trials:e,seed:37});r.push(E("power-controlled",a,[{ok:a.significantRate>o.minPower,why:`detects +${o.powerProbeEffect} only ${a.significantRate.toFixed(3)} of the time`}]));let m=r.filter(h=>!h.passed).map(h=>h.detail);return{green:m.length===0,checks:r,failures:m}}i(me,"runPromotionCanary");var ge=3,we=7;export{V as a,me as b,ge as c,we as d};
@@ -1 +1 @@
1
- import{a as i}from"./chunk-QQ2UPNBC.js";import{h as s}from"./chunk-H2ORWIEY.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-ZWKKFAIX.js";import{h as s}from"./chunk-H2ORWIEY.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};
@@ -0,0 +1,8 @@
1
+ import{g as p}from"./chunk-MODFTCZY.js";import{a as s}from"./chunk-ZLLER3HP.js";var f="<RATIONALE>",g="</RATIONALE>",a="<PROPOSED_INSTRUCTION>",l="</PROPOSED_INSTRUCTION>",c=.5,u=3;function m(e){let t=e.immutableSections.length>0?e.immutableSections.map(n=>` - ${n}`).join(`
2
+ `):" (none)";return["You are improving an AI coding assistant instruction file so that it scores","better on a fixed set of evaluation cases.","",`The file is a ${e.targetType} named "${e.targetName}".`,"","RULES","1. Return the COMPLETE new file, not a diff, not a patch, not a summary,"," and not an excerpt. Everything you omit will be DELETED from the file.","2. Preserve everything you are not deliberately changing, byte for byte.","3. Make a focused edit. You are one step in a measured loop: a small change"," that can be attributed beats a rewrite that cannot.","4. Do not edit these sections or anything nested under them \u2014 an edit that"," touches them is refused downstream and the whole proposal is wasted:",t,"5. Do not add meta-commentary about the evaluation, the loop, or this"," prompt to the file. The file is read by other agents as instructions.","","OUTPUT FORMAT \u2014 exactly this, with no text before or after:",f,"One or two sentences: what you changed and which evidence motivated it.",g,a,"The complete new file content.",l].join(`
3
+ `)}s(m,"buildProposerSystemPrompt");function d(e){let t=e.evidence,n=["## CURRENT FILE CONTENT","",e.currentContent,""];if(t.weakest.length>0){n.push("## CASES WHERE THIS FILE CURRENTLY UNDERPERFORMS","");for(let o of t.weakest)n.push(`- ${o.name}: passes ${(o.withPassRate*100).toFixed(0)}% with the file vs ${(o.withoutPassRate*100).toFixed(0)}% without it`);n.push("")}return t.nonDiscriminating.length>0&&n.push("## CASES THAT CARRY NO SIGNAL EITHER WAY","","These score the same with and without the file. Changing the file to chase","them is unlikely to move anything.","",...t.nonDiscriminating.map(o=>`- ${o}`),""),t.notes.length>0&&n.push("## NOTES","",...t.notes.map(o=>`- ${o}`),""),n.join(`
4
+ `)}s(d,"buildProposerData");function h(e,t,n){let o=e.lastIndexOf(n);if(o<0)return null;let r=e.lastIndexOf(t,o);return r<0?null:e.slice(r+t.length,o)}s(h,"between");function E(e){let t=e.split(`
5
+ `);for(;t.length>0&&t[0].trim()==="";)t.shift();for(;t.length>0&&t[t.length-1].trim()==="";)t.pop();if(t.length<2)return t.join(`
6
+ `);let n=t[0].trim(),o=t[t.length-1].trim(),r=/^(`{3,}|~{3,})[a-zA-Z0-9_-]*$/.test(n),i=/^(`{3,}|~{3,})$/.test(o);return r&&i?t.slice(1,-1).join(`
7
+ `):t.join(`
8
+ `)}s(E,"stripWrappingFence");function T(e,t){if(!e||e.trim()==="")return{ok:!1,reason:"proposer returned nothing"};let n=h(e,a,l);if(n==null)return{ok:!1,reason:`proposer reply had no ${a}\u2026${l} block`};let o=E(n).trim();if(o==="")return{ok:!1,reason:"proposed content was empty"};if(o===t.trim())return{ok:!1,reason:"proposal is identical to the current version"};let r=o.length/Math.max(1,t.trim().length);if(r<c)return{ok:!1,reason:`proposal retains only ${(r*100).toFixed(0)}% of the predecessor's length (floor ${(c*100).toFixed(0)}%) \u2014 treating it as a truncated or summarised reply rather than an edit`};if(r>u)return{ok:!1,reason:`proposal is ${r.toFixed(1)}x the predecessor's length (ceiling ${u}x) \u2014 treating it as runaway generation`};let i=(h(e,f,g)??"").trim();return{ok:!0,proposal:{candidateContent:o,rationale:i===""?"(proposer supplied no rationale)":i}}}s(T,"parseProposalResponse");async function O(e,t=16e3){let n=await p(m(e),d(e),t);return n==null?{ok:!1,reason:"no LLM backend available, or the proposer call failed"}:T(n,e.currentContent)}s(O,"proposeInstructionEdit");export{c as a,u as b,m as c,d,T as e,O as f};
@@ -1,4 +1,4 @@
1
- import{a as C}from"./chunk-4VZLIGMS.js";import{b as $}from"./chunk-UUMW6X2W.js";import{a as y}from"./chunk-KAWNGQS2.js";import{c as f}from"./chunk-HMMO27U4.js";import{e as h,f as w}from"./chunk-H2ORWIEY.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{a as C}from"./chunk-4VZLIGMS.js";import{b as $}from"./chunk-3VYV6ZYB.js";import{a as y}from"./chunk-7AZKPX2J.js";import{c as f}from"./chunk-HMMO27U4.js";import{e as h,f as w}from"./chunk-H2ORWIEY.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 +1,4 @@
1
- import{a as f}from"../../chunk-XICLXXRH.js";import{a as g}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import{c as d}from"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import{b as l}from"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{b as m,d as p}from"../../chunk-H2ORWIEY.js";import{d as n,h as c}from"../../chunk-O6C2UGBY.js";import{a}from"../../chunk-ZLLER3HP.js";import{Flags as h}from"@oclif/core";var o=class w extends g{static{a(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:h.string({char:"e",description:"Email address"}),password:h.string({char:"p",description:"Password (for non-interactive use)"})};async run(){let{flags:r}=await this.parse(w),s=r.email,t=r.password;if(!s||!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:i,password:u}=await import("@inquirer/prompts");s||(s=await i({message:"Email:"})),t||(t=await u({message:"Password:"}))}let e;try{e=await p("/auth/login",{method:"POST",body:{email:s,password:t},timeoutMs:2e4})}catch(i){throw i instanceof m&&i.statusCode===401&&this.error("Invalid email or password."),i}let v=e.expiresAt??new Date(Date.now()+3600*1e3).toISOString();n({accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:v,email:e.email}),c(e.accessToken,process.env.RULEMETRIC_API_URL),await l(),await f(this.log.bind(this),this.warn.bind(this),this.config.version),d("auth_login",{},this.config.version),this.log(`Logged in as ${e.email}`)}};export{o as default};
1
+ import{a as f}from"../../chunk-XICLXXRH.js";import{a as w}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import{c}from"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import{b as n}from"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{b as r,d as a}from"../../chunk-H2ORWIEY.js";import{b as m,d,h as u,i as g}from"../../chunk-O6C2UGBY.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
+
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
+ 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{b as f,c as O}from"../chunk-V5U3E4BZ.js";import{c as g,d as h,e as P}from"../chunk-MVM6OGAF.js";import"../chunk-KKDHD4XA.js";import"../chunk-SZ62CP55.js";import{d as R}from"../chunk-3BVHPQZW.js";import"../chunk-SMGSLY5N.js";import"../chunk-PJ3WHQ67.js";import"../chunk-N7ODX6PO.js";import{a as x}from"../chunk-PPKPCXJD.js";import"../chunk-IZTIYR5Q.js";import"../chunk-V44SRRYR.js";import"../chunk-U6XEU573.js";import"../chunk-VLOX6KOM.js";import"../chunk-3AV3GTMP.js";import{a as y}from"../chunk-H2ORWIEY.js";import{a as T,g as p}from"../chunk-O6C2UGBY.js";import{a as u}from"../chunk-ZLLER3HP.js";import{spawnSync as H}from"node:child_process";import{existsSync as S,readFileSync as X}from"node:fs";import{join as $}from"node:path";var m=class b extends x{static{u(this,"Diagnostics")}static description='Diagnose capture / proxy / connectivity problems (e.g. a client-side "502 Bad Gateway")';static examples=["<%= config.bin %> diagnostics"];baseUrl(){return process.env.RULEMETRIC_API_URL??T().apiUrl??y}async checkDirect(){let t=process.env.HTTPS_PROXY,e=process.env.HTTP_PROXY;delete process.env.HTTPS_PROXY,delete process.env.HTTP_PROXY;let o=new AbortController,i=setTimeout(()=>o.abort(),8e3);try{return(await globalThis.fetch(`${this.baseUrl()}/health`,{signal:o.signal})).ok}catch{return!1}finally{clearTimeout(i),t!==void 0&&(process.env.HTTPS_PROXY=t),e!==void 0&&(process.env.HTTP_PROXY=e)}}configuredProxy(){if(process.env.HTTPS_PROXY)return process.env.HTTPS_PROXY;for(let t of["settings.local.json","settings.json"]){let e=$(process.cwd(),".claude",t);if(S(e))try{let o=JSON.parse(X(e,"utf8"));if(o.env?.HTTPS_PROXY)return o.env.HTTPS_PROXY}catch{}}return null}checkThroughProxy(t){let e=H("curl",["-sS","-x",t,"--max-time","8","-o","/dev/null","-w","%{http_code}",`${this.baseUrl()}/health`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return e.error||typeof e.stdout!="string"?null:e.stdout.trim()==="200"}async run(){await this.parse(b);let t=process.version,e=this.configuredProxy(),o=e!=null,[i,s,c]=await Promise.all([this.checkDirect(),P(g),P(h)]),l=o&&e?this.checkThroughProxy(e):null,n=u((d,v,A)=>{let w=v===null?"\u2013":v?"[OK]":"[!!]";this.log(` ${w} ${d.padEnd(22)} ${A}`)},"line");this.log("RuleMetric diagnostics"),this.log(""),n("Node",!f(t),`${t}${f(t)?" (< 20.11 \u2014 breaks the bundled proxy)":""}`),n("API (direct)",i,`${this.baseUrl()}/health ${i?"reachable":"UNREACHABLE"}`),n("Authenticated",p(),p()?"yes":"no \u2014 run `rulemetric auth login`"),n("Proxy configured",o?!0:null,o?e:"no HTTPS_PROXY set"),o&&(n("Gateway :"+g,s,s?"listening":"NOT listening"),n("mitmproxy :"+h,c,c?"listening":"not listening (gateway should route direct)"),n("API (via proxy)",l,l===null?"inconclusive (curl unavailable)":l?"reachable":"FAILED \u2014 502/blocked through your proxy"));let r=R();n("claude CLI",r.claudeBin!=null,r.claudeBin??"not found \u2014 LLM features (grading, distill) will no-op"),n("codex CLI",r.codexBin!=null?!0:null,r.codexBin?`${r.codexBin}${r.codexConfiguredModel?` (model ${r.codexConfiguredModel})`:""}`:"not found \u2014 optional; enables the cross-vendor reviewer (evals validate-judge)");let a=O({nodeVersion:t,directApiOk:i,httpsProxySet:o,gatewayAlive:s,mitmproxyAlive:c,proxyPathOk:l});this.log("");let _=a.severity==="ok"?"[OK]":a.severity==="warn"?"[!!]":"[XX]";this.log(`${_} ${a.headline}`);for(let d of a.hints)this.log(` \u2022 ${d}`)}};export{m as default};
1
+ import{b,c as S}from"../chunk-V5U3E4BZ.js";import{a as X}from"../chunk-VLXCQ2DC.js";import"../chunk-I2DZGJRR.js";import{c as k,d as T,e as w}from"../chunk-MVM6OGAF.js";import"../chunk-KKDHD4XA.js";import"../chunk-SZ62CP55.js";import{d as H}from"../chunk-OPUI7CM2.js";import"../chunk-MODFTCZY.js";import"../chunk-PJ3WHQ67.js";import"../chunk-N7ODX6PO.js";import{a as _}from"../chunk-PPKPCXJD.js";import"../chunk-IZTIYR5Q.js";import"../chunk-V44SRRYR.js";import"../chunk-U6XEU573.js";import"../chunk-VLOX6KOM.js";import"../chunk-3AV3GTMP.js";import{a as R,e as O}from"../chunk-H2ORWIEY.js";import{a as A,g as h}from"../chunk-O6C2UGBY.js";import{a as m}from"../chunk-ZLLER3HP.js";import{spawnSync as E}from"node:child_process";import{existsSync as U,readFileSync as L}from"node:fs";import{join as B}from"node:path";var x=class u extends _{static{m(this,"Diagnostics")}static description='Diagnose capture / proxy / connectivity problems (e.g. a client-side "502 Bad Gateway")';static examples=["<%= config.bin %> diagnostics"];baseUrl(){return process.env.RULEMETRIC_API_URL??A().apiUrl??R}async checkDirect(){let t=process.env.HTTPS_PROXY,o=process.env.HTTP_PROXY;delete process.env.HTTPS_PROXY,delete process.env.HTTP_PROXY;let i=new AbortController,s=setTimeout(()=>i.abort(),8e3);try{return(await globalThis.fetch(`${this.baseUrl()}/health`,{signal:i.signal})).ok}catch{return!1}finally{clearTimeout(s),t!==void 0&&(process.env.HTTPS_PROXY=t),o!==void 0&&(process.env.HTTP_PROXY=o)}}configuredProxy(){if(process.env.HTTPS_PROXY)return process.env.HTTPS_PROXY;for(let t of["settings.local.json","settings.json"]){let o=B(process.cwd(),".claude",t);if(U(o))try{let i=JSON.parse(L(o,"utf8"));if(i.env?.HTTPS_PROXY)return i.env.HTTPS_PROXY}catch{}}return null}checkThroughProxy(t){let o=E("curl",["-sS","-x",t,"--max-time","8","-o","/dev/null","-w","%{http_code}",`${this.baseUrl()}/health`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return o.error||typeof o.stdout!="string"?null:o.stdout.trim()==="200"}async run(){await this.parse(u);let t=process.version,o=this.configuredProxy(),i=o!=null,[s,g,v]=await Promise.all([this.checkDirect(),w(k),w(T)]),p=i&&o?this.checkThroughProxy(o):null,n=m((e,c,a)=>{let d=c===null?"\u2013":c?"[OK]":"[!!]";this.log(` ${d} ${e.padEnd(22)} ${a}`)},"line");this.log("RuleMetric diagnostics"),this.log(""),n("Node",!b(t),`${t}${b(t)?" (< 20.11 \u2014 breaks the bundled proxy)":""}`),n("API (direct)",s,`${this.baseUrl()}/health ${s?"reachable":"UNREACHABLE"}`),n("Authenticated",h(),h()?"yes":"no \u2014 run `rulemetric auth login`"),n("Proxy configured",i?!0:null,i?o:"no HTTPS_PROXY set"),i&&(n("Gateway :"+k,g,g?"listening":"NOT listening"),n("mitmproxy :"+T,v,v?"listening":"not listening (gateway should route direct)"),n("API (via proxy)",p,p===null?"inconclusive (curl unavailable)":p?"reachable":"FAILED \u2014 502/blocked through your proxy"));let l=H();n("claude CLI",l.claudeBin!=null,l.claudeBin??"not found \u2014 LLM features (grading, distill) will no-op"),n("codex CLI",l.codexBin!=null?!0:null,l.codexBin?`${l.codexBin}${l.codexConfiguredModel?` (model ${l.codexConfiguredModel})`:""}`:"not found \u2014 optional; enables the cross-vendor reviewer (evals validate-judge)");let r=null;if(h()&&s)try{r=await O("/api/workers/health")}catch{r=null}if(r){let e=r.worker;n("Worker",!!e.active,e.present?e.active?`online (last heartbeat ${e.ageSeconds??"?"}s ago${e.clientVersion?`, v${e.clientVersion}`:""})`:`NOT RUNNING \u2014 last heartbeat ${M(e.ageSeconds)} ago`:"never connected \u2014 no worker has ever reported in");let c=r.pending.reduce((a,d)=>a+d.count,0);if(c>0){let a=r.verdict.stuck.reduce((y,P)=>y+P.count,0),d=r.verdict.unclaimable.reduce((y,P)=>y+P.count,0);n("Job queue",a===0,`${c} pending`+(a>0?` \u2014 ${a} waiting on this worker`:"")+(d>0?` \u2014 ${d} need a worker with DATABASE_URL`:""))}else n("Job queue",!0,"empty")}else h()&&s&&n("Worker",null,"could not read /workers/health (older API?)");let $=X(process.cwd()),I={claude_code:"session hooks (+ proxy for instruction linking)",codex:"worker transcript sync of ~/.codex/sessions \u2014 no project config needed",cursor:"user hooks (~/.cursor/hooks.json)",copilot_agent:"workspace hooks",antigravity:"user hooks (~/.gemini/config/hooks.json)"};this.log(""),this.log(" Capture coverage (agents found on this machine):");for(let e of $)this.log(` \u2022 ${e.padEnd(15)} ${I[e]??"captured"}`);r&&!r.worker.active&&$.includes("codex")&&this.log(" ! Codex capture runs INSIDE the worker \u2014 it is stopped while the worker is down.");let f=S({nodeVersion:t,directApiOk:s,httpsProxySet:i,gatewayAlive:g,mitmproxyAlive:v,proxyPathOk:p});this.log("");let Y=f.severity==="ok"?"[OK]":f.severity==="warn"?"[!!]":"[XX]";this.log(`${Y} ${f.headline}`);for(let e of f.hints)this.log(` \u2022 ${e}`);if(r&&r.verdict.severity!=="ok"){let e=r.verdict.severity==="warn"?"[!!]":"[XX]";this.log(""),this.log(`${e} ${r.verdict.headline}`);for(let c of r.verdict.hints)this.log(` \u2022 ${c}`)}}};function M(u){if(u===null)return"never";if(u<90)return`${Math.round(u)}s`;let t=Math.round(u/60);return t<90?`${t}m`:`${Math.round(t/60)}h`}m(M,"formatAge");export{x as default};
@@ -1,3 +1,3 @@
1
- import{a as k,b as A,c as I}from"../../chunk-47HDPK73.js";import{e as O}from"../../chunk-6N6NTMOR.js";import"../../chunk-TIOKY2IA.js";import"../../chunk-M4YF7YO7.js";import"../../chunk-RSKQRVPJ.js";import"../../chunk-35ST2BX7.js";import"../../chunk-6UTJGOBA.js";import"../../chunk-N7TGRFVZ.js";import"../../chunk-OSIP6FUD.js";import"../../chunk-ULRVMH7O.js";import"../../chunk-PRDYXO6Z.js";import"../../chunk-QFVGUZDO.js";import"../../chunk-T4P2NV3P.js";import"../../chunk-BUWWFHGO.js";import"../../chunk-MDPN46EY.js";import"../../chunk-5RBLIVBF.js";import"../../chunk-CS2OQ3GC.js";import"../../chunk-DUP232AH.js";import"../../chunk-DO3KHK2X.js";import"../../chunk-UF6US7VU.js";import"../../chunk-MSTF7A7D.js";import"../../chunk-ZL4MZMUK.js";import"../../chunk-4HZWSFSY.js";import{k as u}from"../../chunk-KZ65LEUH.js";import"../../chunk-YQ56FQEO.js";import"../../chunk-QQ2UPNBC.js";import"../../chunk-TDD7IOV2.js";import"../../chunk-5DIOZDDZ.js";import"../../chunk-MODXEGCU.js";import"../../chunk-4VZLIGMS.js";import"../../chunk-UUMW6X2W.js";import"../../chunk-HL755A5U.js";import"../../chunk-6UEFCMR2.js";import"../../chunk-CJRYYV76.js";import"../../chunk-ZW5TAV3L.js";import"../../chunk-L2CFSMBC.js";import"../../chunk-Z72VHGV7.js";import"../../chunk-KAWNGQS2.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-K25S2MGU.js";import"../../chunk-X2ILN3KP.js";import"../../chunk-HMMO27U4.js";import"../../chunk-3BVHPQZW.js";import"../../chunk-SMGSLY5N.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as b}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{f as N}from"../../chunk-H2ORWIEY.js";import{e as P,l as g}from"../../chunk-O6C2UGBY.js";import{a as e}from"../../chunk-ZLLER3HP.js";import{trace as te,context as re}from"@opentelemetry/api";import{NodeSDK as M}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as V}from"@opentelemetry/exporter-trace-otlp-http";import{BatchSpanProcessor as $,ConsoleSpanExporter as j,SimpleSpanProcessor as q}from"@opentelemetry/sdk-trace-node";import{Resource as F}from"@opentelemetry/resources";import{ATTR_SERVICE_NAME as G,ATTR_SERVICE_VERSION as U}from"@opentelemetry/semantic-conventions";function L(t){if(!t)return{};let r={};for(let n of t.split(",")){let o=n.indexOf("=");if(o===-1)continue;let i=n.slice(0,o).trim(),a=n.slice(o+1).trim();i&&(r[i]=a)}return r}e(L,"parseOtlpHeaders");var l=null;function y(){return process.env.TELEMETRY_ENABLED!=="false"}e(y,"isTelemetryEnabled");function h(t){if(!y()||l!==null)return"off";let r=new F({[G]:t.serviceName,[U]:t.serviceVersion??"0.1.0"}),n=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,o,i;if(n){let a=L(process.env.OTEL_EXPORTER_OTLP_HEADERS),d=new V({url:`${n}/v1/traces`,headers:a});i=new $(d),o="otlp"}else if(process.env.OTEL_SPAN_EXPORT==="none")i=void 0,o="silent";else{let a=new j;i=new q(a),o="console"}return l=new M({resource:r,spanProcessors:i?[i]:[]}),l.start(),o}e(h,"initTelemetry");async function f(){l&&(await l.shutdown(),l=null)}e(f,"shutdownTelemetry");import{SpanKind as fe,SpanStatusCode as me}from"@opentelemetry/api";import{trace as Ee,context as Se}from"@opentelemetry/api";import*as p from"@sentry/node";var E=!1;function S(t){if(E)return!1;let r=process.env.SENTRY_DSN;return r?(p.init({dsn:r,serverName:t.serviceName,environment:process.env.NODE_ENV??"development",tracesSampleRate:0}),E=!0,!0):!1}e(S,"initSentry");async function m(t){E&&await p.flush(t)}e(m,"flushSentry");import{existsSync as B,mkdirSync as H,readFileSync as w,unlinkSync as D,writeFileSync as C}from"node:fs";import{dirname as K,join as v}from"node:path";import{execFileSync as Y}from"node:child_process";var c=v(g(),"evals-agent.lock");function J(t){try{return process.kill(t,0),!0}catch(r){return r.code==="EPERM"}}e(J,"pidAlive");function z(t){if(!J(t))return!1;try{let r=Y("ps",["-p",String(t),"-o","command="],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]});return/run\.js\s+evals\s+agent|evals\s+agent/.test(r)}catch{return!0}}e(z,"isLiveAgent");function Q(){try{H(K(c),{recursive:!0})}catch{}for(let t=0;t<2;t++)try{return C(c,String(process.pid),{flag:"wx"}),{ok:!0}}catch(r){if(r.code!=="EEXIST")throw r;let n=0;try{n=Number(w(c,"utf-8").trim())}catch{}if(n&&n!==process.pid&&z(n))return{ok:!1,holder:n};try{D(c)}catch{}}try{C(c,String(process.pid))}catch{}return{ok:!0}}e(Q,"acquireAgentLock");function T(){try{B(c)&&Number(w(c,"utf-8").trim())===process.pid&&D(c)}catch{}}e(T,"releaseAgentLock");var x=class t extends b{static{e(this,"EvalAgentCommand")}static description="The worker daemon: long-polls /api/work/next, claims jobs, and runs them locally. Installed as a launchd service by `rulemetric service install`.";static examples=["<%= config.bin %> evals agent"];async run(){await this.parse(t),this.requireAuth();let r=Q();if(!r.ok){this.log(`Another rulemetric evals agent is already running (pid ${r.holder}). Refusing to start a second instance.`);return}process.env.PG_APPLICATION_NAME||="rulemetric-agent",S({serviceName:"rulemetric-agent"})&&this.log("[sentry] error capture enabled");let o=h({serviceName:"rulemetric-agent"});o==="otlp"?this.log(`[otel] traces exporting to ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT}`):o==="console"?this.log("[otel] cron spans printing to stdout (set OTEL_EXPORTER_OTLP_ENDPOINT to ship to a backend)"):this.log("[otel] disabled (TELEMETRY_ENABLED=false)"),!P()&&!process.env.RULEMETRIC_API_KEY&&this.error("No auth token found. Run `rulemetric auth login` first."),this.log("Starting thin agent (Phase 4b parallel-run)..."),this.log(`Long-polling /api/work/next. Press Ctrl+C to stop.
1
+ import{a as k,b as A,c as I}from"../../chunk-47HDPK73.js";import{e as O}from"../../chunk-DTMLVFNM.js";import"../../chunk-TIOKY2IA.js";import"../../chunk-W2MOTOQE.js";import"../../chunk-3FJT6LL4.js";import"../../chunk-DAGDGAPU.js";import"../../chunk-6QKI756T.js";import"../../chunk-RSKQRVPJ.js";import"../../chunk-JEBHSV2M.js";import"../../chunk-L5ORQB25.js";import"../../chunk-Q76LGSIU.js";import"../../chunk-WEF5LPGS.js";import"../../chunk-N7TGRFVZ.js";import{j as u}from"../../chunk-3DLVY7LD.js";import"../../chunk-ZAWAPLIE.js";import"../../chunk-AIEM6VXO.js";import"../../chunk-BZUIMHHT.js";import"../../chunk-QFVGUZDO.js";import"../../chunk-ZL4MZMUK.js";import"../../chunk-5RBLIVBF.js";import"../../chunk-LEXVC7VH.js";import"../../chunk-5W55CRBJ.js";import"../../chunk-JR4CWY3J.js";import"../../chunk-ZERPMWRT.js";import"../../chunk-UR6GZGFK.js";import"../../chunk-UF6US7VU.js";import"../../chunk-YQ56FQEO.js";import"../../chunk-JGYCLDYF.js";import"../../chunk-ZWKKFAIX.js";import"../../chunk-TDD7IOV2.js";import"../../chunk-MODXEGCU.js";import"../../chunk-7DFNBRLY.js";import"../../chunk-4VZLIGMS.js";import"../../chunk-3VYV6ZYB.js";import"../../chunk-OZQV5CDT.js";import"../../chunk-6UEFCMR2.js";import"../../chunk-CJRYYV76.js";import"../../chunk-BSJBNOJT.js";import"../../chunk-L2CFSMBC.js";import"../../chunk-Z72VHGV7.js";import"../../chunk-7AZKPX2J.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-V5MJ4ICC.js";import"../../chunk-WKXTY5AM.js";import"../../chunk-HMMO27U4.js";import"../../chunk-OPUI7CM2.js";import"../../chunk-MODFTCZY.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as b}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{f as N}from"../../chunk-H2ORWIEY.js";import{e as P,l as g}from"../../chunk-O6C2UGBY.js";import{a as e}from"../../chunk-ZLLER3HP.js";import{trace as te,context as re}from"@opentelemetry/api";import{NodeSDK as M}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as V}from"@opentelemetry/exporter-trace-otlp-http";import{BatchSpanProcessor as $,ConsoleSpanExporter as j,SimpleSpanProcessor as q}from"@opentelemetry/sdk-trace-node";import{Resource as F}from"@opentelemetry/resources";import{ATTR_SERVICE_NAME as G,ATTR_SERVICE_VERSION as U}from"@opentelemetry/semantic-conventions";function L(t){if(!t)return{};let r={};for(let n of t.split(",")){let o=n.indexOf("=");if(o===-1)continue;let i=n.slice(0,o).trim(),a=n.slice(o+1).trim();i&&(r[i]=a)}return r}e(L,"parseOtlpHeaders");var l=null;function y(){return process.env.TELEMETRY_ENABLED!=="false"}e(y,"isTelemetryEnabled");function h(t){if(!y()||l!==null)return"off";let r=new F({[G]:t.serviceName,[U]:t.serviceVersion??"0.1.0"}),n=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,o,i;if(n){let a=L(process.env.OTEL_EXPORTER_OTLP_HEADERS),d=new V({url:`${n}/v1/traces`,headers:a});i=new $(d),o="otlp"}else if(process.env.OTEL_SPAN_EXPORT==="none")i=void 0,o="silent";else{let a=new j;i=new q(a),o="console"}return l=new M({resource:r,spanProcessors:i?[i]:[]}),l.start(),o}e(h,"initTelemetry");async function f(){l&&(await l.shutdown(),l=null)}e(f,"shutdownTelemetry");import{SpanKind as fe,SpanStatusCode as me}from"@opentelemetry/api";import{trace as Ee,context as Se}from"@opentelemetry/api";import*as p from"@sentry/node";var E=!1;function S(t){if(E)return!1;let r=process.env.SENTRY_DSN;return r?(p.init({dsn:r,serverName:t.serviceName,environment:process.env.NODE_ENV??"development",tracesSampleRate:0}),E=!0,!0):!1}e(S,"initSentry");async function m(t){E&&await p.flush(t)}e(m,"flushSentry");import{existsSync as B,mkdirSync as H,readFileSync as w,unlinkSync as D,writeFileSync as C}from"node:fs";import{dirname as K,join as v}from"node:path";import{execFileSync as Y}from"node:child_process";var c=v(g(),"evals-agent.lock");function J(t){try{return process.kill(t,0),!0}catch(r){return r.code==="EPERM"}}e(J,"pidAlive");function z(t){if(!J(t))return!1;try{let r=Y("ps",["-p",String(t),"-o","command="],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]});return/run\.js\s+evals\s+agent|evals\s+agent/.test(r)}catch{return!0}}e(z,"isLiveAgent");function Q(){try{H(K(c),{recursive:!0})}catch{}for(let t=0;t<2;t++)try{return C(c,String(process.pid),{flag:"wx"}),{ok:!0}}catch(r){if(r.code!=="EEXIST")throw r;let n=0;try{n=Number(w(c,"utf-8").trim())}catch{}if(n&&n!==process.pid&&z(n))return{ok:!1,holder:n};try{D(c)}catch{}}try{C(c,String(process.pid))}catch{}return{ok:!0}}e(Q,"acquireAgentLock");function T(){try{B(c)&&Number(w(c,"utf-8").trim())===process.pid&&D(c)}catch{}}e(T,"releaseAgentLock");var x=class t extends b{static{e(this,"EvalAgentCommand")}static description="The worker daemon: long-polls /api/work/next, claims jobs, and runs them locally. Installed as a launchd service by `rulemetric service install`.";static examples=["<%= config.bin %> evals agent"];async run(){await this.parse(t),this.requireAuth();let r=Q();if(!r.ok){this.log(`Another rulemetric evals agent is already running (pid ${r.holder}). Refusing to start a second instance.`);return}process.env.PG_APPLICATION_NAME||="rulemetric-agent",S({serviceName:"rulemetric-agent"})&&this.log("[sentry] error capture enabled");let o=h({serviceName:"rulemetric-agent"});o==="otlp"?this.log(`[otel] traces exporting to ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT}`):o==="console"?this.log("[otel] cron spans printing to stdout (set OTEL_EXPORTER_OTLP_ENDPOINT to ship to a backend)"):this.log("[otel] disabled (TELEMETRY_ENABLED=false)"),!P()&&!process.env.RULEMETRIC_API_KEY&&this.error("No auth token found. Run `rulemetric auth login` first."),this.log("Starting thin agent (Phase 4b parallel-run)..."),this.log(`Long-polling /api/work/next. Press Ctrl+C to stop.
2
2
  `);let a=new AbortController,d=new k({providers:[A()],statePath:v(g(),"transcript-sync-state.json"),importTranscript:e(s=>N("/api/sessions/import",s),"importTranscript"),log:e(s=>this.log(`[transcript-sync] ${s}`),"log")});I(d,{signal:a.signal,log:e(s=>this.log(`[transcript-sync] ${s}`),"log")});let R=e(async s=>{this.log(`
3
3
  [${s}] shutting down agent...`),a.abort(),await Promise.allSettled([m(2e3),f(),u()]),T(),process.exit(0)},"shutdown");process.on("SIGINT",()=>{R("SIGINT")}),process.on("SIGTERM",()=>{R("SIGTERM")});let _=!1;try{await O({signal:a.signal,log:e(s=>this.log(s),"log"),version:this.config.version,readInstalledVersion:e(()=>{try{return JSON.parse(w(v(this.config.root,"package.json"),"utf-8")).version??null}catch{return null}},"readInstalledVersion"),onVersionDrift:e(()=>{_=!0},"onVersionDrift")}),_&&(this.log("[upgrade] Installed CLI version changed \u2014 restarting worker onto the new code."),await Promise.allSettled([m(2e3),f(),u()]),T(),process.exit(1))}finally{T(),await u()}}};export{x as default};
@@ -1,4 +1,4 @@
1
- import{a as k}from"../../chunk-CJRYYV76.js";import{b as $}from"../../chunk-ZW5TAV3L.js";import"../../chunk-L2CFSMBC.js";import"../../chunk-Z72VHGV7.js";import"../../chunk-KAWNGQS2.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-K25S2MGU.js";import"../../chunk-HMMO27U4.js";import"../../chunk-SMGSLY5N.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as w}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as n}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as h}from"../../chunk-ZLLER3HP.js";import{Args as A,Flags as r}from"@oclif/core";var m=class y extends w{static{h(this,"EvalAutoRun")}static description="Run evals in a loop until the effect verdict is statistically powered (\xA76f auto-run-to-power)";static examples=["<%= config.bin %> evals auto-run <target-id> # preview (cost + plan)","<%= config.bin %> evals auto-run <target-id> --yes # run until powered / budget","<%= config.bin %> evals auto-run <target-id> --yes --max-runs 120 --batch-parallel 4"];static args={targetId:A.string({description:"Eval target ID",required:!0})};static flags={yes:r.boolean({char:"y",description:"Actually run. Without this, only previews the plan + cost."}),"max-runs":r.integer({description:"Hard ceiling on completed runs",default:200}),"batch-parallel":r.integer({description:"Concurrent executions within a batch",default:3}),timeout:r.integer({description:"Timeout per eval in ms",default:12e4}),model:r.string({description:"Model for eval execution"}),"grader-model":r.string({description:"Model for grading"}),"skip-baseline":r.boolean({description:"Skip without_target runs (no delta \u2014 not recommended)",default:!1})};async run(){let{args:C,flags:e}=await this.parse(y);this.requireAuth();let i=C.targetId,c=20,a=await n(`/api/eval-targets/${i}`),l=await n(`/api/eval-targets/${i}/evals`);l.length===0&&this.error(`No active cases on "${a.name}". Generate some (\`evals create\` / the web Generate button) or run \`evals refine-cases\` first.`);let b=l.length*(e["skip-baseline"]?1:2),f=Math.ceil(e["max-runs"]/b);if(this.log(`Auto-run "${a.name}" v${a.version} toward a powered \xB1${c}pp verdict.`),this.log(`Plan: up to ${e["max-runs"]} runs (${l.length} active case(s) \xD7 ${e["skip-baseline"]?1:2}/batch = ${b}/batch, \u2264${f} batches). Each run is a synthetic \`claude -p\` execution + grade.`),this.log('Note: this is a controlled synthetic A/B. For a DEPLOYED instruction with real usage, the Insights observational verdict is cheaper and uses real sessions \u2014 auto-run is for pre-deploy, catalog skills, or targets with no real "without" cohort.'),!e.yes){this.log(`
1
+ import{a as k}from"../../chunk-CJRYYV76.js";import{b as $}from"../../chunk-BSJBNOJT.js";import"../../chunk-L2CFSMBC.js";import"../../chunk-Z72VHGV7.js";import"../../chunk-7AZKPX2J.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-V5MJ4ICC.js";import"../../chunk-HMMO27U4.js";import"../../chunk-MODFTCZY.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as w}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as n}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as h}from"../../chunk-ZLLER3HP.js";import{Args as A,Flags as r}from"@oclif/core";var m=class y extends w{static{h(this,"EvalAutoRun")}static description="Run evals in a loop until the effect verdict is statistically powered (\xA76f auto-run-to-power)";static examples=["<%= config.bin %> evals auto-run <target-id> # preview (cost + plan)","<%= config.bin %> evals auto-run <target-id> --yes # run until powered / budget","<%= config.bin %> evals auto-run <target-id> --yes --max-runs 120 --batch-parallel 4"];static args={targetId:A.string({description:"Eval target ID",required:!0})};static flags={yes:r.boolean({char:"y",description:"Actually run. Without this, only previews the plan + cost."}),"max-runs":r.integer({description:"Hard ceiling on completed runs",default:200}),"batch-parallel":r.integer({description:"Concurrent executions within a batch",default:3}),timeout:r.integer({description:"Timeout per eval in ms",default:12e4}),model:r.string({description:"Model for eval execution"}),"grader-model":r.string({description:"Model for grading"}),"skip-baseline":r.boolean({description:"Skip without_target runs (no delta \u2014 not recommended)",default:!1})};async run(){let{args:C,flags:e}=await this.parse(y);this.requireAuth();let i=C.targetId,c=20,a=await n(`/api/eval-targets/${i}`),l=await n(`/api/eval-targets/${i}/evals`);l.length===0&&this.error(`No active cases on "${a.name}". Generate some (\`evals create\` / the web Generate button) or run \`evals refine-cases\` first.`);let b=l.length*(e["skip-baseline"]?1:2),f=Math.ceil(e["max-runs"]/b);if(this.log(`Auto-run "${a.name}" v${a.version} toward a powered \xB1${c}pp verdict.`),this.log(`Plan: up to ${e["max-runs"]} runs (${l.length} active case(s) \xD7 ${e["skip-baseline"]?1:2}/batch = ${b}/batch, \u2264${f} batches). Each run is a synthetic \`claude -p\` execution + grade.`),this.log('Note: this is a controlled synthetic A/B. For a DEPLOYED instruction with real usage, the Insights observational verdict is cheaper and uses real sessions \u2014 auto-run is for pre-deploy, catalog skills, or targets with no real "without" cohort.'),!e.yes){this.log(`
2
2
  Preview only. Re-run with --yes to start.`);return}let t={runsCompleted:0,maxRuns:e["max-runs"],batchesRun:0,maxBatches:f},x={targetId:i,targetVersion:a.version,iteration:1,timeout:e.timeout,model:e.model,graderModel:e["grader-model"],skipGrading:!1,targetType:a.type,targetName:a.name};for(;;){let s;try{s=await n(`/api/eval-targets/${i}/judge-calibration`)}catch(o){this.log(`
3
3
  \u25A0 stopping \u2014 could not read the power check: ${o instanceof Error?o.message:String(o)}`);break}let E={powered:s.powerCheck?.powered??!1,mde:s.powerCheck?.mde==null?1/0:s.powerCheck.mde},B=s.caseDiscrimination??{total:0,discriminating:0,nonDiscriminating:0,unpaired:0},p=k(E,B,t,{targetEffectPp:c});if(this.log(`
4
4
  ${p.action==="stop"?"\u25A0":"\u25B8"} ${p.reason}`),p.action==="stop")break;let v=await n(`/api/eval-targets/${i}/evals`);if(v.length===0){this.log("\u25A0 no active cases left \u2014 stopping.");break}let{completed:g,failed:D}=await $({cases:v,targetContent:a.content,concurrency:e["batch-parallel"],runNumber:t.batchesRun+1,opts:x,skipBaseline:e["skip-baseline"],onLog:h(o=>this.log(o),"onLog")});if(t.runsCompleted+=g,t.batchesRun+=1,this.log(`Batch ${t.batchesRun}: ${g} completed, ${D} failed \u2014 ${t.runsCompleted}/${t.maxRuns} runs, ${t.batchesRun}/${t.maxBatches} batches.`),g===0){this.log("\u25A0 batch produced 0 completed runs \u2014 the executor appears broken (check the model / `claude -p`). Aborting.");break}}let d=await n(`/api/eval-targets/${i}/judge-calibration`),u=d.powerCheck?.mde,R=u==null||!Number.isFinite(u)?"unknown":`\xB1${Math.round(u*100)}pp`;this.log(`
@@ -1,4 +1,4 @@
1
- import{b as h,c as f}from"../../chunk-4O7MJUPH.js";import"../../chunk-X2ILN3KP.js";import{a as m}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as c}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as u}from"../../chunk-ZLLER3HP.js";import{Args as p,Flags as v}from"@oclif/core";var d=class b extends m{static{u(this,"EvalBenchmarkCommand")}static description="Aggregate eval runs into a benchmark for a target";static examples=["<%= config.bin %> evals benchmark <target-id>","<%= config.bin %> evals benchmark <target-id> --iteration 2"];static args={targetId:p.string({description:"Eval target ID",required:!0})};static flags={iteration:v.integer({description:"Filter runs by iteration",default:1})};async run(){let{args:o,flags:l}=await this.parse(b);this.requireAuth();let g=await c(`/api/eval-targets/${o.targetId}`);this.log(`Aggregating benchmark for "${g.name}" v${g.version}, iteration ${l.iteration}`);let a=await h(o.targetId,l.iteration);a.totalRuns===0&&this.error("No completed runs found. Run evals first with `rulemetric evals run`."),this.log(`
1
+ import{b as h,c as f}from"../../chunk-LETTPEG4.js";import"../../chunk-WKXTY5AM.js";import{a as m}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as c}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as u}from"../../chunk-ZLLER3HP.js";import{Args as p,Flags as v}from"@oclif/core";var d=class b extends m{static{u(this,"EvalBenchmarkCommand")}static description="Aggregate eval runs into a benchmark for a target";static examples=["<%= config.bin %> evals benchmark <target-id>","<%= config.bin %> evals benchmark <target-id> --iteration 2"];static args={targetId:p.string({description:"Eval target ID",required:!0})};static flags={iteration:v.integer({description:"Filter runs by iteration",default:1})};async run(){let{args:o,flags:l}=await this.parse(b);this.requireAuth();let g=await c(`/api/eval-targets/${o.targetId}`);this.log(`Aggregating benchmark for "${g.name}" v${g.version}, iteration ${l.iteration}`);let a=await h(o.targetId,l.iteration);a.totalRuns===0&&this.error("No completed runs found. Run evals first with `rulemetric evals run`."),this.log(`
2
2
  Aggregated ${a.totalRuns} runs
3
3
  `);for(let[e,n]of Object.entries(a.runSummary)){this.log(`${e}:`);for(let[r,i]of Object.entries(n)){let s=i;this.log(` ${r}: mean=${s.mean} stddev=${s.stddev} [${s.min}, ${s.max}]`)}}let t=a.verdict;if(t)if(this.log(`
4
4
  Verdict (${t.mode}, baseline=${t.baseline}):`),!t.sufficient)this.log(` ${t.insufficientReason??"insufficient data"} \u2014 no effect claimed`);else{let e=t.delta>=0?"+":"";this.log(` pass-rate delta: ${e}${(t.delta*100).toFixed(0)}% (n=${t.nWith} paired)`),this.log(` 95% CI: ${(t.ci.lower*100).toFixed(0)}\u2013${(t.ci.upper*100).toFixed(0)}%`),t.pValue!=null&&this.log(` McNemar p: ${t.pValue.toFixed(4)}`),this.log(` significant: ${t.significant?"YES":"no"}`)}if(a.notes.length>0){this.log(`
@@ -1,4 +1,4 @@
1
- import{b as P,c as C}from"../../chunk-WYF5BIQW.js";import{a as V}from"../../chunk-4VZLIGMS.js";import{a as N}from"../../chunk-KAWNGQS2.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-K25S2MGU.js";import"../../chunk-X2ILN3KP.js";import{c as F}from"../../chunk-HMMO27U4.js";import"../../chunk-SMGSLY5N.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as A}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as w,f as m,g as S}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as k}from"../../chunk-ZLLER3HP.js";import{createInterface as _}from"node:readline/promises";import{Args as q,Flags as g}from"@oclif/core";var $=class O extends A{static{k(this,"EvalOptimizeCommand")}static description="Iteratively optimize eval target content using eval results as feedback";static examples=["<%= config.bin %> evals optimize <target-id>","<%= config.bin %> evals optimize <target-id> --auto --max-iterations 3"];static args={targetId:q.string({description:"Eval target ID",required:!0})};static flags={auto:g.boolean({description:"Skip interactive review, apply suggestions automatically",default:!1}),"max-iterations":g.integer({description:"Maximum optimization iterations",default:5}),threshold:g.string({description:"Stop if pass rate reaches this threshold (0-1)",default:"0.95"}),model:g.string({description:"Model for eval execution"}),"analyzer-model":g.string({description:"Model for analysis/suggestions"}),timeout:g.integer({description:"Timeout per eval in ms",default:12e4})};async run(){let{args:n,flags:e}=await this.parse(O);this.requireAuth();let t=await w(`/api/eval-targets/${n.targetId}`),i=await w(`/api/eval-targets/${n.targetId}/evals`);i.length===0&&this.error("No evals found. Create some first with `rulemetric evals create`.");let s=[...i].sort(()=>Math.random()-.5),c=Math.ceil(s.length*.6),u=s.slice(0,c),d=s.slice(c);this.log(`Optimizing "${t.name}" v${t.version}`),this.log(`Evals: ${u.length} train, ${d.length} test`);let h=parseFloat(e.threshold);this.log(`Config: max ${e["max-iterations"]} iterations, threshold ${(h*100).toFixed(0)}%`),e.auto&&this.log("Mode: auto (no interactive review)"),this.log("");let T=t.version,f=0,x=0;for(let l=1;l<=e["max-iterations"];l++){this.log(`
1
+ import{b as P,c as C}from"../../chunk-QH7PCQHM.js";import{a as V}from"../../chunk-4VZLIGMS.js";import{a as N}from"../../chunk-7AZKPX2J.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-V5MJ4ICC.js";import"../../chunk-WKXTY5AM.js";import{c as F}from"../../chunk-HMMO27U4.js";import"../../chunk-MODFTCZY.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as A}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as w,f as m,g as S}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as k}from"../../chunk-ZLLER3HP.js";import{createInterface as _}from"node:readline/promises";import{Args as q,Flags as g}from"@oclif/core";var $=class O extends A{static{k(this,"EvalOptimizeCommand")}static description="Iteratively optimize eval target content using eval results as feedback";static examples=["<%= config.bin %> evals optimize <target-id>","<%= config.bin %> evals optimize <target-id> --auto --max-iterations 3"];static args={targetId:q.string({description:"Eval target ID",required:!0})};static flags={auto:g.boolean({description:"Skip interactive review, apply suggestions automatically",default:!1}),"max-iterations":g.integer({description:"Maximum optimization iterations",default:5}),threshold:g.string({description:"Stop if pass rate reaches this threshold (0-1)",default:"0.95"}),model:g.string({description:"Model for eval execution"}),"analyzer-model":g.string({description:"Model for analysis/suggestions"}),timeout:g.integer({description:"Timeout per eval in ms",default:12e4})};async run(){let{args:n,flags:e}=await this.parse(O);this.requireAuth();let t=await w(`/api/eval-targets/${n.targetId}`),i=await w(`/api/eval-targets/${n.targetId}/evals`);i.length===0&&this.error("No evals found. Create some first with `rulemetric evals create`.");let s=[...i].sort(()=>Math.random()-.5),c=Math.ceil(s.length*.6),u=s.slice(0,c),d=s.slice(c);this.log(`Optimizing "${t.name}" v${t.version}`),this.log(`Evals: ${u.length} train, ${d.length} test`);let h=parseFloat(e.threshold);this.log(`Config: max ${e["max-iterations"]} iterations, threshold ${(h*100).toFixed(0)}%`),e.auto&&this.log("Mode: auto (no interactive review)"),this.log("");let T=t.version,f=0,x=0;for(let l=1;l<=e["max-iterations"];l++){this.log(`
2
2
  === Iteration ${l} ===`),this.log("Running train evals...");let b=await this.runEvalsOnTarget(t,u,e),p=this.computePassRate(b);if(this.log(`Train pass rate: ${(p*100).toFixed(1)}%`),p>=h){this.log(`Train score ${(p*100).toFixed(1)}% >= threshold ${(h*100).toFixed(0)}%. Stopping.`);let o=await this.runEvalsOnTarget(t,d,e),z=this.computePassRate(o);this.log(`Final test score: ${(z*100).toFixed(1)}%`),await m("/api/optimization-runs",{evalTargetId:t.id,type:"content",iteration:l,inputVersion:t.version,trainScore:p,testScore:z,analysis:{reason:"threshold_reached"},status:"completed"});break}this.log("Analyzing results...");let M=b.map(o=>({evalName:o.evalName,prompt:o.prompt,expectations:o.expectations,grading:o.grading})),a=await V({content:t.content,evalResults:M,model:e["analyzer-model"]??e.model,timeout:e.timeout});this.log(`
3
3
  Assessment: ${a.overallAssessment}`),this.log(`Suggestions: ${a.suggestions.length}`);for(let o of a.suggestions)this.log(` - [${o.section}] ${o.reasoning}`);if(a.proposedContent===t.content){this.log("No changes proposed. Stopping."),await m("/api/optimization-runs",{evalTargetId:t.id,type:"content",iteration:l,inputVersion:t.version,trainScore:p,analysis:{reason:"no_changes"},status:"completed"});break}if(!e.auto&&!await this.confirm(`
4
4
  Apply the proposed changes as a new version? [y/N] `)){this.log("Changes not applied. Stopping."),await m("/api/optimization-runs",{evalTargetId:t.id,type:"content",iteration:l,inputVersion:t.version,trainScore:p,analysis:{reason:"user_declined",suggestions:a.suggestions},status:"completed"});break}let r=await S(`/api/eval-targets/${t.id}`,{content:a.proposedContent});this.log(`Created v${r.version}`),this.log(`Running test evals on v${t.version} (baseline) and v${r.version}...`);let E=await this.runEvalsOnTarget(t,d,e),R=await this.runEvalsOnTarget(r,d,e),v=this.computePassRate(R),I=this.computePassRate(E);this.log(`Test pass rate: v${t.version} ${(I*100).toFixed(1)}% \u2192 v${r.version} ${(v*100).toFixed(1)}%`);let y=P(E,R);if(y&&this.log(C(y,t.version,r.version)),await m("/api/optimization-runs",{evalTargetId:t.id,type:"content",iteration:l,inputVersion:t.version,outputVersion:r.version,trainScore:p,testScore:v,analysis:{suggestions:a.suggestions,overallAssessment:a.overallAssessment,priorTestScore:I,verdict:y},status:"completed"}),v>f)f=v,T=r.version,x=0;else if(x++,x>=2){this.log("No improvement for 2 consecutive iterations. Stopping.");break}t=r}this.log(`
@@ -1,4 +1,4 @@
1
- import{b as w}from"../../chunk-UUMW6X2W.js";import"../../chunk-SMGSLY5N.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as f}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as g,f as p,h as v}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as d}from"../../chunk-ZLLER3HP.js";import{Args as P,Flags as b}from"@oclif/core";var r=d(i=>i==null?"n/a":`${Math.round(i*100)}%`,"pct"),c=class i extends f{static{d(this,"EvalRefineCases")}static description="Retire non-discriminating eval cases and regenerate discriminating replacements (\xA76e)";static examples=["<%= config.bin %> evals refine-cases <target-id> # preview","<%= config.bin %> evals refine-cases <target-id> --yes # apply: retire + regenerate","<%= config.bin %> evals refine-cases <target-id> --yes --no-generate"];static args={targetId:P.string({description:"Eval target ID",required:!0})};static flags={yes:b.boolean({char:"y",description:"Apply (retire + regenerate). Without this, only previews."}),"no-generate":b.boolean({description:"Retire dead cases but do not regenerate replacements."})};async run(){let{args:$,flags:o}=await this.parse(i);this.requireAuth();let n=$.targetId,s=await g(`/api/eval-targets/${n}`),m=await g(`/api/eval-targets/${n}/judge-calibration`),t=m.caseDiscrimination;if(!t||t.cases.length===0&&t.unpairedCases.length===0){this.log("No case-discrimination data yet \u2014 run some evals with AND without the target first (`evals run` / the web Run Evals button), then refine.");return}let u=t.cases.filter(e=>!e.discriminating),a=[...u.map(e=>({evalId:e.evalId,name:e.name,feedback:{name:e.name,withPassRate:e.withPassRate,withoutPassRate:e.withoutPassRate,reason:e.note}})),...t.unpairedCases.map(e=>({evalId:e.evalId,name:e.name,feedback:{name:e.name,withPassRate:e.withPassRate??0,withoutPassRate:e.withoutPassRate,reason:"runs in only one cohort (no with-vs-without comparison possible)"}}))];if(this.log(`Target "${s.name}" v${s.version} \u2014 judge ${m.judge.currentModel??"(unstamped)"}`),this.log(`${t.total} diagnosable case(s): ${t.discriminating} discriminate, ${t.nonDiscriminating} flat/wrong-sign, ${t.unpaired} unpaired.`),a.length===0){this.log("Every case discriminates \u2014 nothing to retire. \u{1F389}");return}this.log(`
1
+ import{b as w}from"../../chunk-3VYV6ZYB.js";import"../../chunk-MODFTCZY.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as f}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as g,f as p,h as v}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as d}from"../../chunk-ZLLER3HP.js";import{Args as P,Flags as b}from"@oclif/core";var r=d(i=>i==null?"n/a":`${Math.round(i*100)}%`,"pct"),c=class i extends f{static{d(this,"EvalRefineCases")}static description="Retire non-discriminating eval cases and regenerate discriminating replacements (\xA76e)";static examples=["<%= config.bin %> evals refine-cases <target-id> # preview","<%= config.bin %> evals refine-cases <target-id> --yes # apply: retire + regenerate","<%= config.bin %> evals refine-cases <target-id> --yes --no-generate"];static args={targetId:P.string({description:"Eval target ID",required:!0})};static flags={yes:b.boolean({char:"y",description:"Apply (retire + regenerate). Without this, only previews."}),"no-generate":b.boolean({description:"Retire dead cases but do not regenerate replacements."})};async run(){let{args:$,flags:o}=await this.parse(i);this.requireAuth();let n=$.targetId,s=await g(`/api/eval-targets/${n}`),m=await g(`/api/eval-targets/${n}/judge-calibration`),t=m.caseDiscrimination;if(!t||t.cases.length===0&&t.unpairedCases.length===0){this.log("No case-discrimination data yet \u2014 run some evals with AND without the target first (`evals run` / the web Run Evals button), then refine.");return}let u=t.cases.filter(e=>!e.discriminating),a=[...u.map(e=>({evalId:e.evalId,name:e.name,feedback:{name:e.name,withPassRate:e.withPassRate,withoutPassRate:e.withoutPassRate,reason:e.note}})),...t.unpairedCases.map(e=>({evalId:e.evalId,name:e.name,feedback:{name:e.name,withPassRate:e.withPassRate??0,withoutPassRate:e.withoutPassRate,reason:"runs in only one cohort (no with-vs-without comparison possible)"}}))];if(this.log(`Target "${s.name}" v${s.version} \u2014 judge ${m.judge.currentModel??"(unstamped)"}`),this.log(`${t.total} diagnosable case(s): ${t.discriminating} discriminate, ${t.nonDiscriminating} flat/wrong-sign, ${t.unpaired} unpaired.`),a.length===0){this.log("Every case discriminates \u2014 nothing to retire. \u{1F389}");return}this.log(`
2
2
  Would retire ${a.length} non-discriminating case(s):`);for(let e of u)this.log(` \u2717 ${e.name} \u2014 ${r(e.withPassRate)} with vs ${r(e.withoutPassRate)} without (\u0394${(e.separation*100).toFixed(0)}pp) \u2014 ${e.note}`);for(let e of t.unpairedCases)this.log(` \u2717 ${e.name} \u2014 ${r(e.withPassRate)} with vs ${r(e.withoutPassRate)} without \u2014 unpaired`);if(!o.yes){this.log(`
3
3
  Preview only. Re-run with --yes to retire ${a.length} case(s)${o["no-generate"]?"":" and generate replacements"}.`);return}for(let e of a)await v(`/api/eval-targets/${n}/evals/${e.evalId}`,{retire:!0,retiredReason:e.feedback.reason}),this.log(` retired ${e.name}`);if(o["no-generate"]){this.log(`
4
4
  Retired ${a.length} case(s). Skipped regeneration (--no-generate).`);return}this.log(`
@@ -1,3 +1,3 @@
1
- import{a as k}from"../../chunk-ZW5TAV3L.js";import"../../chunk-L2CFSMBC.js";import"../../chunk-Z72VHGV7.js";import"../../chunk-KAWNGQS2.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-K25S2MGU.js";import"../../chunk-HMMO27U4.js";import"../../chunk-SMGSLY5N.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as $}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as v,f as h}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as R}from"../../chunk-ZLLER3HP.js";import{Args as I,Flags as g}from"@oclif/core";var b=class _ extends ${static{R(this,"EvalRunCommand")}static description="Run evals against a target, optionally grade results, and post to API";static examples=["<%= config.bin %> evals run <target-id>","<%= config.bin %> evals run <target-id> --parallel 3 --runs-per-eval 2","<%= config.bin %> evals run <target-id> --skip-baseline --skip-grading"];static args={targetId:I.string({description:"Eval target ID",required:!0})};static flags={parallel:g.integer({description:"Number of parallel eval executions",default:1}),"runs-per-eval":g.integer({description:"Number of runs per eval for variance analysis",default:1}),iteration:g.integer({description:"Iteration number for tracking",default:1}),"skip-baseline":g.boolean({description:"Skip baseline (without_target) runs",default:!1}),"skip-grading":g.boolean({description:"Skip LLM grading step",default:!1}),model:g.string({description:"Model for eval execution (default: user configured)"}),"grader-model":g.string({description:"Model for grading (default: same as execution model)"}),timeout:g.integer({description:"Timeout per eval in ms",default:12e4})};async run(){let{args:c,flags:r}=await this.parse(_);this.requireAuth();let i=await v(`/api/eval-targets/${c.targetId}`),l=await v(`/api/eval-targets/${c.targetId}/evals`);l.length===0&&this.error(`No evals found for target "${i.name}". Create some with \`rulemetric evals create\`.`),this.log(`Running ${l.length} eval(s) for "${i.name}" v${i.version}`),this.log(`Config: ${r["runs-per-eval"]} run(s) per eval, parallel=${r.parallel}, iteration=${r.iteration}`),r["skip-baseline"]&&this.log("Skipping baseline runs"),r["skip-grading"]&&this.log("Skipping grading"),this.log("");let m=[{name:"with_target",content:i.content}];r["skip-baseline"]||m.push({name:"without_target"});let p=[];for(let a of l)for(let n of m)for(let t=1;t<=r["runs-per-eval"];t++)p.push({eval_:a,configuration:n.name,targetContent:n.content,runNumber:t});let u=[],y=r.parallel;for(let a=0;a<p.length;a+=y){let n=p.slice(a,a+y),t=await Promise.all(n.map(d=>this.executeAndGrade(d,i,r)));u.push(...t)}this.log(""),this.log("Posting results to API...");for(let a of u)await h("/api/eval-runs",a);try{await h(`/api/eval-targets/${c.targetId}/label-state`,{})}catch{}this.log(""),this.log("=== Results Summary ===");for(let a of m){let n=u.filter(e=>e.configuration===a.name),t=n.filter(e=>e.status==="completed"),d=t.filter(e=>Object.keys(e.grading).length>0);if(this.log(`
1
+ import{a as k}from"../../chunk-BSJBNOJT.js";import"../../chunk-L2CFSMBC.js";import"../../chunk-Z72VHGV7.js";import"../../chunk-7AZKPX2J.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-V5MJ4ICC.js";import"../../chunk-HMMO27U4.js";import"../../chunk-MODFTCZY.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as $}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import{e as v,f as h}from"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as R}from"../../chunk-ZLLER3HP.js";import{Args as I,Flags as g}from"@oclif/core";var b=class _ extends ${static{R(this,"EvalRunCommand")}static description="Run evals against a target, optionally grade results, and post to API";static examples=["<%= config.bin %> evals run <target-id>","<%= config.bin %> evals run <target-id> --parallel 3 --runs-per-eval 2","<%= config.bin %> evals run <target-id> --skip-baseline --skip-grading"];static args={targetId:I.string({description:"Eval target ID",required:!0})};static flags={parallel:g.integer({description:"Number of parallel eval executions",default:1}),"runs-per-eval":g.integer({description:"Number of runs per eval for variance analysis",default:1}),iteration:g.integer({description:"Iteration number for tracking",default:1}),"skip-baseline":g.boolean({description:"Skip baseline (without_target) runs",default:!1}),"skip-grading":g.boolean({description:"Skip LLM grading step",default:!1}),model:g.string({description:"Model for eval execution (default: user configured)"}),"grader-model":g.string({description:"Model for grading (default: same as execution model)"}),timeout:g.integer({description:"Timeout per eval in ms",default:12e4})};async run(){let{args:c,flags:r}=await this.parse(_);this.requireAuth();let i=await v(`/api/eval-targets/${c.targetId}`),l=await v(`/api/eval-targets/${c.targetId}/evals`);l.length===0&&this.error(`No evals found for target "${i.name}". Create some with \`rulemetric evals create\`.`),this.log(`Running ${l.length} eval(s) for "${i.name}" v${i.version}`),this.log(`Config: ${r["runs-per-eval"]} run(s) per eval, parallel=${r.parallel}, iteration=${r.iteration}`),r["skip-baseline"]&&this.log("Skipping baseline runs"),r["skip-grading"]&&this.log("Skipping grading"),this.log("");let m=[{name:"with_target",content:i.content}];r["skip-baseline"]||m.push({name:"without_target"});let p=[];for(let a of l)for(let n of m)for(let t=1;t<=r["runs-per-eval"];t++)p.push({eval_:a,configuration:n.name,targetContent:n.content,runNumber:t});let u=[],y=r.parallel;for(let a=0;a<p.length;a+=y){let n=p.slice(a,a+y),t=await Promise.all(n.map(d=>this.executeAndGrade(d,i,r)));u.push(...t)}this.log(""),this.log("Posting results to API...");for(let a of u)await h("/api/eval-runs",a);try{await h(`/api/eval-targets/${c.targetId}/label-state`,{})}catch{}this.log(""),this.log("=== Results Summary ===");for(let a of m){let n=u.filter(e=>e.configuration===a.name),t=n.filter(e=>e.status==="completed"),d=t.filter(e=>Object.keys(e.grading).length>0);if(this.log(`
2
2
  ${a.name}:`),this.log(` Runs: ${t.length}/${n.length} completed`),d.length>0){let e=d.map(o=>o.grading.summary?.pass_rate??0),s=e.reduce((o,f)=>o+f,0)/e.length;this.log(` Avg pass_rate: ${(s*100).toFixed(1)}%`)}for(let e of n){let s=l.find(x=>x.id===e.evalId)?.name??e.evalId,o=e.grading.summary?.pass_rate,f=o!==void 0?` pass_rate=${(o*100).toFixed(0)}%`:"",w=e.timing.duration_ms?` ${(e.timing.duration_ms/1e3).toFixed(1)}s`:"";this.log(` [${e.status}] ${s} run#${e.runNumber}${f}${w}`)}}if(!r["skip-baseline"]&&u.length>0){let a=u.filter(t=>t.configuration==="with_target"&&Object.keys(t.grading).length>0),n=u.filter(t=>t.configuration==="without_target"&&Object.keys(t.grading).length>0);if(a.length>0&&n.length>0){let t=a.map(s=>s.grading.summary?.pass_rate??0).reduce((s,o)=>s+o,0)/a.length,d=n.map(s=>s.grading.summary?.pass_rate??0).reduce((s,o)=>s+o,0)/n.length,e=t-d;this.log(`
3
3
  Delta: ${e>0?"+":""}${(e*100).toFixed(1)}% (with_target vs without_target)`)}}}async executeAndGrade(c,r,i){return k(c,{targetId:r.id,targetVersion:r.version,iteration:i.iteration,timeout:i.timeout,model:i.model,graderModel:i["grader-model"],skipGrading:i["skip-grading"],targetType:r.type,targetName:r.name},l=>this.log(l))}};export{b as default};
@@ -1 +1 @@
1
- import{c,d as m}from"../../chunk-HL755A5U.js";import"../../chunk-6UEFCMR2.js";import"../../chunk-KAWNGQS2.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-K25S2MGU.js";import"../../chunk-HMMO27U4.js";import"../../chunk-3BVHPQZW.js";import"../../chunk-SMGSLY5N.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as u}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as r}from"../../chunk-ZLLER3HP.js";import{Args as p,Flags as s}from"@oclif/core";var o=r(n=>n==null?"\u2014":`${(n*100).toFixed(0)}%`,"pct"),g=class n extends u{static{r(this,"EvalValidateJudge")}static description="Score a second model against your human judge-review labels (\xA76g validation pass)";static examples=["<%= config.bin %> evals validate-judge <target-id> # auto-detect installed CLIs","<%= config.bin %> evals validate-judge <target-id> --engine codex --model gpt-5.5","<%= config.bin %> evals validate-judge <target-id> --model claude-sonnet-5 --json","<%= config.bin %> evals validate-judge <target-id> --limit 5 # quick sample"];static args={targetId:p.string({description:"Eval target ID",required:!0})};static flags={model:s.string({description:"Second reviewer model. Default: resolved from your installed tooling (codex: your ~/.codex/config.toml model; claude: a tier that differs from the original judge)."}),engine:s.string({description:"CLI that runs the second reviewer. `auto` prefers your installed codex for a cross-vendor reviewer \u2014 two Claude models share a training lineage, so their agreement overstates independence.",options:["auto","claude","codex"],default:"auto"}),limit:s.integer({description:"Sample only the N most-recently-annotated runs (cost control / smoke)"}),"skip-reviewed":s.boolean({description:"Only re-grade assertions this reviewer model has not ruled on yet",default:!1}),parallel:s.integer({description:"Concurrent re-grades",default:3}),timeout:s.integer({description:"Timeout per re-grade in ms",default:12e4}),json:s.boolean({description:"Emit the full report as JSON"})};async run(){let{args:h,flags:i}=await this.parse(n);this.requireAuth();let a;try{a=await m({targetId:h.targetId,engineFlag:i.engine,modelFlag:i.model,limit:i.limit,parallel:i.parallel,timeoutMs:i.timeout,skipReviewed:i["skip-reviewed"],log:r(t=>this.log(t),"log"),warn:r(t=>this.warn(t),"warn")})}catch(t){throw t instanceof c&&this.error(t.message),t}let{report:e,judgeModels:l,reviewerModel:d}=a;if(l.length===1&&l[0]===d&&this.warn(`Second reviewer resolved to the SAME model as the original judge (${l[0]}) \u2014 this measures self-consistency, not independent review.`),i.json){this.log(JSON.stringify({target:a.targetName,judgeA:l,judgeB:d,persisted:a.persisted,alreadyReviewed:a.alreadyReviewed,...e},null,2));return}if(e.pairs===0&&a.alreadyReviewed>0){this.log(`All ${a.alreadyReviewed} labeled assertion(s) already reviewed by ${d} \u2014 nothing new to grade.`);return}if(this.log(""),this.log(`Second reviewer: ${d} \u2014 scored against ${e.pairs} human-labeled assertion(s)`+(e.skipped?` (${e.skipped} skipped)`:"")),this.log(""),this.log(` reviewer vs HUMAN: ${o(e.bVsHuman.overall.rate)} overall \xB7 ${o(e.bVsHuman.onJudgePass.rate)} where judge passed \xB7 ${o(e.bVsHuman.onJudgeFail.rate)} where judge failed`),this.log(` original judge vs human: ${o(e.aVsHuman.overall.rate)} (your approve rate)`),this.log(` reviewer vs judge: ${o(e.bVsA.overall.rate)} (inter-model, not truth)`),this.log(` Cohen's \u03BA (reviewer vs human): ${e.kappaBvsHuman==null?"undefined (degenerate marginals)":e.kappaBvsHuman.toFixed(2)}`),this.log(""),e.suggestedAnchorWeight!=null&&this.log(` suggested \xA76g anchor weight if used as a passive label source: ${e.suggestedAnchorWeight.toFixed(2)} (misclassification attenuation (2\xB7acc\u22121)\xB2; validated:false either way)`),e.disagreements.length>0){this.log(""),this.log(` ${e.disagreements.length} disagreement(s) with your labels \u2014 flagged on the Review tab:`);for(let t of e.disagreements.slice(0,10))this.log(` run ${t.runId.slice(0,8)} #${t.expectationIndex}: human=${t.humanPassed?"pass":"fail"} reviewer=${t.judgeBPassed?"pass":"fail"} \u2014 ${t.text.slice(0,80)}`);e.disagreements.length>10&&this.log(` \u2026 and ${e.disagreements.length-10} more (use --json for all)`)}}};export{g as default};
1
+ import{c,d as m}from"../../chunk-OZQV5CDT.js";import"../../chunk-6UEFCMR2.js";import"../../chunk-7AZKPX2J.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-V5MJ4ICC.js";import"../../chunk-HMMO27U4.js";import"../../chunk-OPUI7CM2.js";import"../../chunk-MODFTCZY.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as u}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a as r}from"../../chunk-ZLLER3HP.js";import{Args as p,Flags as s}from"@oclif/core";var o=r(n=>n==null?"\u2014":`${(n*100).toFixed(0)}%`,"pct"),g=class n extends u{static{r(this,"EvalValidateJudge")}static description="Score a second model against your human judge-review labels (\xA76g validation pass)";static examples=["<%= config.bin %> evals validate-judge <target-id> # auto-detect installed CLIs","<%= config.bin %> evals validate-judge <target-id> --engine codex --model gpt-5.5","<%= config.bin %> evals validate-judge <target-id> --model claude-sonnet-5 --json","<%= config.bin %> evals validate-judge <target-id> --limit 5 # quick sample"];static args={targetId:p.string({description:"Eval target ID",required:!0})};static flags={model:s.string({description:"Second reviewer model. Default: resolved from your installed tooling (codex: your ~/.codex/config.toml model; claude: a tier that differs from the original judge)."}),engine:s.string({description:"CLI that runs the second reviewer. `auto` prefers your installed codex for a cross-vendor reviewer \u2014 two Claude models share a training lineage, so their agreement overstates independence.",options:["auto","claude","codex"],default:"auto"}),limit:s.integer({description:"Sample only the N most-recently-annotated runs (cost control / smoke)"}),"skip-reviewed":s.boolean({description:"Only re-grade assertions this reviewer model has not ruled on yet",default:!1}),parallel:s.integer({description:"Concurrent re-grades",default:3}),timeout:s.integer({description:"Timeout per re-grade in ms",default:12e4}),json:s.boolean({description:"Emit the full report as JSON"})};async run(){let{args:h,flags:i}=await this.parse(n);this.requireAuth();let a;try{a=await m({targetId:h.targetId,engineFlag:i.engine,modelFlag:i.model,limit:i.limit,parallel:i.parallel,timeoutMs:i.timeout,skipReviewed:i["skip-reviewed"],log:r(t=>this.log(t),"log"),warn:r(t=>this.warn(t),"warn")})}catch(t){throw t instanceof c&&this.error(t.message),t}let{report:e,judgeModels:l,reviewerModel:d}=a;if(l.length===1&&l[0]===d&&this.warn(`Second reviewer resolved to the SAME model as the original judge (${l[0]}) \u2014 this measures self-consistency, not independent review.`),i.json){this.log(JSON.stringify({target:a.targetName,judgeA:l,judgeB:d,persisted:a.persisted,alreadyReviewed:a.alreadyReviewed,...e},null,2));return}if(e.pairs===0&&a.alreadyReviewed>0){this.log(`All ${a.alreadyReviewed} labeled assertion(s) already reviewed by ${d} \u2014 nothing new to grade.`);return}if(this.log(""),this.log(`Second reviewer: ${d} \u2014 scored against ${e.pairs} human-labeled assertion(s)`+(e.skipped?` (${e.skipped} skipped)`:"")),this.log(""),this.log(` reviewer vs HUMAN: ${o(e.bVsHuman.overall.rate)} overall \xB7 ${o(e.bVsHuman.onJudgePass.rate)} where judge passed \xB7 ${o(e.bVsHuman.onJudgeFail.rate)} where judge failed`),this.log(` original judge vs human: ${o(e.aVsHuman.overall.rate)} (your approve rate)`),this.log(` reviewer vs judge: ${o(e.bVsA.overall.rate)} (inter-model, not truth)`),this.log(` Cohen's \u03BA (reviewer vs human): ${e.kappaBvsHuman==null?"undefined (degenerate marginals)":e.kappaBvsHuman.toFixed(2)}`),this.log(""),e.suggestedAnchorWeight!=null&&this.log(` suggested \xA76g anchor weight if used as a passive label source: ${e.suggestedAnchorWeight.toFixed(2)} (misclassification attenuation (2\xB7acc\u22121)\xB2; validated:false either way)`),e.disagreements.length>0){this.log(""),this.log(` ${e.disagreements.length} disagreement(s) with your labels \u2014 flagged on the Review tab:`);for(let t of e.disagreements.slice(0,10))this.log(` run ${t.runId.slice(0,8)} #${t.expectationIndex}: human=${t.humanPassed?"pass":"fail"} reviewer=${t.judgeBPassed?"pass":"fail"} \u2014 ${t.text.slice(0,80)}`);e.disagreements.length>10&&this.log(` \u2026 and ${e.disagreements.length-10} more (use --json for all)`)}}};export{g as default};
@@ -1 +1 @@
1
- import{b as y,c as h}from"../../chunk-JAPCCEKF.js";import{B as l,E as g}from"../../chunk-2JRDG4LJ.js";import"../../chunk-I2DZGJRR.js";import{c as e,g as p,i as m,k as f}from"../../chunk-MVM6OGAF.js";import"../../chunk-KKDHD4XA.js";import{b as d,d as u}from"../../chunk-SZ62CP55.js";import{a as c}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a}from"../../chunk-ZLLER3HP.js";import{spawn as S}from"node:child_process";import{existsSync as v,readFileSync as R,statSync as C,writeFileSync as M}from"node:fs";import{homedir as T}from"node:os";import{join as o}from"node:path";var s=o(T(),".config","rulemetric"),x=o(s,"proxy-addon.version"),_=o(s,"proxy.pid"),w=o(s,"proxy-drift-restart.at"),E=10*6e4,n=class P extends c{static{a(this,"GatewayEnsure")}static description="Ensure the gateway proxy is running (called by hooks, not for direct use)";static hidden=!0;async run(){await this.parse(P),this.maybeRestartStaleProxy();let t=await p(e);if(t.status==="ours-live"){let r=h(i=>{i==="vscode"?l(e):g(e)});r.length>0&&console.error(`[RuleMetric] Gateway healthy again \u2014 restored ${r.join(", ")} proxy settings.`);return}if(t.status==="foreign"){if(m())return;let r=y(e);console.error(`[RuleMetric] A non-RuleMetric process holds :${e} \u2014 cannot start gateway. `+(r.length>0?`Unpinned ${r.join(", ")} proxy settings so editors are not routed through it. `:"")+"Run `rulemetric diagnostics` if Claude Code HTTPS requests fail.");return}try{f(this.config.version)}catch(r){console.error(`[RuleMetric] Could not start gateway: ${r.message}`)}}maybeRestartStaleProxy(){try{if(!v(x))return;let t=R(x,"utf-8").trim();if(!t||t===this.config.version)return;let r=R(_,"utf-8").trim(),i=Number(r);if(!Number.isFinite(i)||!u(i,d))return;try{if(Date.now()-C(w).mtimeMs<E)return}catch{}M(w,new Date().toISOString()),S(process.execPath,[process.argv[1],"proxy","restart"],{detached:!0,stdio:"ignore"}).unref(),console.error(`[RuleMetric] Capture proxy is running CLI ${t} but ${this.config.version} is installed \u2014 restarting it in the background.`)}catch{}}};export{n as default};
1
+ import{b as y,c as h}from"../../chunk-CYKELSHS.js";import{B as l,E as g}from"../../chunk-VLXCQ2DC.js";import"../../chunk-I2DZGJRR.js";import{c as e,g as p,i as m,k as f}from"../../chunk-MVM6OGAF.js";import"../../chunk-KKDHD4XA.js";import{b as d,d as u}from"../../chunk-SZ62CP55.js";import{a as c}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import"../../chunk-O6C2UGBY.js";import{a}from"../../chunk-ZLLER3HP.js";import{spawn as S}from"node:child_process";import{existsSync as v,readFileSync as R,statSync as C,writeFileSync as M}from"node:fs";import{homedir as T}from"node:os";import{join as o}from"node:path";var s=o(T(),".config","rulemetric"),x=o(s,"proxy-addon.version"),_=o(s,"proxy.pid"),w=o(s,"proxy-drift-restart.at"),E=10*6e4,n=class P extends c{static{a(this,"GatewayEnsure")}static description="Ensure the gateway proxy is running (called by hooks, not for direct use)";static hidden=!0;async run(){await this.parse(P),this.maybeRestartStaleProxy();let t=await p(e);if(t.status==="ours-live"){let r=h(i=>{i==="vscode"?l(e):g(e)});r.length>0&&console.error(`[RuleMetric] Gateway healthy again \u2014 restored ${r.join(", ")} proxy settings.`);return}if(t.status==="foreign"){if(m())return;let r=y(e);console.error(`[RuleMetric] A non-RuleMetric process holds :${e} \u2014 cannot start gateway. `+(r.length>0?`Unpinned ${r.join(", ")} proxy settings so editors are not routed through it. `:"")+"Run `rulemetric diagnostics` if Claude Code HTTPS requests fail.");return}try{f(this.config.version)}catch(r){console.error(`[RuleMetric] Could not start gateway: ${r.message}`)}}maybeRestartStaleProxy(){try{if(!v(x))return;let t=R(x,"utf-8").trim();if(!t||t===this.config.version)return;let r=R(_,"utf-8").trim(),i=Number(r);if(!Number.isFinite(i)||!u(i,d))return;try{if(Date.now()-C(w).mtimeMs<E)return}catch{}M(w,new Date().toISOString()),S(process.execPath,[process.argv[1],"proxy","restart"],{detached:!0,stdio:"ignore"}).unref(),console.error(`[RuleMetric] Capture proxy is running CLI ${t} but ${this.config.version} is installed \u2014 restarting it in the background.`)}catch{}}};export{n as default};
@@ -1 +1 @@
1
- import{a as pt}from"../../chunk-6XEC6474.js";import{B as ut,E as dt,H as gt,I as ht,e as z,f as Q,g as Z,i as tt,j as et,k as st,n as ot,p as it,q as rt,r as at,u as nt,v as lt,y as ct}from"../../chunk-2JRDG4LJ.js";import{a as q,b as W,c as m,d as J,g as A}from"../../chunk-I2DZGJRR.js";import{c as s,g as X,h as D,i as F,k as O,l as V}from"../../chunk-MVM6OGAF.js";import{e as B}from"../../chunk-KKDHD4XA.js";import"../../chunk-SZ62CP55.js";import{a as f}from"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as Y}from"../../chunk-XICLXXRH.js";import{a as M}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import{c as N}from"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import{b as L}from"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import{a as G}from"../../chunk-O6C2UGBY.js";import{a as v}from"../../chunk-ZLLER3HP.js";import{Flags as w}from"@oclif/core";import{execFileSync as ft,spawnSync as l}from"node:child_process";import{existsSync as c}from"node:fs";import{homedir as mt}from"node:os";import{join as _,dirname as Ct}from"node:path";function vt(){try{let d=ft("/bin/sh",["-c","command -v rulemetric"],{encoding:"utf-8"}).trim();if(d&&c(d))return Ct(d)}catch{}}v(vt,"resolveHookBinDir");function wt(){try{return ft("launchctl",["list","com.rulemetric.gateway"],{stdio:["ignore","pipe","pipe"]}),!0}catch{return!1}}v(wt,"isGatewayLaunchdManaged");var o=_(mt(),".mitmproxy","mitmproxy-ca-cert.pem"),R=class d extends M{static{v(this,"HooksInstall")}static description="Install session tracking hooks and context capture proxy for Claude Code";static examples=["<%= config.bin %> hooks install","<%= config.bin %> hooks install --global","<%= config.bin %> hooks install --no-proxy"];static flags={"no-proxy":w.boolean({default:!1,description:"Skip proxy/gateway configuration (hooks only)"}),"project-dir":w.string({description:"Project directory to install hooks in (defaults to cwd)"}),global:w.boolean({char:"g",default:!1,description:"Install hooks globally (~/.claude/settings.json) so all projects are tracked"}),"statusline-usage":w.boolean({default:!1,description:"Install the statusline shim so Claude Code pushes live rate_limits on every refresh (makes /usage rings update in real time without needing the proxy)"})};async run(){let{flags:i}=await this.parse(d),r=i.global,n=r?mt():i["project-dir"]??process.cwd(),x=_(n,".claude"),y=st(x,r),K=r?"settings.json":"settings.local.json",k=i["no-proxy"],P=!1,g=k?"no_proxy_flag":void 0,h=!1,S=[];r&&this.log(`Installing hooks globally \u2192 ${y}`);let{settings:a,recoveredBackup:$}=z(y);if($&&this.log(`[!!] ${y} was not valid JSON \u2014 backed it up to ${$} and continued with a fresh file.`),!r){let e=ot(_(x,"settings.json"),s);e.migrated&&(this.log("[OK] Moved RuleMetric machine-local state out of the shared .claude/settings.json (it now lives in .claude/settings.local.json)"),e.backupPath&&this.log(` Previous shared settings backed up \u2192 ${e.backupPath}`),e.removedStatusline&&c(q)&&!A(a)&&(a.statusLine=m))}let I=G();(I.accessToken||process.env.RULEMETRIC_ACCESS_TOKEN)&&!I.apiKey&&!process.env.RULEMETRIC_API_KEY&&await Y(this.log.bind(this),this.warn.bind(this),this.config.version);let yt=tt(a),C=vt();if(Z(a,C),this.log(yt?`[OK] Refreshed RuleMetric Claude Code session hooks \u2192 .claude/${K}`:`[OK] Installed RuleMetric Claude Code session hooks \u2192 .claude/${K}`),!k){let e=!!f("mitmdump");if(e||(this.log(""),this.log("[!!] mitmproxy not found \u2014 installing..."),S=["brew","pipx","uv"].filter(t=>!!f(t)),e=this.installMitmproxy(),e||(this.log("[!!] Could not install mitmproxy. Skipping proxy config."),this.log(" Install manually: pipx install mitmproxy"),this.log(" Then re-run: rulemetric hooks install"))),c(o))this.log("[OK] CA certificate found");else{this.log("[..] Generating CA certificate...");let t=f("mitmdump");t&&(l(t,["--set","listen_port=0","-q"],{timeout:5e3,stdio:"ignore"}),c(o)?this.log(`[OK] CA certificate generated at ${o}`):this.log("[!!] Could not generate CA cert"))}let u=c(o);u&&!this.isCACertTrusted()?(this.log("[..] Installing CA certificate into system trust store (requires admin)..."),h=this.trustCACert(),h?this.log("[OK] CA certificate trusted by system"):(this.log("[!!] Could not install CA cert automatically."),process.platform==="darwin"?this.log(` Run manually: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${o}`):process.platform==="linux"&&this.log(` Run manually: sudo cp ${o} /usr/local/share/ca-certificates/mitmproxy-ca.crt && sudo update-ca-certificates`))):u&&(this.log("[OK] CA certificate already trusted"),h=!0);let p=wt(),b=await X(s);if(p)this.log("[OK] Gateway managed by launchd (com.rulemetric.gateway)");else if(b.status==="ours-live")this.log("[OK] Gateway already running");else if(b.status==="foreign"&&F()){this.log("[..] Restarting gateway (running build predates the identity handshake)..."),V(),await new Promise(t=>setTimeout(t,500));try{let t=O(this.config.version);this.log(`[OK] Gateway restarted (PID ${t})`)}catch(t){this.log(`[!!] Could not restart gateway: ${t.message}`)}}else if(b.status!=="foreign")try{let t=O(this.config.version);this.log(`[OK] Gateway started (PID ${t})`)}catch(t){this.log(`[!!] Could not start gateway: ${t.message}`)}let j=await D(s,{timeoutMs:4e3});if(!u)g=e?"ca_not_generated":S.length===0?"no_package_manager":"mitmproxy_install_failed",this.log("[!!] No CA certificate \u2014 NOT setting HTTPS_PROXY (capture stays hooks-only)."),this.log(" Install mitmproxy, then re-run: rulemetric hooks install");else if(j.status==="foreign"&&!p){g="gateway_port_foreign";let t=B(s);this.log(`[!!] Port :${s} is held by a process that is NOT the RuleMetric gateway \u2014 NOT setting HTTPS_PROXY.`),this.log(t?` Holding the port: ${t}`:` Could not identify the holder (try: lsof -nP -iTCP:${s} -sTCP:LISTEN)`),this.log(" Capture still works via hooks. Free the port, then re-run: rulemetric hooks install")}else if(j.status==="dead")g="gateway_not_live",this.log(`[!!] Gateway is not answering on :${s} \u2014 NOT setting HTTPS_PROXY.`),this.log(" Capture still works via hooks. To enable deep (proxy) capture later:"),this.log(" rulemetric proxy start && rulemetric hooks install");else{let t=a.env??{};t.HTTPS_PROXY=`http://localhost:${s}`,t.NO_PROXY=et,c(o)&&(t.NODE_EXTRA_CA_CERTS=o),a.env=t,P=!0,this.log(`[OK] HTTPS_PROXY set to gateway on :${s} (verified live)`),nt(n,s,o)&&this.log("[OK] Cursor proxy configured \u2192 .cursor/settings.json"),lt(n,s,o)&&this.log("[OK] VS Code workspace proxy configured \u2192 .vscode/settings.json"),ut(s)&&this.log("[OK] VS Code user proxy configured \u2192 ~/Library/Application Support/Code/User/settings.json"),dt(s)&&this.log("[OK] Cursor user proxy configured \u2192 ~/Library/Application Support/Cursor/User/settings.json"),h?ct(s,o)&&this.log("[OK] HTTPS_PROXY set for GUI apps (launchctl + LaunchAgent)"):(g="ca_untrusted",this.log("[!!] CA not trusted \u2014 skipping machine-wide GUI proxy (would break native-app TLS)."),this.log(" Claude Code capture is unaffected. Trust the CA + re-run to enable cross-app capture."))}}if(!r){let e=it(n,C);e&&this.log(`[OK] Cursor hooks configured \u2192 ${e}`);let u=at(n,C);u&&this.log(`[OK] Copilot Agent hooks configured \u2192 ${u}`);let p=gt(n);p&&this.log(`[OK] Antigravity workspace hooks configured \u2192 ${p}`)}let E=ht();E&&this.log(`[OK] Antigravity user hooks configured \u2192 ${E}`);let H=rt(C);if(H&&this.log(`[OK] Cursor user hooks configured \u2192 ${H}`),i["statusline-usage"])if(A(a))this.log("[OK] Statusline shim already installed");else{let e=J(a);W(e),a.statusLine=m,e?this.log(`[OK] Statusline shim installed \u2192 ${m.command} (chains to: ${e})`):this.log(`[OK] Statusline shim installed \u2192 ${m.command}`),this.log(" Rate-limit rings will now update on Claude Code's statusline refresh cadence")}let{backupPath:U}=Q(y,a);U&&this.log(`[OK] Backed up previous settings \u2192 ${U}`),this.log(""),this.log("Setup complete! Next steps:"),r?(this.log(" 1. Install always-on API: rulemetric service install"),this.log(" 2. Start Claude Code in any project \u2014 all sessions tracked automatically"),this.log(""),this.log("The API service starts on login and restarts on crash.")):k?(this.log(" 1. Start Claude Code \u2014 sessions are captured by the hooks just installed"),this.log(""),this.log("No proxy means no mitmproxy / CA cert needed. The hooks capture full"),this.log("sessions on their own; re-run without --no-proxy to also capture system"),this.log("prompts for instruction-effectiveness linking.")):(this.log(" 1. Start Claude Code \u2014 sessions are captured by hooks immediately"),P?this.log(" 2. Full-depth capture is ON \u2014 the proxy is live on :"+s+"."):this.log(" 2. Enable full depth (proxy not yet live): rulemetric proxy start"),this.log(""),this.log("Hooks capture every session (lifecycle + transcript). The proxy adds the"),this.log("rendered system prompt (instruction-effectiveness linking) + cross-tool capture."),this.log(""),this.log("To capture traffic from other clients (Python, curl, etc.):"),this.log(' eval "$(rulemetric proxy env --all)"')),await L(),N("hooks_installed",{proxy:P,caTrusted:h,reason:g,installers:S,global:r},this.config.version);let T=await pt();this.log(""),T.available?this.log(`[OK] tmux found${T.version?` (v${T.version})`:""} \u2014 live send enabled`):this.log("[!!] tmux not found \u2014 live send will fall back to opening Terminal. Install with: brew install tmux")}installMitmproxy(){for(let[i,r]of[["pipx",["install","mitmproxy"]],["uv",["tool","install","mitmproxy"]],["brew",["install","mitmproxy"]]]){let n=f(i);if(n&&(this.log(` Installing via ${i}...`),l(n,[...r],{stdio:"inherit"}).status===0))return!0}return!1}isCACertTrusted(){return process.platform==="darwin"?l("security",["verify-cert","-c",o],{stdio:"pipe"}).status===0:process.platform==="linux"?c("/usr/local/share/ca-certificates/mitmproxy-ca.crt"):process.platform==="win32"?l("certutil",["-verify",o],{stdio:"pipe"}).status===0:!1}trustCACert(){return process.platform==="darwin"?l("sudo",["security","add-trusted-cert","-d","-r","trustRoot","-k","/Library/Keychains/System.keychain",o],{stdio:"inherit"}).status===0:process.platform==="linux"?l("sudo",["cp",o,"/usr/local/share/ca-certificates/mitmproxy-ca.crt"],{stdio:"inherit"}).status!==0?!1:l("sudo",["update-ca-certificates"],{stdio:"inherit"}).status===0:process.platform==="win32"?l("certutil",["-addstore","-f","Root",o],{stdio:"inherit"}).status===0:!1}};export{R as default};
1
+ import{a as pt}from"../../chunk-6XEC6474.js";import{B as ut,E as dt,H as gt,I as ht,e as z,f as Q,g as Z,i as tt,j as et,k as st,n as ot,p as it,q as rt,r as at,u as nt,v as lt,y as ct}from"../../chunk-VLXCQ2DC.js";import{a as q,b as W,c as m,d as J,g as A}from"../../chunk-I2DZGJRR.js";import{c as s,g as X,h as D,i as F,k as O,l as V}from"../../chunk-MVM6OGAF.js";import{e as B}from"../../chunk-KKDHD4XA.js";import"../../chunk-SZ62CP55.js";import{a as f}from"../../chunk-PJ3WHQ67.js";import"../../chunk-N7ODX6PO.js";import{a as Y}from"../../chunk-XICLXXRH.js";import{a as M}from"../../chunk-PPKPCXJD.js";import"../../chunk-IZTIYR5Q.js";import{c as N}from"../../chunk-V44SRRYR.js";import"../../chunk-U6XEU573.js";import{b as L}from"../../chunk-VLOX6KOM.js";import"../../chunk-3AV3GTMP.js";import"../../chunk-H2ORWIEY.js";import{a as G}from"../../chunk-O6C2UGBY.js";import{a as v}from"../../chunk-ZLLER3HP.js";import{Flags as w}from"@oclif/core";import{execFileSync as ft,spawnSync as l}from"node:child_process";import{existsSync as c}from"node:fs";import{homedir as mt}from"node:os";import{join as _,dirname as Ct}from"node:path";function vt(){try{let d=ft("/bin/sh",["-c","command -v rulemetric"],{encoding:"utf-8"}).trim();if(d&&c(d))return Ct(d)}catch{}}v(vt,"resolveHookBinDir");function wt(){try{return ft("launchctl",["list","com.rulemetric.gateway"],{stdio:["ignore","pipe","pipe"]}),!0}catch{return!1}}v(wt,"isGatewayLaunchdManaged");var o=_(mt(),".mitmproxy","mitmproxy-ca-cert.pem"),R=class d extends M{static{v(this,"HooksInstall")}static description="Install session tracking hooks and context capture proxy for Claude Code";static examples=["<%= config.bin %> hooks install","<%= config.bin %> hooks install --global","<%= config.bin %> hooks install --no-proxy"];static flags={"no-proxy":w.boolean({default:!1,description:"Skip proxy/gateway configuration (hooks only)"}),"project-dir":w.string({description:"Project directory to install hooks in (defaults to cwd)"}),global:w.boolean({char:"g",default:!1,description:"Install hooks globally (~/.claude/settings.json) so all projects are tracked"}),"statusline-usage":w.boolean({default:!1,description:"Install the statusline shim so Claude Code pushes live rate_limits on every refresh (makes /usage rings update in real time without needing the proxy)"})};async run(){let{flags:i}=await this.parse(d),r=i.global,n=r?mt():i["project-dir"]??process.cwd(),x=_(n,".claude"),y=st(x,r),K=r?"settings.json":"settings.local.json",k=i["no-proxy"],P=!1,g=k?"no_proxy_flag":void 0,h=!1,S=[];r&&this.log(`Installing hooks globally \u2192 ${y}`);let{settings:a,recoveredBackup:$}=z(y);if($&&this.log(`[!!] ${y} was not valid JSON \u2014 backed it up to ${$} and continued with a fresh file.`),!r){let e=ot(_(x,"settings.json"),s);e.migrated&&(this.log("[OK] Moved RuleMetric machine-local state out of the shared .claude/settings.json (it now lives in .claude/settings.local.json)"),e.backupPath&&this.log(` Previous shared settings backed up \u2192 ${e.backupPath}`),e.removedStatusline&&c(q)&&!A(a)&&(a.statusLine=m))}let I=G();(I.accessToken||process.env.RULEMETRIC_ACCESS_TOKEN)&&!I.apiKey&&!process.env.RULEMETRIC_API_KEY&&await Y(this.log.bind(this),this.warn.bind(this),this.config.version);let yt=tt(a),C=vt();if(Z(a,C),this.log(yt?`[OK] Refreshed RuleMetric Claude Code session hooks \u2192 .claude/${K}`:`[OK] Installed RuleMetric Claude Code session hooks \u2192 .claude/${K}`),!k){let e=!!f("mitmdump");if(e||(this.log(""),this.log("[!!] mitmproxy not found \u2014 installing..."),S=["brew","pipx","uv"].filter(t=>!!f(t)),e=this.installMitmproxy(),e||(this.log("[!!] Could not install mitmproxy. Skipping proxy config."),this.log(" Install manually: pipx install mitmproxy"),this.log(" Then re-run: rulemetric hooks install"))),c(o))this.log("[OK] CA certificate found");else{this.log("[..] Generating CA certificate...");let t=f("mitmdump");t&&(l(t,["--set","listen_port=0","-q"],{timeout:5e3,stdio:"ignore"}),c(o)?this.log(`[OK] CA certificate generated at ${o}`):this.log("[!!] Could not generate CA cert"))}let u=c(o);u&&!this.isCACertTrusted()?(this.log("[..] Installing CA certificate into system trust store (requires admin)..."),h=this.trustCACert(),h?this.log("[OK] CA certificate trusted by system"):(this.log("[!!] Could not install CA cert automatically."),process.platform==="darwin"?this.log(` Run manually: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${o}`):process.platform==="linux"&&this.log(` Run manually: sudo cp ${o} /usr/local/share/ca-certificates/mitmproxy-ca.crt && sudo update-ca-certificates`))):u&&(this.log("[OK] CA certificate already trusted"),h=!0);let p=wt(),b=await X(s);if(p)this.log("[OK] Gateway managed by launchd (com.rulemetric.gateway)");else if(b.status==="ours-live")this.log("[OK] Gateway already running");else if(b.status==="foreign"&&F()){this.log("[..] Restarting gateway (running build predates the identity handshake)..."),V(),await new Promise(t=>setTimeout(t,500));try{let t=O(this.config.version);this.log(`[OK] Gateway restarted (PID ${t})`)}catch(t){this.log(`[!!] Could not restart gateway: ${t.message}`)}}else if(b.status!=="foreign")try{let t=O(this.config.version);this.log(`[OK] Gateway started (PID ${t})`)}catch(t){this.log(`[!!] Could not start gateway: ${t.message}`)}let j=await D(s,{timeoutMs:4e3});if(!u)g=e?"ca_not_generated":S.length===0?"no_package_manager":"mitmproxy_install_failed",this.log("[!!] No CA certificate \u2014 NOT setting HTTPS_PROXY (capture stays hooks-only)."),this.log(" Install mitmproxy, then re-run: rulemetric hooks install");else if(j.status==="foreign"&&!p){g="gateway_port_foreign";let t=B(s);this.log(`[!!] Port :${s} is held by a process that is NOT the RuleMetric gateway \u2014 NOT setting HTTPS_PROXY.`),this.log(t?` Holding the port: ${t}`:` Could not identify the holder (try: lsof -nP -iTCP:${s} -sTCP:LISTEN)`),this.log(" Capture still works via hooks. Free the port, then re-run: rulemetric hooks install")}else if(j.status==="dead")g="gateway_not_live",this.log(`[!!] Gateway is not answering on :${s} \u2014 NOT setting HTTPS_PROXY.`),this.log(" Capture still works via hooks. To enable deep (proxy) capture later:"),this.log(" rulemetric proxy start && rulemetric hooks install");else{let t=a.env??{};t.HTTPS_PROXY=`http://localhost:${s}`,t.NO_PROXY=et,c(o)&&(t.NODE_EXTRA_CA_CERTS=o),a.env=t,P=!0,this.log(`[OK] HTTPS_PROXY set to gateway on :${s} (verified live)`),nt(n,s,o)&&this.log("[OK] Cursor proxy configured \u2192 .cursor/settings.json"),lt(n,s,o)&&this.log("[OK] VS Code workspace proxy configured \u2192 .vscode/settings.json"),ut(s)&&this.log("[OK] VS Code user proxy configured \u2192 ~/Library/Application Support/Code/User/settings.json"),dt(s)&&this.log("[OK] Cursor user proxy configured \u2192 ~/Library/Application Support/Cursor/User/settings.json"),h?ct(s,o)&&this.log("[OK] HTTPS_PROXY set for GUI apps (launchctl + LaunchAgent)"):(g="ca_untrusted",this.log("[!!] CA not trusted \u2014 skipping machine-wide GUI proxy (would break native-app TLS)."),this.log(" Claude Code capture is unaffected. Trust the CA + re-run to enable cross-app capture."))}}if(!r){let e=it(n,C);e&&this.log(`[OK] Cursor hooks configured \u2192 ${e}`);let u=at(n,C);u&&this.log(`[OK] Copilot Agent hooks configured \u2192 ${u}`);let p=gt(n);p&&this.log(`[OK] Antigravity workspace hooks configured \u2192 ${p}`)}let E=ht();E&&this.log(`[OK] Antigravity user hooks configured \u2192 ${E}`);let H=rt(C);if(H&&this.log(`[OK] Cursor user hooks configured \u2192 ${H}`),i["statusline-usage"])if(A(a))this.log("[OK] Statusline shim already installed");else{let e=J(a);W(e),a.statusLine=m,e?this.log(`[OK] Statusline shim installed \u2192 ${m.command} (chains to: ${e})`):this.log(`[OK] Statusline shim installed \u2192 ${m.command}`),this.log(" Rate-limit rings will now update on Claude Code's statusline refresh cadence")}let{backupPath:U}=Q(y,a);U&&this.log(`[OK] Backed up previous settings \u2192 ${U}`),this.log(""),this.log("Setup complete! Next steps:"),r?(this.log(" 1. Install always-on API: rulemetric service install"),this.log(" 2. Start Claude Code in any project \u2014 all sessions tracked automatically"),this.log(""),this.log("The API service starts on login and restarts on crash.")):k?(this.log(" 1. Start Claude Code \u2014 sessions are captured by the hooks just installed"),this.log(""),this.log("No proxy means no mitmproxy / CA cert needed. The hooks capture full"),this.log("sessions on their own; re-run without --no-proxy to also capture system"),this.log("prompts for instruction-effectiveness linking.")):(this.log(" 1. Start Claude Code \u2014 sessions are captured by hooks immediately"),P?this.log(" 2. Full-depth capture is ON \u2014 the proxy is live on :"+s+"."):this.log(" 2. Enable full depth (proxy not yet live): rulemetric proxy start"),this.log(""),this.log("Hooks capture every session (lifecycle + transcript). The proxy adds the"),this.log("rendered system prompt (instruction-effectiveness linking) + cross-tool capture."),this.log(""),this.log("To capture traffic from other clients (Python, curl, etc.):"),this.log(' eval "$(rulemetric proxy env --all)"')),await L(),N("hooks_installed",{proxy:P,caTrusted:h,reason:g,installers:S,global:r},this.config.version);let T=await pt();this.log(""),T.available?this.log(`[OK] tmux found${T.version?` (v${T.version})`:""} \u2014 live send enabled`):this.log("[!!] tmux not found \u2014 live send will fall back to opening Terminal. Install with: brew install tmux")}installMitmproxy(){for(let[i,r]of[["pipx",["install","mitmproxy"]],["uv",["tool","install","mitmproxy"]],["brew",["install","mitmproxy"]]]){let n=f(i);if(n&&(this.log(` Installing via ${i}...`),l(n,[...r],{stdio:"inherit"}).status===0))return!0}return!1}isCACertTrusted(){return process.platform==="darwin"?l("security",["verify-cert","-c",o],{stdio:"pipe"}).status===0:process.platform==="linux"?c("/usr/local/share/ca-certificates/mitmproxy-ca.crt"):process.platform==="win32"?l("certutil",["-verify",o],{stdio:"pipe"}).status===0:!1}trustCACert(){return process.platform==="darwin"?l("sudo",["security","add-trusted-cert","-d","-r","trustRoot","-k","/Library/Keychains/System.keychain",o],{stdio:"inherit"}).status===0:process.platform==="linux"?l("sudo",["cp",o,"/usr/local/share/ca-certificates/mitmproxy-ca.crt"],{stdio:"inherit"}).status!==0?!1:l("sudo",["update-ca-certificates"],{stdio:"inherit"}).status===0:process.platform==="win32"?l("certutil",["-addstore","-f","Root",o],{stdio:"inherit"}).status===0:!1}};export{R as default};