@rulemetric/cli 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-C7HW36P5.js +1 -0
- package/dist/{chunk-SDBQOHXY.js → chunk-VXKBPESK.js} +1 -1
- package/dist/commands/evals/agent.js +1 -1
- package/dist/lib/agent-loop.js +1 -1
- package/dist/lib/jobs/handlers/cron-suggest-instructions.js +1 -1
- package/dist/lib/manual-tasks.js +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +6 -6
- package/dist/chunk-W54I75IW.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as X}from"./chunk-HOQPVOMF.js";import{b as D}from"./chunk-GIRPEMTW.js";import{a as x}from"./chunk-MODXEGCU.js";import{d as J,f as B}from"./chunk-B3BHB26P.js";import{e as w,f as R}from"./chunk-GP46IPK2.js";import{b as H,c as U}from"./chunk-DS4P5C4F.js";import{a as u}from"./chunk-ZLLER3HP.js";import{readFileSync as q,realpathSync as V}from"node:fs";import y from"node:path";import A from"node:os";function Q(s){let n=y.resolve(s);if(n===y.resolve(A.homedir()))return!1;let a=y.parse(n).root;if(n===a)return!1;try{let o=V(A.tmpdir());if(V(n)===o)return!1}catch{}return!0}u(Q,"isScorableProjectPath");var Z=5,ee=Number(process.env.RULEMETRIC_MAX_SUGGESTION_PROJECTS??10),te=48,ne=.5,O=400,oe=3,re=.6,se=1;function ae(s){let n=s.bloated??[],a=new Set([...s.harmful.map(o=>o.id),...s.candidates.map(o=>o.id)]);return n.filter(o=>!a.has(o.id)).slice(0,se).map(o=>({instructionId:o.id,estimatedTokens:o.estimatedTokens,topProjectId:o.topProjectId??null,score:.55,reason:`Costs ~${o.estimatedTokens} tokens every session and measures neutral across ${o.exposures} exposed session(s) \u2014 enough data to detect an effect, and none found. Consider shortening "${o.name}" rather than removing it.`+(o.containsSafetyLanguage?" CAUTION: it contains guardrail language (destructive-command or credential rules) \u2014 preserve those lines when shortening.":"")}))}u(ae,"buildTrimProposals");async function ie(s,n,a){let o=[],i=0;for(let d of s)try{await a("/api/instruction-experiments",{instructionId:d.instructionId,projectPath:n,source:"groom"}),i++}catch(g){let m=g instanceof Error?g.message:String(g);o.push({...d,reason:`${d.reason} (not measurable by withholding: ${m})`})}return{nominated:i,unmeasurable:o}}u(ie,"nominateRemovals");function ce(s){let n=[];for(let o of s.harmful){let i=o.verdict.delta;n.push({instructionId:o.id,score:Math.min(.95,.75+Math.abs(i)),topProjectId:o.topProjectId??null,reason:`Measured harmful: sessions using "${o.name}" scored ${(i*100).toFixed(1)}pp worse across ${o.exposures} exposed session(s). Observational \u2014 review before archiving.`})}let a=new Set(s.harmful.map(o=>o.id));for(let o of s.candidates)a.has(o.id)||n.push({instructionId:o.id,score:re,topProjectId:o.topProjectId??null,reason:`Unused: "${o.name}" is ${o.reason} (${o.totalExposures} lifetime exposure(s)) but still costs context budget every session.`});return n.slice(0,oe)}u(ce,"buildRemovalProposals");function le(){let s=y.join(A.homedir(),".config","rulemetric","skills-registry.json");try{let n=q(s,"utf-8"),a=JSON.parse(n),o=new Date(a.generatedAt).getTime();return Number.isNaN(o)?"unknown":Date.now()-o>te*60*60*1e3?"stale":"fresh"}catch{return"unknown"}}u(le,"observeSkillsRegistry");var Re=u(async(s,n)=>{let a=J(),o=a!=="none";o?n.logger.info(`Scoring backend: ${a}`):n.logger.warn("No LLM backend available (claude CLI missing and ANTHROPIC_API_KEY unset); skipping relevance scoring. Removal/trim proposals still run \u2014 they need no LLM.");let i;try{i=(await w("/api/sessions/project-paths?limit="+ee)).projectPaths}catch(e){n.logger.warn(`Failed to fetch project paths: ${e instanceof Error?e.message:String(e)}`);return}if(i.length===0){n.logger.info("No recent project paths; nothing to score");return}let d=new Map;try{let e=await w("/api/projects?limit=200");for(let t of e.projects??[])t.primaryCheckoutPath&&d.set(x(t.primaryCheckoutPath),t.id)}catch(e){n.logger.warn(`Failed to fetch projects for id resolution: ${e instanceof Error?e.message:String(e)}`)}let g=new Map;try{let e=await w(`/api/catalog?limit=200&contentPreview=${O}`);for(let t of e)g.set(t.id,{id:t.id,name:t.name,description:t.description??"",tags:t.tags??[],contentPreview:(t.contentPreview??"").slice(0,O)})}catch(e){n.logger.warn(`Failed to fetch catalog: ${e instanceof Error?e.message:String(e)}`)}try{let e=await w("/api/instructions?limit=100");for(let t of e.instructions??[])g.has(t.id)||g.set(t.id,{id:t.id,name:t.name,description:t.description??"",tags:t.tags??[],contentPreview:(t.content??"").slice(0,O)})}catch(e){n.logger.warn(`Failed to fetch personal instructions: ${e instanceof Error?e.message:String(e)}`)}let m=[],p=[];try{let e=await w("/api/insights/groom-candidates");if(!e.captureHealthy)n.logger.info(`Grooming paused: ${e.reason??"capture unhealthy"}`);else{m=ce(e),p=ae(e);let t=e.safetyGuarded+e.harmfulSafetyGuarded;n.logger.info(`Removal proposals: ${m.length} (${e.harmful.length} measured-harmful, ${e.candidates.length} never-used, ${t} withheld by the safety allowlist); trim proposals: ${p.length} (${(e.bloated??[]).length} measured-neutral and expensive, ${e.trimSafetyFlagged??0} flagged as containing guardrail language)`)}}catch(e){n.logger.warn(`Failed to fetch groom candidates: ${e instanceof Error?e.message:String(e)}`)}let b=[...g.values()];if(b.length===0&&m.length===0&&p.length===0){n.logger.info("No candidate instructions and nothing to retire; nothing to score");return}n.logger.info(`Scoring ${b.length} candidates across ${i.length} project(s)`);let M=0,l=null,I=new Set;for(let e of i)try{let t=x(e);if(!Q(t)){n.logger.info(`Skipping ${t}: not a project directory (home/root)`);continue}let f=D(t),k=o&&f.length>0;f.length===0&&n.logger.info(`${t}: insufficient language signals; removal/trim only`);let v=X(t),z={name:y.basename(t),description:v.description,languages:f,topics:v.topics,dependencies:v.dependencies},E=k?U(b):[];k&&n.logger.info(`Scoring ${b.length} candidates for ${t} in ${E.length} batch(es)`);let C=[],$=0;for(let r of E)try{let c=await B(H(z,r),"",4096);if(!c){$++;continue}let T=c.recommendations??[];for(let P of T)typeof P.instructionId=="string"&&typeof P.score=="number"&&typeof P.reason=="string"&&C.push({instructionId:P.instructionId,score:P.score,reason:P.reason})}catch(c){$++,n.logger.warn(`Batch failed for ${t}: ${c instanceof Error?c.message:String(c)}`)}$>0&&n.logger.warn(`${$}/${E.length} batch(es) failed for ${t} (backend ${a}); suggestions are partial`),k&&C.length===0&&n.logger.warn(`No usable LLM output for ${t} (backend ${a})`);let K=C.filter(r=>r.score>=ne).sort((r,c)=>c.score-r.score).slice(0,Z),_=d.get(t),W=l===null||l===t;l===null&&(l=t);let N=u(r=>r.topProjectId?r.topProjectId===_:W,"placeHere"),F=m.filter(N),{nominated:L,unmeasurable:G}=await ie(F,t,R);L>0&&n.logger.info(`${t}: ${L} removal candidate(s) nominated for randomised withholding instead of the feed`);let h=[...K.map(r=>({instructionId:r.instructionId,score:r.score,reason:r.reason,kind:"add"})),...G.map(({topProjectId:r,...c})=>({...c,kind:"remove"})),...p.filter(N).map(({estimatedTokens:r,topProjectId:c,...T})=>({...T,kind:"trim"}))];if(h.length===0){n.logger.info(`Nothing to suggest for ${t}`);continue}await R("/api/instruction-suggestions/batch-upsert",{projectPath:t,..._?{projectId:_}:{},suggestions:h}),n.logger.info(`${t}: ${h.filter(r=>r.kind==="add").length} add + ${h.filter(r=>r.kind==="remove").length} remove + ${h.filter(r=>r.kind==="trim").length} trim`);for(let r of h)r.kind!=="add"&&I.add(r.instructionId);let Y=new Set(G.map(r=>r.instructionId));for(let r of F)Y.has(r.instructionId)||I.add(r.instructionId);M++}catch(t){n.logger.warn(`Failed to score ${e}: ${t instanceof Error?t.message:String(t)}`)}let j=[...m.filter(e=>!I.has(e.instructionId)),...p.filter(e=>!I.has(e.instructionId)).map(({estimatedTokens:e,...t})=>t)];if(j.length>0&&l)try{let e=new Set(p.map(t=>t.instructionId));await R("/api/instruction-suggestions/batch-upsert",{projectPath:l,...d.get(l)?{projectId:d.get(l)}:{},suggestions:j.map(({topProjectId:t,...f})=>({...f,kind:e.has(f.instructionId)?"trim":"remove"}))}),n.logger.info(`Orphan sweep: ${j.length} proposal(s) whose project was not scored this run placed on ${l}`)}catch(e){n.logger.warn(`Orphan sweep failed: ${e instanceof Error?e.message:String(e)}`)}let S=le();if(S==="unknown")n.logger.warn("Skills registry unreadable or has no usable generatedAt; leaving suggestion staleness unchanged");else try{await R("/api/instruction-suggestions/mark-stale",{stale:S==="stale"}),S==="stale"?n.logger.warn("Skills registry is stale (>48h); marked catalog-skill suggestions stale"):n.logger.info("Skills registry is fresh; cleared staleness on catalog-skill suggestions")}catch{}n.logger.info(`Done: scored ${M}/${i.length} projects`)},"cronSuggestInstructions");export{Q as a,ae as b,ie as c,ce as d,Re as e};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as K}from"./chunk-BFDXMIXO.js";import{b as G}from"./chunk-IEQDLURA.js";import{a as W}from"./chunk-X5WOTWT4.js";import{b as L}from"./chunk-NEP5EWHJ.js";import{a as D}from"./chunk-3TSZ77FB.js";import{a as V}from"./chunk-I2CXODLD.js";import{a as P}from"./chunk-ZYGBABMZ.js";import{a as x}from"./chunk-JPW4LP2O.js";import{a as y}from"./chunk-PZS55PW2.js";import{a as U}from"./chunk-3CX6YUEX.js";import{e as S}from"./chunk-
|
|
1
|
+
import{c as K}from"./chunk-BFDXMIXO.js";import{b as G}from"./chunk-IEQDLURA.js";import{a as W}from"./chunk-X5WOTWT4.js";import{b as L}from"./chunk-NEP5EWHJ.js";import{a as D}from"./chunk-3TSZ77FB.js";import{a as V}from"./chunk-I2CXODLD.js";import{a as P}from"./chunk-ZYGBABMZ.js";import{a as x}from"./chunk-JPW4LP2O.js";import{a as y}from"./chunk-PZS55PW2.js";import{a as U}from"./chunk-3CX6YUEX.js";import{e as S}from"./chunk-C7HW36P5.js";import{b as C}from"./chunk-GJKHHZSQ.js";import{a as N}from"./chunk-4QW5DQNL.js";import{a as T}from"./chunk-3737WF6X.js";import{a as M}from"./chunk-NIEP5G3T.js";import{b as R}from"./chunk-5RBLIVBF.js";import{a as $}from"./chunk-GAFMAVFO.js";import{a as O}from"./chunk-ZL5LUOBZ.js";import{a as F}from"./chunk-FPOPUEA6.js";import{a as J}from"./chunk-HPN22ZIN.js";import{a as B}from"./chunk-CQARFIJB.js";import{l as H}from"./chunk-7EKHB3U7.js";import{d as A}from"./chunk-NTKO4H2K.js";import{b as E,e as I,f as _}from"./chunk-GP46IPK2.js";import{a}from"./chunk-ZLLER3HP.js";var Z={process_eval:T,process_insights:M,process_launch:L,process_send_message:P,process_conversation:N,process_session_goal:x,distill_memories:C,memory_ab:D,process_run_cleanup:V,cron_refine_cases:J,cron_retire_unused_skills:U,cron_suggest_instructions:S,cron_refresh_skills:y,cron_refresh_pricing:B,cron_eval_autorun:O,cron_auto_accept_suggestions:$,cron_instruction_training:F,cron_instruction_evolution:H,process_judge_review:W},q=Object.keys(Z),ee=new Set([]);function ne(e=process.env){return e.DATABASE_URL?q:q.filter(n=>!ee.has(n))}a(ne,"availableCapabilities");var re=3e4,te=3e4,oe=3e4,Q=500,X=1e4,se=`thin-agent-${process.pid}`,b=null;function ae(e,n,r,c){let i;try{let u=A();i={claude:u.claudeBin!=null,codex:u.codexBin!=null,codexModel:u.codexConfiguredModel}}catch{}let m=a(u=>{_("/api/workers/heartbeat",{workerType:"cli-worker",clientName:se,clientVersion:c,workerVersion:"0.1.0",currentJobId:null,inFlightCount:0,lastError:null,status:u,metadata:{capabilities:e,mode:"thin-agent",llmEngines:i}}).then(d=>{let l=d?.advisory;l&&l.message!==b?(b=l.message,s(r,{event:"worker_advisory",code:l.code,message:l.message})):l||(b=null)}).catch(d=>{s(r,{event:"presence_heartbeat_error",error:d instanceof Error?d.message:String(d)})})},"send");m("alive");let o=setInterval(()=>m("alive"),oe);n.addEventListener("abort",()=>{clearInterval(o),m("shutting_down")},{once:!0})}a(ae,"startPresenceHeartbeat");function s(e,n){try{e(JSON.stringify({ts:new Date().toISOString(),...n}))}catch{e(`[agent-loop] log_error event=${n.event}`)}}a(s,"structuredLog");function Y(e,n){return n.aborted?Promise.resolve(!1):e<=0?Promise.resolve(!0):new Promise(r=>{let c=setTimeout(()=>{n.removeEventListener("abort",i),r(!0)},e),i=a(()=>{clearTimeout(c),n.removeEventListener("abort",i),r(!1)},"onAbort");n.addEventListener("abort",i,{once:!0})})}a(Y,"abortableSleep");async function ie(e,n){let r=`capabilities=${encodeURIComponent(e.join(","))}&waitMs=${n}`,c=await I(`/api/work/next?${r}`);return c==null||typeof c=="string"?null:c}a(ie,"pollForWork");function le(e,n){return{logger:{info:a(r=>n(r),"info"),warn:a(r=>n(r),"warn"),error:a(r=>n(r),"error")},job:{attempts:e}}}a(le,"makeHelpers");async function ce(e,n,r){let c=Z[e.kind],i=Date.now();if(s(r,{event:"claim",jobId:e.id,kind:e.kind,attempts:e.attempts}),!c){let o=`unknown kind: ${e.kind}`;s(r,{event:"fail",jobId:e.id,kind:e.kind,terminal:!0,error:o}),await _(`/api/work/${e.id}/fail`,{leaseToken:e.leaseToken,error:o,terminal:!0}).catch(()=>{});return}let m=setInterval(()=>{s(r,{event:"heartbeat",jobId:e.id}),_(`/api/work/${e.id}/heartbeat`,{leaseToken:e.leaseToken}).catch(o=>{s(r,{event:"heartbeat_error",jobId:e.id,error:o instanceof Error?o.message:String(o)})})},n);try{let o=le(e.attempts,r),u=await c(e.payload,o)??{};clearInterval(m),s(r,{event:"complete",jobId:e.id,kind:e.kind,durationMs:Date.now()-i}),await _(`/api/work/${e.id}/complete`,{leaseToken:e.leaseToken,result:u})}catch(o){clearInterval(m);let u=R(o),d=o instanceof Error?o.message:String(o);s(r,{event:"fail",jobId:e.id,kind:e.kind,durationMs:Date.now()-i,terminal:u,error:d}),await _(`/api/work/${e.id}/fail`,{leaseToken:e.leaseToken,error:d,terminal:u}).catch(l=>{s(r,{event:"fail_post_error",jobId:e.id,error:l instanceof Error?l.message:String(l)})})}}a(ce,"runOne");var z=new Set(["process_eval","process_conversation","process_insights","process_session_goal","distill_memories","memory_ab","cron_suggest_instructions","cron_eval_autorun","cron_instruction_evolution","process_judge_review"]);async function Ce(e){let n=e.log??(()=>{}),r=e.pollWaitMs??re,c=e.heartbeatIntervalMs??te,i=e.capabilities??ne();s(n,{event:"agent_start",capabilities:i,pollWaitMs:r,heartbeatIntervalMs:c});try{let t=G();t.removed.length>0&&s(n,{event:"eval_worktrees_swept",removed:t.removed.length})}catch(t){s(n,{event:"eval_worktree_sweep_failed",error:t instanceof Error?t.message:String(t)})}ae(i,e.signal,n,e.version),K({signal:e.signal,log:n}).catch(t=>{s(n,{event:"tt_heartbeat_fatal",error:t instanceof Error?t.message:String(t)})});let m=5*6e4,o=0,u=a(()=>{if(!e.readInstalledVersion||!e.version)return!1;let t=Date.now();if(t-o<m)return!1;o=t;let f=e.readInstalledVersion();return!!(f&&f!==e.version)},"versionDrifted"),d=new AbortController,l=d.signal;e.signal.aborted?d.abort():e.signal.addEventListener("abort",()=>d.abort(),{once:!0});let v=a(async(t,f)=>{let g=Q;for(;!l.aborted;){if(u()){s(n,{event:"agent_version_drift",bootVersion:e.version,installedVersion:e.readInstalledVersion?.()??null}),d.abort(),e.onVersionDrift?.();break}let h=null;try{h=await ie([...f],r)}catch(p){let j=p instanceof E?p.statusCode:void 0;if(s(n,{event:"poll_error",lane:t,status:j,error:p instanceof Error?p.message:String(p)}),!await Y(g,l))break;g=Math.min(g*2,X);continue}if(!h){if(s(n,{event:"poll_204",lane:t}),!await Y(g,l))break;g=Math.min(g*2,X);continue}g=Q,await ce(h,c,n)}},"runLane"),k=i.filter(t=>z.has(t)),w=i.filter(t=>!z.has(t));k.length>0&&w.length>0?(s(n,{event:"agent_lanes",heavy:k.length,fast:w.length}),await Promise.all([v("heavy",k),v("fast",w)])):await v("single",i),s(n,{event:"agent_stop"})}a(Ce,"runAgentLoop");export{Z as a,q as b,ne as c,ie as d,Ce as e};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{a as C,b as L,c as D}from"../../chunk-GWDZNGUP.js";import{c as d}from"../../chunk-LUCVMLHV.js";import{e as I}from"../../chunk-
|
|
1
|
+
import{a as C,b as L,c as D}from"../../chunk-GWDZNGUP.js";import{c as d}from"../../chunk-LUCVMLHV.js";import{e as I}from"../../chunk-VXKBPESK.js";import"../../chunk-BFDXMIXO.js";import"../../chunk-IEQDLURA.js";import"../../chunk-X5WOTWT4.js";import"../../chunk-NEP5EWHJ.js";import"../../chunk-3TSZ77FB.js";import"../../chunk-I2CXODLD.js";import"../../chunk-RFISMWRW.js";import"../../chunk-ZYGBABMZ.js";import"../../chunk-JPW4LP2O.js";import"../../chunk-PZS55PW2.js";import"../../chunk-3CX6YUEX.js";import"../../chunk-3ZHVP3KE.js";import"../../chunk-C7HW36P5.js";import"../../chunk-HOQPVOMF.js";import"../../chunk-GJKHHZSQ.js";import"../../chunk-4QW5DQNL.js";import"../../chunk-3737WF6X.js";import"../../chunk-NIEP5G3T.js";import"../../chunk-5RBLIVBF.js";import"../../chunk-GAFMAVFO.js";import"../../chunk-ZL5LUOBZ.js";import"../../chunk-FPOPUEA6.js";import"../../chunk-HPN22ZIN.js";import"../../chunk-CQARFIJB.js";import"../../chunk-3UKZJAFS.js";import"../../chunk-L6NQNVK2.js";import"../../chunk-E7BOAZ3X.js";import"../../chunk-UK5JOTMW.js";import"../../chunk-OZRUGBN5.js";import"../../chunk-XFAFMYIP.js";import"../../chunk-GIRPEMTW.js";import"../../chunk-IS4JRZK2.js";import"../../chunk-7HJJCRYK.js";import"../../chunk-355GZ7LR.js";import"../../chunk-QEKWPQDQ.js";import"../../chunk-E7XOYGL5.js";import"../../chunk-NNOSORNV.js";import"../../chunk-LJRE3LZ2.js";import"../../chunk-NQSB4YVT.js";import"../../chunk-RHVU6IFW.js";import"../../chunk-CNOD6HWU.js";import"../../chunk-OASW7DOD.js";import"../../chunk-6UEFCMR2.js";import"../../chunk-MODXEGCU.js";import"../../chunk-RBSEE2Z6.js";import"../../chunk-AFYZYXQ3.js";import"../../chunk-7EKHB3U7.js";import"../../chunk-M7QSC64D.js";import"../../chunk-SCBOQFZ4.js";import"../../chunk-LB24UKHZ.js";import"../../chunk-G7V4ZZZ3.js";import"../../chunk-BTKKWYIU.js";import"../../chunk-ADZ7HHCD.js";import"../../chunk-NTKO4H2K.js";import"../../chunk-3QXRLIGC.js";import"../../chunk-HFGO5762.js";import"../../chunk-7FY23IMS.js";import"../../chunk-GN3ZHQ46.js";import"../../chunk-U2NT5OSQ.js";import"../../chunk-KGURGIZ2.js";import"../../chunk-UPFH72PF.js";import"../../chunk-XLVOAGSG.js";import"../../chunk-CDY7TQFZ.js";import"../../chunk-XRTZU7IZ.js";import"../../chunk-B3BHB26P.js";import"../../chunk-N7ODX6PO.js";import"../../chunk-PJ3WHQ67.js";import"../../chunk-VBXL7XO7.js";import"../../chunk-TZA4HAVF.js";import{b as k,f as h,h as A}from"../../chunk-QXPYGN7I.js";import{a as O}from"../../chunk-JKXU7FAY.js";import"../../chunk-IZTIYR5Q.js";import"../../chunk-RDXWQDNZ.js";import"../../chunk-Y3T5Q5CD.js";import"../../chunk-OJSWNU56.js";import"../../chunk-3AV3GTMP.js";import{f as b}from"../../chunk-GP46IPK2.js";import"../../chunk-DS4P5C4F.js";import{e as P,l as f}from"../../chunk-PZNWH4VQ.js";import{a as e}from"../../chunk-ZLLER3HP.js";import{trace as se,context as ie}from"@opentelemetry/api";import{NodeSDK as j}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as q}from"@opentelemetry/exporter-trace-otlp-http";import{BatchSpanProcessor as F,ConsoleSpanExporter as U,SimpleSpanProcessor as X}from"@opentelemetry/sdk-trace-node";import{Resource as B}from"@opentelemetry/resources";import{ATTR_SERVICE_NAME as H,ATTR_SERVICE_VERSION as K}from"@opentelemetry/semantic-conventions";function $(t){if(!t)return{};let r={};for(let n of t.split(",")){let s=n.indexOf("=");if(s===-1)continue;let i=n.slice(0,s).trim(),a=n.slice(s+1).trim();i&&(r[i]=a)}return r}e($,"parseOtlpHeaders");var p=null;function y(){return process.env.TELEMETRY_ENABLED!=="false"}e(y,"isTelemetryEnabled");function S(t){if(!y()||p!==null)return"off";let r=new B({[H]:t.serviceName,[K]:t.serviceVersion??"0.1.0"}),n=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,s,i;if(n){let a=$(process.env.OTEL_EXPORTER_OTLP_HEADERS),l=new q({url:`${n}/v1/traces`,headers:a});i=new F(l),s="otlp"}else if(process.env.OTEL_SPAN_EXPORT==="none")i=void 0,s="silent";else{let a=new U;i=new X(a),s="console"}return p=new j({resource:r,spanProcessors:i?[i]:[]}),p.start(),s}e(S,"initTelemetry");async function m(){p&&(await p.shutdown(),p=null)}e(m,"shutdownTelemetry");import{SpanKind as he,SpanStatusCode as ye}from"@opentelemetry/api";import{trace as ve,context as we}from"@opentelemetry/api";import*as u from"@sentry/node";var E=!1;function T(t){if(E)return!1;let r=process.env.SENTRY_DSN;return r?(u.init({dsn:r,serverName:t.serviceName,environment:process.env.NODE_ENV??"development",tracesSampleRate:0}),E=!0,!0):!1}e(T,"initSentry");async function g(t){E&&await u.flush(t)}e(g,"flushSentry");import{existsSync as J,mkdirSync as W,readFileSync as R,unlinkSync as V,writeFileSync as M}from"node:fs";import{dirname as z,join as v}from"node:path";import{execFileSync as Q}from"node:child_process";var c=v(f(),"evals-agent.lock");function Z(t){try{return process.kill(t,0),!0}catch(r){return r.code==="EPERM"}}e(Z,"pidAlive");function ee(t){if(!Z(t))return!1;try{let r=Q("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(ee,"isLiveAgent");function te(){try{W(z(c),{recursive:!0})}catch{}for(let t=0;t<2;t++)try{return M(c,String(process.pid),{flag:"wx"}),{ok:!0}}catch(r){if(r.code!=="EEXIST")throw r;let n=0;try{n=Number(R(c,"utf-8").trim())}catch{}if(n&&n!==process.pid&&ee(n))return{ok:!1,holder:n};try{V(c)}catch{}}try{M(c,String(process.pid))}catch{}return{ok:!0}}e(te,"acquireAgentLock");function x(){try{J(c)&&Number(R(c,"utf-8").trim())===process.pid&&V(c)}catch{}}e(x,"releaseAgentLock");var w=class t extends O{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=te();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",T({serviceName:"rulemetric-agent"})&&this.log("[sentry] error capture enabled");let s=S({serviceName:"rulemetric-agent"});s==="otlp"?this.log(`[otel] traces exporting to ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT}`):s==="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,l=await k({configDir:f()});if(this.log(`[transcript-sync] Codex capture: ${h(l)}`),l.error)this.log(`[transcript-sync] WARNING: ${l.error}`);else if(l.mode==="allowlist")for(let o of l.roots)this.log(`[transcript-sync] \u2022 ${o}`);let G=new C({providers:[L(void 0,void 0,A({configDir:f(),onChange:e(o=>this.log(`[transcript-sync] Codex capture changed: ${h(o)}`),"onChange")}))],statePath:v(f(),"transcript-sync-state.json"),importTranscript:e(o=>b("/api/sessions/import",o),"importTranscript"),log:e(o=>this.log(`[transcript-sync] ${o}`),"log")});D(G,{signal:a.signal,log:e(o=>this.log(`[transcript-sync] ${o}`),"log")});let N=e(async o=>{this.log(`
|
|
3
3
|
[${o}] shutting down agent...`),a.abort(),await Promise.allSettled([g(2e3),m(),d()]),x(),process.exit(0)},"shutdown");process.on("SIGINT",()=>{N("SIGINT")}),process.on("SIGTERM",()=>{N("SIGTERM")});let _=!1;try{await I({signal:a.signal,log:e(o=>this.log(o),"log"),version:this.config.version,readInstalledVersion:e(()=>{try{return JSON.parse(R(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([g(2e3),m(),d()]),x(),process.exit(1))}finally{x(),await d()}}};export{w as default};
|
package/dist/lib/agent-loop.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a,b,c,d,e}from"../chunk-
|
|
1
|
+
import{a,b,c,d,e}from"../chunk-VXKBPESK.js";import"../chunk-BFDXMIXO.js";import"../chunk-IEQDLURA.js";import"../chunk-X5WOTWT4.js";import"../chunk-NEP5EWHJ.js";import"../chunk-3TSZ77FB.js";import"../chunk-I2CXODLD.js";import"../chunk-RFISMWRW.js";import"../chunk-ZYGBABMZ.js";import"../chunk-JPW4LP2O.js";import"../chunk-PZS55PW2.js";import"../chunk-3CX6YUEX.js";import"../chunk-3ZHVP3KE.js";import"../chunk-C7HW36P5.js";import"../chunk-HOQPVOMF.js";import"../chunk-GJKHHZSQ.js";import"../chunk-4QW5DQNL.js";import"../chunk-3737WF6X.js";import"../chunk-NIEP5G3T.js";import"../chunk-5RBLIVBF.js";import"../chunk-GAFMAVFO.js";import"../chunk-ZL5LUOBZ.js";import"../chunk-FPOPUEA6.js";import"../chunk-HPN22ZIN.js";import"../chunk-CQARFIJB.js";import"../chunk-3UKZJAFS.js";import"../chunk-L6NQNVK2.js";import"../chunk-E7BOAZ3X.js";import"../chunk-UK5JOTMW.js";import"../chunk-OZRUGBN5.js";import"../chunk-XFAFMYIP.js";import"../chunk-GIRPEMTW.js";import"../chunk-IS4JRZK2.js";import"../chunk-7HJJCRYK.js";import"../chunk-355GZ7LR.js";import"../chunk-QEKWPQDQ.js";import"../chunk-E7XOYGL5.js";import"../chunk-NNOSORNV.js";import"../chunk-LJRE3LZ2.js";import"../chunk-NQSB4YVT.js";import"../chunk-RHVU6IFW.js";import"../chunk-CNOD6HWU.js";import"../chunk-OASW7DOD.js";import"../chunk-6UEFCMR2.js";import"../chunk-MODXEGCU.js";import"../chunk-RBSEE2Z6.js";import"../chunk-AFYZYXQ3.js";import"../chunk-7EKHB3U7.js";import"../chunk-M7QSC64D.js";import"../chunk-SCBOQFZ4.js";import"../chunk-LB24UKHZ.js";import"../chunk-G7V4ZZZ3.js";import"../chunk-BTKKWYIU.js";import"../chunk-ADZ7HHCD.js";import"../chunk-NTKO4H2K.js";import"../chunk-3QXRLIGC.js";import"../chunk-HFGO5762.js";import"../chunk-7FY23IMS.js";import"../chunk-GN3ZHQ46.js";import"../chunk-U2NT5OSQ.js";import"../chunk-KGURGIZ2.js";import"../chunk-UPFH72PF.js";import"../chunk-XLVOAGSG.js";import"../chunk-CDY7TQFZ.js";import"../chunk-XRTZU7IZ.js";import"../chunk-B3BHB26P.js";import"../chunk-N7ODX6PO.js";import"../chunk-PJ3WHQ67.js";import"../chunk-VBXL7XO7.js";import"../chunk-TZA4HAVF.js";import"../chunk-GP46IPK2.js";import"../chunk-DS4P5C4F.js";import"../chunk-PZNWH4VQ.js";import"../chunk-ZLLER3HP.js";export{b as CAPABILITIES,a as HANDLERS,c as availableCapabilities,d as pollForWork,e as runAgentLoop};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a,b,c,d,e}from"../../../chunk-
|
|
1
|
+
import{a,b,c,d,e}from"../../../chunk-C7HW36P5.js";import"../../../chunk-HOQPVOMF.js";import"../../../chunk-GIRPEMTW.js";import"../../../chunk-MODXEGCU.js";import"../../../chunk-B3BHB26P.js";import"../../../chunk-N7ODX6PO.js";import"../../../chunk-PJ3WHQ67.js";import"../../../chunk-GP46IPK2.js";import"../../../chunk-DS4P5C4F.js";import"../../../chunk-PZNWH4VQ.js";import"../../../chunk-ZLLER3HP.js";export{d as buildRemovalProposals,b as buildTrimProposals,e as cronSuggestInstructions,a as isScorableProjectPath,c as nominateRemovals};
|
package/dist/lib/manual-tasks.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as l}from"../chunk-KOQRNWIW.js";import"../chunk-LUCVMLHV.js";import{a as u}from"../chunk-PZS55PW2.js";import{e as g}from"../chunk-
|
|
1
|
+
import{a as l}from"../chunk-KOQRNWIW.js";import"../chunk-LUCVMLHV.js";import{a as u}from"../chunk-PZS55PW2.js";import{e as g}from"../chunk-C7HW36P5.js";import"../chunk-HOQPVOMF.js";import"../chunk-GIRPEMTW.js";import"../chunk-MODXEGCU.js";import{a as i}from"../chunk-GY5IJ4RS.js";import"../chunk-B3BHB26P.js";import"../chunk-N7ODX6PO.js";import"../chunk-PJ3WHQ67.js";import"../chunk-GP46IPK2.js";import"../chunk-DS4P5C4F.js";import"../chunk-PZNWH4VQ.js";import{a as o}from"../chunk-ZLLER3HP.js";var c={cron_check_changelog:o(async(r,e)=>{let s=await l({logger:{info:o(t=>e.logger.info(t),"info"),warn:o(t=>e.logger.warn(t),"warn")}});e.logger.info(`[cron_check_changelog] result: created=${s.createdCount} skipped=${s.skippedCount}`)},"cron_check_changelog"),cron_suggest_instructions:o((r,e)=>g(r,e),"cron_suggest_instructions"),cron_refresh_skills:o((r,e)=>u(r,e),"cron_refresh_skills")},p=i.map(r=>{let e=c[r.name];if(!e)throw new Error(`manual-tasks: no handler registered for "${r.name}"`);return{...r,handler:e}});async function m(r){let e=p.find(n=>n.name===r);if(!e)return{name:r,durationMs:0,ok:!1,error:`Unknown task: ${r}`,logs:[]};let s=[],t={logger:{info:o(n=>s.push({level:"info",message:n}),"info"),warn:o(n=>s.push({level:"warn",message:n}),"warn"),error:o(n=>s.push({level:"error",message:n}),"error")},job:{attempts:0}},a=Date.now();try{return await e.handler({},t),{name:r,durationMs:Date.now()-a,ok:!0,logs:s}}catch(n){return{name:r,durationMs:Date.now()-a,ok:!1,error:n instanceof Error?n.message:String(n),logs:s}}}o(m,"runManualTask");export{p as MANUAL_TASKS,m as runManualTask};
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulemetric/cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
"postgres": "^3.4.0",
|
|
81
81
|
"react": "^19.0.0",
|
|
82
82
|
"zod": "^3.24.0",
|
|
83
|
-
"@rulemetric/
|
|
84
|
-
"@rulemetric/skills-registry": "0.12.
|
|
85
|
-
"@rulemetric/
|
|
83
|
+
"@rulemetric/proxy": "0.12.1",
|
|
84
|
+
"@rulemetric/skills-registry": "0.12.1",
|
|
85
|
+
"@rulemetric/hooks": "0.12.1"
|
|
86
86
|
},
|
|
87
87
|
"//deps": "Worker (`evals agent`) runtime deps: the @opentelemetry/* set, @sentry/node, and postgres are STATIC top-level imports loaded at worker startup (via bundled @rulemetric/{telemetry,db}) — they MUST be runtime deps or a clean `npm i -g` crashes with ModuleLoadError. `better-sqlite3` is optionalDependencies (below): it's a native module, lazy `require()`'d inside a try/catch (packages/session providers cursor/opencode) so a missing binary degrades gracefully — making it a hard dep would break `npm i -g` on platforms without prebuilt binaries. `resend` stays a devDep: lazy `await import('resend')` guarded by RESEND_API_KEY, which end-user workers never set (provider falls back to noop). Classification verified via import-graph scan of dist/commands/evals/agent.js + per-importer static/lazy check.",
|
|
88
88
|
"optionalDependencies": {
|
|
@@ -102,12 +102,12 @@
|
|
|
102
102
|
"tsx": "^4.19.0",
|
|
103
103
|
"typescript": "^5.9.0",
|
|
104
104
|
"vitest": "^3.2.0",
|
|
105
|
-
"@rulemetric/api": "0.0.1",
|
|
106
|
-
"@rulemetric/core": "0.0.1",
|
|
107
105
|
"@rulemetric/db": "0.0.1",
|
|
108
106
|
"@rulemetric/effectiveness": "0.0.1",
|
|
109
107
|
"@rulemetric/email": "0.0.1",
|
|
110
108
|
"@rulemetric/session": "0.2.1",
|
|
109
|
+
"@rulemetric/core": "0.0.1",
|
|
110
|
+
"@rulemetric/api": "0.0.1",
|
|
111
111
|
"@rulemetric/telemetry": "0.0.1",
|
|
112
112
|
"@rulemetric/typescript-config": "0.0.0"
|
|
113
113
|
},
|
package/dist/chunk-W54I75IW.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{c as D}from"./chunk-HOQPVOMF.js";import{b as B}from"./chunk-GIRPEMTW.js";import{a as T}from"./chunk-MODXEGCU.js";import{d as U,f as J}from"./chunk-B3BHB26P.js";import{e as w,f as R}from"./chunk-GP46IPK2.js";import{b as G,c as H}from"./chunk-DS4P5C4F.js";import{a as u}from"./chunk-ZLLER3HP.js";import{readFileSync as Y,realpathSync as X}from"node:fs";import y from"node:path";import O from"node:os";function q(s){let o=y.resolve(s);if(o===y.resolve(O.homedir()))return!1;let a=y.parse(o).root;if(o===a)return!1;try{let n=X(O.tmpdir());if(X(o)===n)return!1}catch{}return!0}u(q,"isScorableProjectPath");var Q=5,Z=Number(process.env.RULEMETRIC_MAX_SUGGESTION_PROJECTS??10),tt=48,et=.5,x=400,ot=3,nt=.6,rt=1;function st(s){let o=s.bloated??[],a=new Set([...s.harmful.map(n=>n.id),...s.candidates.map(n=>n.id)]);return o.filter(n=>!a.has(n.id)).slice(0,rt).map(n=>({instructionId:n.id,estimatedTokens:n.estimatedTokens,topProjectId:n.topProjectId??null,score:.55,reason:`Costs ~${n.estimatedTokens} tokens every session and measures neutral across ${n.exposures} exposed session(s) \u2014 enough data to detect an effect, and none found. Consider shortening "${n.name}" rather than removing it.`+(n.containsSafetyLanguage?" CAUTION: it contains guardrail language (destructive-command or credential rules) \u2014 preserve those lines when shortening.":"")}))}u(st,"buildTrimProposals");async function at(s,o,a){let n=[],i=0;for(let d of s)try{await a("/api/instruction-experiments",{instructionId:d.instructionId,projectPath:o,source:"groom"}),i++}catch(g){let m=g instanceof Error?g.message:String(g);n.push({...d,reason:`${d.reason} (not measurable by withholding: ${m})`})}return{nominated:i,unmeasurable:n}}u(at,"nominateRemovals");function it(s){let o=[];for(let n of s.harmful){let i=n.verdict.delta;o.push({instructionId:n.id,score:Math.min(.95,.75+Math.abs(i)),topProjectId:n.topProjectId??null,reason:`Measured harmful: sessions using "${n.name}" scored ${(i*100).toFixed(1)}pp worse across ${n.exposures} exposed session(s). Observational \u2014 review before archiving.`})}let a=new Set(s.harmful.map(n=>n.id));for(let n of s.candidates)a.has(n.id)||o.push({instructionId:n.id,score:nt,topProjectId:n.topProjectId??null,reason:`Unused: "${n.name}" is ${n.reason} (${n.totalExposures} lifetime exposure(s)) but still costs context budget every session.`});return o.slice(0,ot)}u(it,"buildRemovalProposals");async function ct(){let s=y.join(O.homedir(),".config","rulemetric","skills-registry.json");try{let o=Y(s,"utf-8"),a=JSON.parse(o);return Date.now()-new Date(a.generatedAt).getTime()>tt*60*60*1e3}catch{return!0}}u(ct,"checkSkillsRegistryStale");var wt=u(async(s,o)=>{let a=U(),n=a!=="none";n?o.logger.info(`Scoring backend: ${a}`):o.logger.warn("No LLM backend available (claude CLI missing and ANTHROPIC_API_KEY unset); skipping relevance scoring. Removal/trim proposals still run \u2014 they need no LLM.");let i;try{i=(await w("/api/sessions/project-paths?limit="+Z)).projectPaths}catch(t){o.logger.warn(`Failed to fetch project paths: ${t instanceof Error?t.message:String(t)}`);return}if(i.length===0){o.logger.info("No recent project paths; nothing to score");return}let d=new Map;try{let t=await w("/api/projects?limit=200");for(let e of t.projects??[])e.primaryCheckoutPath&&d.set(T(e.primaryCheckoutPath),e.id)}catch(t){o.logger.warn(`Failed to fetch projects for id resolution: ${t instanceof Error?t.message:String(t)}`)}let g=new Map;try{let t=await w(`/api/catalog?limit=200&contentPreview=${x}`);for(let e of t)g.set(e.id,{id:e.id,name:e.name,description:e.description??"",tags:e.tags??[],contentPreview:(e.contentPreview??"").slice(0,x)})}catch(t){o.logger.warn(`Failed to fetch catalog: ${t instanceof Error?t.message:String(t)}`)}try{let t=await w("/api/instructions?limit=100");for(let e of t.instructions??[])g.has(e.id)||g.set(e.id,{id:e.id,name:e.name,description:e.description??"",tags:e.tags??[],contentPreview:(e.content??"").slice(0,x)})}catch(t){o.logger.warn(`Failed to fetch personal instructions: ${t instanceof Error?t.message:String(t)}`)}let m=[],p=[];try{let t=await w("/api/insights/groom-candidates");if(!t.captureHealthy)o.logger.info(`Grooming paused: ${t.reason??"capture unhealthy"}`);else{m=it(t),p=st(t);let e=t.safetyGuarded+t.harmfulSafetyGuarded;o.logger.info(`Removal proposals: ${m.length} (${t.harmful.length} measured-harmful, ${t.candidates.length} never-used, ${e} withheld by the safety allowlist); trim proposals: ${p.length} (${(t.bloated??[]).length} measured-neutral and expensive, ${t.trimSafetyFlagged??0} flagged as containing guardrail language)`)}}catch(t){o.logger.warn(`Failed to fetch groom candidates: ${t instanceof Error?t.message:String(t)}`)}let I=[...g.values()];if(I.length===0&&m.length===0&&p.length===0){o.logger.info("No candidate instructions and nothing to retire; nothing to score");return}o.logger.info(`Scoring ${I.length} candidates across ${i.length} project(s)`);let M=0,l=null,$=new Set;for(let t of i)try{let e=T(t);if(!q(e)){o.logger.info(`Skipping ${e}: not a project directory (home/root)`);continue}let f=B(e),S=n&&f.length>0;f.length===0&&o.logger.info(`${e}: insufficient language signals; removal/trim only`);let v=D(e),V={name:y.basename(e),description:v.description,languages:f,topics:v.topics,dependencies:v.dependencies},k=S?H(I):[];S&&o.logger.info(`Scoring ${I.length} candidates for ${e} in ${k.length} batch(es)`);let E=[],b=0;for(let r of k)try{let c=await J(G(V,r),"",4096);if(!c){b++;continue}let _=c.recommendations??[];for(let P of _)typeof P.instructionId=="string"&&typeof P.score=="number"&&typeof P.reason=="string"&&E.push({instructionId:P.instructionId,score:P.score,reason:P.reason})}catch(c){b++,o.logger.warn(`Batch failed for ${e}: ${c instanceof Error?c.message:String(c)}`)}b>0&&o.logger.warn(`${b}/${k.length} batch(es) failed for ${e} (backend ${a}); suggestions are partial`),S&&E.length===0&&o.logger.warn(`No usable LLM output for ${e} (backend ${a})`);let z=E.filter(r=>r.score>=et).sort((r,c)=>c.score-r.score).slice(0,Q),C=d.get(e),K=l===null||l===e;l===null&&(l=e);let A=u(r=>r.topProjectId?r.topProjectId===C:K,"placeHere"),L=m.filter(A),{nominated:N,unmeasurable:F}=await at(L,e,R);N>0&&o.logger.info(`${e}: ${N} removal candidate(s) nominated for randomised withholding instead of the feed`);let h=[...z.map(r=>({instructionId:r.instructionId,score:r.score,reason:r.reason,kind:"add"})),...F.map(({topProjectId:r,...c})=>({...c,kind:"remove"})),...p.filter(A).map(({estimatedTokens:r,topProjectId:c,..._})=>({..._,kind:"trim"}))];if(h.length===0){o.logger.info(`Nothing to suggest for ${e}`);continue}await R("/api/instruction-suggestions/batch-upsert",{projectPath:e,...C?{projectId:C}:{},suggestions:h}),o.logger.info(`${e}: ${h.filter(r=>r.kind==="add").length} add + ${h.filter(r=>r.kind==="remove").length} remove + ${h.filter(r=>r.kind==="trim").length} trim`);for(let r of h)r.kind!=="add"&&$.add(r.instructionId);let W=new Set(F.map(r=>r.instructionId));for(let r of L)W.has(r.instructionId)||$.add(r.instructionId);M++}catch(e){o.logger.warn(`Failed to score ${t}: ${e instanceof Error?e.message:String(e)}`)}let j=[...m.filter(t=>!$.has(t.instructionId)),...p.filter(t=>!$.has(t.instructionId)).map(({estimatedTokens:t,...e})=>e)];if(j.length>0&&l)try{let t=new Set(p.map(e=>e.instructionId));await R("/api/instruction-suggestions/batch-upsert",{projectPath:l,...d.get(l)?{projectId:d.get(l)}:{},suggestions:j.map(({topProjectId:e,...f})=>({...f,kind:t.has(f.instructionId)?"trim":"remove"}))}),o.logger.info(`Orphan sweep: ${j.length} proposal(s) whose project was not scored this run placed on ${l}`)}catch(t){o.logger.warn(`Orphan sweep failed: ${t instanceof Error?t.message:String(t)}`)}if(await ct())try{await R("/api/instruction-suggestions/mark-stale",{}),o.logger.warn("Skills registry is stale (>48h); marked all suggestions stale")}catch{}o.logger.info(`Done: scored ${M}/${i.length} projects`)},"cronSuggestInstructions");export{q as a,st as b,at as c,it as d,wt as e};
|