@counterfact-labs/cli 0.2.6 → 0.2.7
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/README.md +20 -0
- package/bundle/client-release.json +1 -1
- package/dist/adapters/completion-lock.js +95 -0
- package/dist/adapters/completion.js +132 -17
- package/dist/adapters/entry-files.js +126 -0
- package/dist/adapters/entry-selection.js +45 -0
- package/dist/adapters/files.js +2 -1
- package/dist/adapters/results.js +10 -2
- package/dist/adapters/selection.js +104 -0
- package/dist/adapters/settings.js +29 -2
- package/dist/analysis-core/analysis/schemas.js +1 -1
- package/dist/analysis-core/chunks/2PZF54KH.js +10 -0
- package/dist/analysis-core/chunks/{OPMA32A6.js → 6RWEWBHK.js} +1 -1
- package/dist/analysis-core/chunks/{PECX3OXB.js → 7NEWZ74F.js} +1 -1
- package/dist/analysis-core/chunks/{6QY5BV5B.js → CGCJN73D.js} +1 -1
- package/dist/analysis-core/chunks/CWYVUGG4.js +1 -0
- package/dist/analysis-core/chunks/{3JWEFCTJ.js → FBTOOUPL.js} +1 -1
- package/dist/analysis-core/chunks/GOQVKWP3.js +32 -0
- package/dist/analysis-core/chunks/IHAVDX4L.js +66 -0
- package/dist/analysis-core/chunks/IVULXWQN.js +21 -0
- package/dist/analysis-core/chunks/K5FUABWW.js +1 -0
- package/dist/analysis-core/chunks/KGQYR62R.js +7 -0
- package/dist/analysis-core/chunks/PY5M22CL.js +1 -0
- package/dist/analysis-core/chunks/{YDBO7P4X.js → RNTMH4MU.js} +1 -1
- package/dist/analysis-core/chunks/RUVMFAST.js +1 -0
- package/dist/analysis-core/chunks/S27VIQMZ.js +1 -0
- package/dist/analysis-core/chunks/{5DGPLXYB.js → SLJ6CW7W.js} +1 -1
- package/dist/analysis-core/chunks/{STI4JE7L.js → UEORNVQB.js} +1 -1
- package/dist/analysis-core/chunks/{X7WZAA7S.js → WYLIV2P2.js} +1 -1
- package/dist/analysis-core/contracts/analysis-selection.js +1 -0
- package/dist/analysis-core/contracts/module-resolution.js +1 -0
- package/dist/analysis-core/contracts/relay-analysis.js +1 -1
- package/dist/analysis-core/contracts/requests.js +1 -1
- package/dist/analysis-core/contracts/selection-paths.js +1 -0
- package/dist/analysis-core/conventions/analysis-fit.js +1 -1
- package/dist/analysis-core/conventions/file-admission.js +1 -1
- package/dist/analysis-core/import/calls/modules.js +1 -0
- package/dist/analysis-core/import/outside-loader-sources.js +1 -1
- package/dist/analysis-core/index.js +3 -3
- package/dist/analysis-core/requests/local-plan.js +1 -1
- package/dist/analysis-core/requests/registry.js +1 -1
- package/dist/analysis-core/requests/template-version.js +1 -1
- package/dist/analysis-core/requests/tools.js +1 -1
- package/dist/analysis-core/settings.js +1 -1
- package/dist/analysis-core/stages/engine-entry.js +1 -1
- package/dist/cli/analysis-selection.js +91 -0
- package/dist/cli/commands/analyze.js +31 -6
- package/dist/cli/completion-delivery.js +63 -0
- package/dist/cli/completion-recovery.js +68 -14
- package/dist/cli/context.js +2 -1
- package/dist/cli/main.js +21 -9
- package/dist/cli/mcp.js +70 -11
- package/dist/cli/prior-completion.js +35 -0
- package/dist/cli/relay-check.js +163 -97
- package/dist/cli/relay-failure.js +32 -0
- package/dist/cli/relay-preparation.js +24 -11
- package/dist/cli/results-upload.js +131 -0
- package/dist/cli/scope-choices.js +57 -0
- package/dist/contract/cli-refusals.js +8 -0
- package/dist/contract/cli-version.js +1 -1
- package/dist/contract/console.js +7 -2
- package/dist/contract/scope-choice.js +78 -0
- package/dist/contract/selection-metadata.js +9 -0
- package/dist/contract/selection-offer.js +43 -0
- package/dist/gatekeeper/console.js +36 -25
- package/package.json +2 -2
- package/dist/analysis-core/chunks/377MLK4M.js +0 -21
- package/dist/analysis-core/chunks/DLPVYWHZ.js +0 -1
- package/dist/analysis-core/chunks/FOKDE64Y.js +0 -1
- package/dist/analysis-core/chunks/KTNA2KTN.js +0 -7
- package/dist/analysis-core/chunks/NIOS7U6C.js +0 -41
- package/dist/analysis-core/chunks/QFY6A3MS.js +0 -66
- package/dist/analysis-core/chunks/SVMEWGD3.js +0 -1
- package/dist/analysis-core/chunks/ZTOVBAG7.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as bt,c as Q,d as Ct,e as _t}from"./chunks/CWYVUGG4.js";import{$ as Fe,I as vt,J as xt,K as Et,L as wt,M as At,N as Rt,O as we,P as Ae,Q as B,R as D,S as Re,T as Ce,U as q,W as ke,X as Oe,Y as V,Z as _e,_ as Ie,aa as Z,ba as kt,ca as Te,da as Le,ea as Me,fa as Ne,ga as je,ha as Pe,ja as Ot,qa as It,sa as Ft,ua as Tt,wa as Lt,ya as Mt}from"./chunks/IHAVDX4L.js";import"./chunks/N7U5N42V.js";import{a as W}from"./chunks/6RWEWBHK.js";import{a as ht,e as xe,l as yt,m as St}from"./chunks/CGCJN73D.js";import{a as Y}from"./chunks/QDYMR6KS.js";import"./chunks/Y7JGSUOA.js";import"./chunks/3MTXB4MK.js";import"./chunks/UEORNVQB.js";import{b as gt}from"./chunks/E7TFIHC5.js";import"./chunks/M6HYSTQD.js";import"./chunks/VGYWI4X2.js";import"./chunks/57M4OQJM.js";import"./chunks/J4AXGE5W.js";import{a as R,d as Ee}from"./chunks/4H23CSUM.js";import"./chunks/K2GNDX3W.js";import"./chunks/HTLIRVP7.js";import"./chunks/DZZBQDGO.js";import"./chunks/FBTOOUPL.js";import{D as ve,R as ut,g as be,r as dt,s as ft,t as mt,u as pt,v as X}from"./chunks/IVULXWQN.js";import{a as P,b as G,f as J}from"./chunks/K5FUABWW.js";import{a as _}from"./chunks/326F4XNG.js";import"./chunks/4F6ZIHXU.js";import"./chunks/SLJ6CW7W.js";import"./chunks/6U2IR4XB.js";import{c as A}from"./chunks/MJGB25S5.js";import"./chunks/WYLIV2P2.js";import{a as it,b as at,c as ct,d as lt}from"./chunks/7NEWZ74F.js";import{r as Se}from"./chunks/KGQYR62R.js";import"./chunks/IBCFGUHI.js";import{b as M}from"./chunks/2PSNOSJ2.js";import"./chunks/KU5DINLW.js";import{Bb as ge,D as le,F as de,Qb as he,Vb as ye,Za as pe,n as ie,qa as k,ta as fe,ua as O,va as T,xb as ue,z as ce}from"./chunks/GOQVKWP3.js";import"./chunks/74FPPPIG.js";import"./chunks/5TATKWLG.js";import{a as ae,g as Ze,h as N}from"./chunks/2PZF54KH.js";import"./chunks/6B2HILSY.js";import{f as I,i as oe,n as se}from"./chunks/JKWTHRUR.js";import"./chunks/SKVEBOGA.js";import{a as Je,b as $}from"./chunks/3GUKUEEJ.js";import{b as re}from"./chunks/724WZMYW.js";import"./chunks/A7WJJMRY.js";import"./chunks/PYKAERZZ.js";import"./chunks/KWECQJ6X.js";import"./chunks/FSLWD2PE.js";import{a as et,b as tt,c as j,d as rt,e as ot,f as st,g as nt}from"./chunks/PY5M22CL.js";import"./chunks/YUY436SM.js";import{a as ne,c as F}from"./chunks/C6X5GDG4.js";import{a as Xe,b as Ye,c as We,d as Qe,e as Ve}from"./chunks/RUVMFAST.js";import{a as me}from"./chunks/S27VIQMZ.js";import{createHash as Nt}from"node:crypto";var Be=new WeakMap,ee={version:"shared-modules-v1",settingsFiles:N.settingsFiles,resolve(s,e){let{paths:a,files:n,settings:i}=e,l=ae(s);if(!l)return[];let f=Be.get(e);return f||(f=new N({files:new Map([...a].map(u=>[u,n.get(u)??""]))},i),Be.set(e,f)),pe(s,n.get(s)??"",l,{allReexports:!0,completeImports:!0}).map(u=>u.dynamic?{from:s,specifier:u.source,status:"refused",provenance:null,reason:"dynamic"}:f.resolve(s,u.source,u.names))}};var jt=s=>s==="too-large"?"over-limit":s==="wrong-type"||s==="empty"?"unsupported":s;function De(s,e){let a=J(s);if(!P(a))return{kind:"refused",reason:"disabled"};let n=j.safeParse(e.request);if(!n.success||n.data.kind!=="file")return{kind:"refused",reason:"invalid-selection"};let i=n.data,l=e.resolver??ee,f=X(a,{profile:"entry-analysis",listing:[...e.entries],selection:i,limits:e.limits}),{entries:u}=f;return{kind:"pending",checkpoint:{version:1,settings:a,request:i,entries:u,files:{},resolutions:{},unavailable:{},targets:{},attempted:{paths:[],bytes:0},resolverVersion:l.version,...l.identity===void 0?{}:{resolverIdentity:l.identity},...e.proposal?{proposal:structuredClone(e.proposal)}:{},limits:f.limits,inventoryIncomplete:(e.inventoryIncomplete??0)+f.inventoryIncomplete}}}async function qe(s,e){let a=j.safeParse(s.request);if(s.version!==1||!a.success||a.data.kind!=="file")return{kind:"refused",reason:"invalid-selection"};let n=structuredClone(s);n.request=a.data;let{settings:i,request:l}=n,f=e.resolver??ee;if(f.version!==n.resolverVersion||f.identity!==n.resolverIdentity)return{kind:"refused",reason:"stale-snapshot"};if(!P(i))return{kind:"refused",reason:"disabled"};let u=new Map(n.entries.map(t=>[t.path,t])),y=new Set(u.keys()),g=new Map(Object.entries(n.files)),m=f.settingsFiles?.(y,g,[l.entry,...Object.keys(n.files)])??[];if(m.every(t=>Object.hasOwn(n.files,t)||Object.hasOwn(n.unavailable,t))){let t=Object.keys(n.files).filter(o=>!Object.hasOwn(n.resolutions,o)),c={paths:y,files:g,settings:i},r=await _(t,4,async o=>{try{return{path:o,edges:await f.resolve(o,c)}}catch{return{path:o,reason:"unreadable"}}});for(let{path:o,edges:h,reason:b}of r)Object.defineProperty(b?n.unavailable:n.resolutions,o,{value:b??h,enumerable:!0,configurable:!0,writable:!0})}let p=ve(i,{...n,settingsFiles:m,targetIdentity:Nt("sha256").update(JSON.stringify(Object.entries(n.targets).sort(([t],[c])=>t.localeCompare(c)))).digest("hex")});if(p.kind==="refused")return{kind:"refused",reason:p.reason};if(p.kind==="ready")return{kind:"ready",selection:p.selection,files:Object.fromEntries(p.selection.files.map(t=>[t.path,n.files[t.path]]))};for(let[t,c]of Object.entries(p.unavailable??{}))Object.defineProperty(n.unavailable,t,{value:c,enumerable:!0,configurable:!0,writable:!0});let v={...i,CF_RESPECT_GITIGNORE:"1",CF_LOCAL_SYMLINK_GUARD:"1",CF_SECRET_SCAN:"1"},S=(t,c,r)=>{if(!me.safeParse(t).success||c&&c.root!==l.launchRoot)return"out-of-scope";let o=k(v,{path:t,...r===void 0?{}:{text:r}},{purpose:"entry",route:"local-folder",...e.admission,gitIgnored:e.gitIgnored,...c?{localTarget:c}:{}});return o.admitted?null:o.reason==="out-of-scope"&&c?"symlink-escape":jt(o.reason)},d=await _(p.pending.filter(t=>!Object.hasOwn(n.files,t)).slice(0,4),4,async t=>{let c=0,r=!1;try{let o=S(t);if(o)return{path:t,reason:o,bytes:c,attempted:r};let h=await e.localTarget(t);if(!h)return{path:t,reason:"unreadable",bytes:c,attempted:r};if(o=S(t,h),o)return{path:t,reason:o,bytes:c,attempted:r};let b=u.get(t);r=!0,c=b.size;let E=await e.read({path:t,size:b.size,ref:b.ref,readBytes:b.size+1});if(E!==null&&(c=Buffer.byteLength(E)),E===null)return{path:t,reason:"unreadable",bytes:c,attempted:r};let w=await e.localTarget(t);return!w||w.path!==h.path||w.root!==h.root?{path:t,reason:"symlink-escape",bytes:c,attempted:r}:(o=S(t,w,E),o?{path:t,reason:o,bytes:c,attempted:r}:c!==b.size?{path:t,reason:"over-limit",bytes:c,attempted:r}:{path:t,text:E,target:w.path,bytes:c,attempted:r})}catch{return{path:t,reason:"unreadable",bytes:c,attempted:r}}});for(let t of d){if(t.attempted){let r=p.pendingSettings.includes(t.path)?n.settingsAttempted??={paths:[],bytes:0}:n.attempted;r.paths.push(t.path),r.bytes+=t.bytes}let c=(r,o)=>Object.defineProperty(r,t.path,{value:o,enumerable:!0,configurable:!0,writable:!0});t.reason?c(n.unavailable,t.reason):t.text!==void 0&&(c(n.files,t.text),c(n.targets,t.target))}return{kind:"pending",checkpoint:n}}async function Pt(s,e){let a=De(s,e);for(;a.kind==="pending";)a=await qe(a.checkpoint,e);return a}var Bt=new Set;function Dt(s,e={}){let a=ne(e.dir),n=e.limits??ce.archive,i=e.listing??Bt,l={commit:null,files:new Map,skipped:[]},f=new Set,u=0,y=0;function g(d){let t=d.replace(/\/$/,"").split("/");return!d.startsWith("/")&&!d.includes("\\")&&!/^[a-z]:/i.test(d)&&!t.some(c=>c===".."||c==="."||!c)}function m(d,t,c,r=i){if(!c||!g(d)||!Number.isSafeInteger(t)||t<0)return"refused";let o=k(s,{path:d,size:t},{purpose:"archive",route:"github",root:a});return o.admitted?e.exampleFolders?.some(h=>d.startsWith(h))||de(d,{root:a,listing:r})?"example":null:o.reason==="excluded"&&le(s,d,a)?"example":o.reason==="excluded"||o.reason==="wrong-type"?"excluded":"refused"}function p(d,t){f.has(d)||(f.add(d),l.skipped.push({path:d,reason:t}))}function v(d,t=i){let c=d.split("/");for(let r=1;r<=c.length;r++){let o=c.slice(0,r).join("/");if(o===a||a.startsWith(`${o}/`))continue;if(F(o,a)===null)return!1;let h=m(`${o}/`,0,!0,t);if(h)return p(`${o}/`,h),!1}return!0}function S(d,t,c=!0){if(F(d,a)===null)return!1;if(!g(d))return p(d,"refused"),!1;let r=d.split("/");if(r.length>1&&!v(r.slice(0,-1).join("/")))return!1;let o=m(d,t,c);return o?(p(d,o),!1):y>=n.files||t>n.bytes-u?(p(d,"over-limit"),!1):(u+=t,y++,!0)}return{result:l,accept:S,enterFolder:v}}function He(s){return s.CF_MODEL_READER!=="0"}async function qt(s,e,a,n){a=O(s,a);let i=structuredClone(e);for(i.files??={},i.cursor=0;;){let l=await q(s,i,a,n);if(l){i=l;continue}let f=i.selected??[];if((i.cursor??0)>=f.length)return i;let u=f.slice(i.cursor).filter(m=>!Object.hasOwn(i.files,m.path)),y=[],g=await _(u,4,async m=>{try{return{path:m.path,text:await B(m,p=>a.read(p),y,i.refused)}}catch(p){return{error:p}}});for(let m of g){if("error"in m)throw m.error;m.text!==null&&(i.files[m.path]=m.text)}y.length&&(i.refused=M(i.refused,y)),i.cursor=f.length}}async function ze(s,e,a,n){let{codeFindingNote:i}=xe(n),l={deriveBytes:0,codeEvidence:[]};if(!e.findingQuality?.config.switches.codeInputs||!e.projectAgents?.enabled)return l;let f=e.projectAgents,u=(e.repos??[]).filter(r=>[...f.byRepo[r.key]??[],...f.codeByRepo?.[r.key]??[]].some(o=>o.codeInputsJson&&(o.codeInputsJson.tools.length||o.codeInputsJson.contextInputs.length))),g=(await _(u,1,async r=>{try{let o=a.find(h=>h.repoKey===r.key);if(!o)throw new Error("Source reader is missing.");return{repo:await qt(s,r,o,e.modelReader??!1)}}catch(o){return{error:o}}})).map(r=>{if("error"in r)throw r.error;return r.repo}),m=g.map(r=>{let o=ke(s,r,D(s,e),e.modelReader,f);return Object.assign(r.files,o.virtualFiles),o.fragment}),p=Object.fromEntries(g.map(r=>[r.key,r.files??{}])),S=Oe({...e,repos:g,mapped:m}).findingQuality?.codeEvidence?.filter(r=>Object.keys(r.input.files).length)??[];if(!S.length)return l;let d=S.map(r=>({repo:r.repo,unitKey:r.unitKey,enabled:!0,inputs:[r.input],files:p[r.repo]}));return{deriveBytes:[...new Map(S.flatMap(r=>Object.entries(r.input.files).map(([o,h])=>[JSON.stringify([r.repo,o]),{path:o,text:h}]))).values()].reduce((r,{path:o,text:h})=>r+Buffer.byteLength(`### ${o}
|
|
2
2
|
\`\`\`
|
|
3
|
-
${
|
|
3
|
+
${ye(h)}
|
|
4
4
|
\`\`\`
|
|
5
5
|
|
|
6
|
-
`),0)+Buffer.byteLength(
|
|
6
|
+
`),0)+Buffer.byteLength(i(S.flatMap(r=>r.input.sources))),codeEvidence:d}}function $e(s,e,a,n,i){let l=e.analysisFlags,f=[],u=new Set,y=0,g=0;for(let o of e.repos??[]){g+=(o.selected??[]).reduce((b,E)=>b+(E.readBytes??E.size),0),f.push(...(o.selected??[]).map(b=>({path:F(b.path,o.root)??b.path,size:b.size})));let h=ge(e.projectAgents,o.key,{nodes:[],edges:[],warnings:[]},i);for(let[b,E]of Object.entries(h.files)){let w=Se(E).length;y+=w,f.push({path:b,size:w}),u.add(b)}}y+=g;let m=Ne(f,l.multiPass,u),p=m>1?24:he,v=(u.size?y:Math.min(y,15e4))+n.deriveBytes,S=Z("derive",s,a),d=Array.from({length:m},(o,h)=>A(s,{template:S},m>1?`Derive findings (part ${h+1} of ${m})`:"Derive findings",R.generate,I(v+je(y,m))+4e3,Ee)),t=l.multiPass&&u.size?g:Math.min(g,15e4);d.push(A(s,{template:"derive-structure"},"Structural pass",R.generate,I(t)+4e3,12e3));let c=Math.ceil(p/_e)*(1+Ie);d.push(A(s,{template:"scope-findings"},"Scope check",a.switches.enabled?a.models.scope:R.mechanical,c*(4e3+I(n.scopeBytes)),c*1e3));let r=Fe(s,p,l.findingCheck??!0,Z("check",s,a),a.switches.fullContext?"whole-file":"legacy");return r&&d.push(r),(l.sourceNotes??!0)&&d.push(A(s,{template:"explain-sources"},"Explain sources",Te,I(Me)*p,Le*p)),e.codeAgents?.model&&e.repos?.some(o=>o.scanNeeded)&&d.push(A(s,{template:"judge-code-prompt"},"Check possible agents in code",R.mechanical,6*3e3,1200)),d.push(...Pe(G(s),s)),d}var Ut=async(s,e)=>{if(e.progress.assertHeld(),e.progress.signal?.throwIfAborted(),!e.model)throw new $("llm","Analysis needs a live model; no provider key is configured.");if(!e.readers.length)throw new $("not_found","This project has no analyzable repository.");let a=s.execution.preparation;if(!a)throw new Error("Preparation options are required for estimation.");let{state:n,settings:i}=s;await T(i,n,e.readers),await e.context.refreshStructureParts?.().catch(()=>{});let l=Y(await e.instructions()),f=W(l),u=l.bundleText("model-reader-runtime-prompt"),y=[...n.warnings??[]],g=D(i,n),m=n.modelReader??He(i),p=n.analysisFlags?Ae(i,n):we(i),v=n.findingQuality??{config:a.qualityConfig},S=await ue(i,n.projectAgents,e.context.loadProjectAgents,void 0,v.config.switches.codeInputs),d=[],t=[],c=e.readers.map(x=>O(i,x));for(let x of c){e.progress.assertHeld(),e.progress.signal?.throwIfAborted();let L=await x.head(),te=await x.list(),C=be(i,te,x.root);!C.readingNotes&&C.skippedNote&&y.push(`${x.repoKey}: ${C.skippedNote}`),t.push({key:x.repoKey,kind:"github",root:x.root,selected:C.selected}),d.push({key:x.repoKey,...x.source??{kind:x.repoKey.startsWith("local:")?"fs":"github"},headSha:L.sha,branch:L.branch,selected:C.selected,...C.readingNotes?{sourceReadNotes:C.readingNotes}:{},cursor:0,files:{},...x.root?{root:x.root}:{},...Re(i,te,C.selected,x.root,g,m)})}let r={...n,repos:d,projectAgents:S,codeAgents:g,modelReader:m,analysisFlags:p,findingQuality:v};await T(i,r,c);let o=await ze(i,r,c,l),{sources:h,files:b}=V({qualityConfig:v.config,codeEvidence:o.codeEvidence}),E=f.enrichRequestInputs("scope-findings",{codeSources:h,codeFiles:b},i),w=Buffer.byteLength(String(E.code))+Math.max(0,Buffer.byteLength(String(E.system))-Buffer.byteLength(f.RULE)),H=[...a.uploadReadingAllowance?[a.uploadReadingAllowance]:[],...$e(i,{...r,repos:t},v.config,{deriveBytes:o.deriveBytes,scopeBytes:w},u)],Ge=await e.context.loadOpenStructures?.()??[],z=(await e.context.loadPendingRechecks?.().catch(()=>[])??[]).reduce((x,L)=>x+L.children.length,0);z&&H.push(A(i,{template:"structure-recheck"},"Post-merge re-check",R.mechanical,z*3e3,z*300));let K=await e.context.chatFindingCount?.().catch(()=>(e.progress.log({level:"warn",code:"chat.count_failed"}),0))??0;K&&H.push(A(i,{},"Re-check chat findings",R.mechanical,K*3e3,K*300));let U=oe(H,a.capUsd);return se(U,e.progress.log),{next:a.confirmPrice?"awaiting_confirm":"fetching_files",clear:[],estimate:U,set:{repos:d,warnings:y,openStructures:Ge,codeAgents:g,modelReader:m,analysisFlags:p,projectAgents:S,findingQuality:v,...p.splitCheck?{splitEstimateBase:U}:{}}}};var $t=async({state:s,settings:e},a)=>{a.progress.assertHeld(),a.progress.signal?.throwIfAborted();let n=[...s.repos??[]];await T(e,s,a.readers);let i=s.repoCursor??0;if(i>=n.length)return{next:"mapping",set:{repoCursor:0},clear:[]};let l=structuredClone(n[i]),f=a.readers.find(t=>t.repoKey===l.key);if(!f)throw new Error(`no reader for ${l.key}`);let u=O(e,f),y=await q(e,l,u,s.modelReader??!1);if(y)return n[i]=y,{next:"fetching_files",set:{repos:n},clear:[]};let g=l.selected??[],m=l.cursor??0,p=g.slice(m,m+20),v={...l.files??{}},S=[];for(let t of p){if(a.progress.assertHeld(),a.progress.signal?.throwIfAborted(),v[t.path]!==void 0)continue;let c=await B(t,r=>u.read(r),S,l.refused);c!==null&&(v[t.path]=c)}S.length&&(l.refused=M(l.refused,S)),l.files=v,l.cursor=m+p.length,n[i]=l;let d=l.cursor>=g.length&&!Ce(e,l);return{next:"fetching_files",set:{repos:n,repoCursor:d?i+1:i},clear:[]}};async function Gt(s,e){let a=e.admission?.exclusions?.length?e.entries.filter(l=>k(s,l,{purpose:"override",route:"github",...e.admission}).admitted):e.entries,n=ie(s)?new Set(a.map(l=>l.path)):void 0,i=!e.admission?.exclusions?.length&&!re(s)?e.read:l=>fe(s,l,e.read,{...e.admission,...n?{listing:n}:{}});return Q(s,{...e,entries:a,read:i})}function Jt(s,e){let a=e?.findingHeadlineDiagnostics??(s.findingHeadlines?.version===2?s.findingHeadlines.diagnostics:s.findingHeadlineDiagnostics);return{set:{...a?{findingHeadlineDiagnostics:a}:{},repos:(s.repos??[]).map(n=>({...n,files:{},selected:[],scan:void 0,ranked:void 0})),...s.projectAgents?{projectAgents:{enabled:s.projectAgents.enabled,byRepo:{}}}:{}},clear:["passResults","sourceNotes","findingHeadlines","findingsRaw","structuresRaw","loadModes","rechecks","recheckedChangeIds","readPaths","inspectPlan","passFindings","codeChecks","newVerdicts",...s.shapeFindings?["shapeFindings"]:[]]}}export{vt as ANALYSIS_FIELDS,et as ANALYSIS_SELECTION_LIMITS,pt as ENTRY_LIMITS,Je as FOLDER_TOO_LARGE_MESSAGE,yt as InputBudgetError,R as MODELS,N as ModuleResolver,k as admitFile,qe as advanceEntrySelection,Rt as analysisFieldsOf,Ot as analysisRuntime,tt as analysisScopeSchema,j as analysisSelectionRequestSchema,nt as analysisSelectionResultSchema,it as analysisSizeLimits,Ct as applyAnalysisDelta,ct as assessAnalysisSize,Tt as buildAnalysisResult,ht as buildRequest,De as createEntrySelectionCheckpoint,Y as createInstructionText,St as createRequestRegistry,W as createRequestTools,Q as discoverLocalSources,dt as discoverReaders,Ut as estimateStage,Gt as fetchLocalSources,$t as fetchStage,At as fetchedPathsOf,P as fileScopeEnabled,G as findingHeadlinesEnabled,Jt as finishAnalysis,Lt as headlinesStage,bt as importProposalEnabled,Xe as importProvenanceSchema,Ye as importRefusalReasonSchema,It as inspectStage,_t as mapStage,lt as measureAnalysisSize,Ve as moduleResolutionSchema,at as parseAnalysisSize,ft as planForJob,X as planImport,st as provenScopeChoiceSchema,Pt as readEntrySelection,kt as readFindingQualityConfig,Qe as refusedImportSchema,gt as render,Dt as repoCollector,ut as resolveAgents,Ze as resolveImport,We as resolvedImportSchema,xt as savedFragmentAt,wt as savedFragmentsOf,V as scopeCodeContext,ot as selectionCompletenessSchema,rt as selectionFileSchema,mt as selectionOfPlan,J as snapshotSettings,Ft as sourceNotesStage,Mt as structureStage,Et as trySavedFragmentAt};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a,b}from"../chunks/
|
|
1
|
+
import{a,b}from"../chunks/RNTMH4MU.js";import"../chunks/IHAVDX4L.js";import"../chunks/N7U5N42V.js";import"../chunks/6RWEWBHK.js";import"../chunks/CGCJN73D.js";import"../chunks/QDYMR6KS.js";import"../chunks/Y7JGSUOA.js";import"../chunks/3MTXB4MK.js";import"../chunks/UEORNVQB.js";import"../chunks/E7TFIHC5.js";import"../chunks/M6HYSTQD.js";import"../chunks/VGYWI4X2.js";import"../chunks/57M4OQJM.js";import"../chunks/J4AXGE5W.js";import"../chunks/4H23CSUM.js";import"../chunks/K2GNDX3W.js";import"../chunks/HTLIRVP7.js";import"../chunks/DZZBQDGO.js";import"../chunks/IVULXWQN.js";import"../chunks/K5FUABWW.js";import"../chunks/326F4XNG.js";import"../chunks/4F6ZIHXU.js";import"../chunks/SLJ6CW7W.js";import"../chunks/6U2IR4XB.js";import"../chunks/MJGB25S5.js";import"../chunks/WYLIV2P2.js";import"../chunks/KGQYR62R.js";import"../chunks/IBCFGUHI.js";import"../chunks/2PSNOSJ2.js";import"../chunks/KU5DINLW.js";import"../chunks/GOQVKWP3.js";import"../chunks/74FPPPIG.js";import"../chunks/5TATKWLG.js";import"../chunks/2PZF54KH.js";import"../chunks/6B2HILSY.js";import"../chunks/JKWTHRUR.js";import"../chunks/SKVEBOGA.js";import"../chunks/3GUKUEEJ.js";import"../chunks/724WZMYW.js";import"../chunks/A7WJJMRY.js";import"../chunks/PYKAERZZ.js";import"../chunks/KWECQJ6X.js";import"../chunks/FSLWD2PE.js";import"../chunks/PY5M22CL.js";import"../chunks/YUY436SM.js";import"../chunks/C6X5GDG4.js";import"../chunks/RUVMFAST.js";import"../chunks/S27VIQMZ.js";export{a as localCallPlan,b as localSourcePlan};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{l as a,m as b,n as c,o as d}from"../chunks/
|
|
1
|
+
import{l as a,m as b,n as c,o as d}from"../chunks/CGCJN73D.js";import"../chunks/QDYMR6KS.js";import"../chunks/Y7JGSUOA.js";import"../chunks/3MTXB4MK.js";import"../chunks/E7TFIHC5.js";import"../chunks/K2GNDX3W.js";import"../chunks/HTLIRVP7.js";import"../chunks/K5FUABWW.js";import"../chunks/SLJ6CW7W.js";import"../chunks/6U2IR4XB.js";import"../chunks/MJGB25S5.js";import"../chunks/WYLIV2P2.js";import"../chunks/74FPPPIG.js";import"../chunks/6B2HILSY.js";import"../chunks/JKWTHRUR.js";import"../chunks/SKVEBOGA.js";import"../chunks/3GUKUEEJ.js";import"../chunks/A7WJJMRY.js";import"../chunks/KWECQJ6X.js";import"../chunks/FSLWD2PE.js";export{a as InputBudgetError,d as buildAnalysisCall,c as callInputBytes,b as createRequestRegistry};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a}from"../chunks/
|
|
1
|
+
import{a}from"../chunks/UEORNVQB.js";import"../chunks/E7TFIHC5.js";import"../chunks/K5FUABWW.js";import"../chunks/WYLIV2P2.js";export{a as createTemplateVersion};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a}from"../chunks/
|
|
1
|
+
import{a}from"../chunks/6RWEWBHK.js";import"../chunks/CGCJN73D.js";import"../chunks/QDYMR6KS.js";import"../chunks/Y7JGSUOA.js";import"../chunks/3MTXB4MK.js";import"../chunks/UEORNVQB.js";import"../chunks/E7TFIHC5.js";import"../chunks/K2GNDX3W.js";import"../chunks/HTLIRVP7.js";import"../chunks/K5FUABWW.js";import"../chunks/SLJ6CW7W.js";import"../chunks/6U2IR4XB.js";import"../chunks/MJGB25S5.js";import"../chunks/WYLIV2P2.js";import"../chunks/74FPPPIG.js";import"../chunks/6B2HILSY.js";import"../chunks/JKWTHRUR.js";import"../chunks/SKVEBOGA.js";import"../chunks/3GUKUEEJ.js";import"../chunks/A7WJJMRY.js";import"../chunks/KWECQJ6X.js";import"../chunks/FSLWD2PE.js";export{a as createRequestTools};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a,b,c,d,e}from"./chunks/
|
|
1
|
+
import{a,b,c,d,e,f}from"./chunks/K5FUABWW.js";import"./chunks/WYLIV2P2.js";export{a as fileScopeEnabled,b as findingHeadlinesEnabled,d as outsideLoadersEnabled,e as promptAgreementEnabled,c as resultSafetyCheckEnabled,f as snapshotSettings};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as B,b as S}from"../chunks/F3R4J3ND.js";import{b as V}from"../chunks/
|
|
1
|
+
import{a as B,b as S}from"../chunks/F3R4J3ND.js";import{b as V}from"../chunks/RNTMH4MU.js";import{b as v,c as K,d as A,e as O}from"../chunks/CWYVUGG4.js";import{O as E,ba as M,oa as z,qa as H,sa as Q,ta as D,ua as N,wa as T,ya as j}from"../chunks/IHAVDX4L.js";import{c as _}from"../chunks/N7U5N42V.js";import"../chunks/6RWEWBHK.js";import"../chunks/CGCJN73D.js";import"../chunks/QDYMR6KS.js";import"../chunks/Y7JGSUOA.js";import"../chunks/3MTXB4MK.js";import"../chunks/UEORNVQB.js";import"../chunks/E7TFIHC5.js";import"../chunks/M6HYSTQD.js";import"../chunks/VGYWI4X2.js";import"../chunks/57M4OQJM.js";import"../chunks/J4AXGE5W.js";import"../chunks/4H23CSUM.js";import"../chunks/K2GNDX3W.js";import"../chunks/HTLIRVP7.js";import"../chunks/DZZBQDGO.js";import"../chunks/FBTOOUPL.js";import"../chunks/IVULXWQN.js";import{b as I}from"../chunks/K5FUABWW.js";import"../chunks/326F4XNG.js";import"../chunks/4F6ZIHXU.js";import"../chunks/SLJ6CW7W.js";import"../chunks/6U2IR4XB.js";import"../chunks/MJGB25S5.js";import{t as k}from"../chunks/WYLIV2P2.js";import"../chunks/KGQYR62R.js";import"../chunks/IBCFGUHI.js";import"../chunks/2PSNOSJ2.js";import"../chunks/KU5DINLW.js";import{sa as P}from"../chunks/GOQVKWP3.js";import"../chunks/74FPPPIG.js";import"../chunks/5TATKWLG.js";import"../chunks/2PZF54KH.js";import"../chunks/6B2HILSY.js";import"../chunks/JKWTHRUR.js";import"../chunks/SKVEBOGA.js";import{b as F}from"../chunks/3GUKUEEJ.js";import"../chunks/724WZMYW.js";import"../chunks/A7WJJMRY.js";import"../chunks/PYKAERZZ.js";import"../chunks/KWECQJ6X.js";import"../chunks/FSLWD2PE.js";import"../chunks/PY5M22CL.js";import"../chunks/YUY436SM.js";import{e as L}from"../chunks/C6X5GDG4.js";import"../chunks/RUVMFAST.js";import"../chunks/S27VIQMZ.js";function G(s,t){return M(s,t,{codeInputs:!1,recall:!1,secondOpinion:!1})}function C(s,t,i,l){let a=t.findingQuality,y={...i.findingCheck?.state?.result??{kept:t.findings,dropped:[],warnings:[]}};a?.assessments&&y.qualityAudit&&(y.qualityAudit={coverage:a.coverage??[],verdicts:a.verdicts??[],assessments:a.assessments,...a.shadow?{shadow:a.shadow}:{}});let e=D(t.findings,t.structures,t.findingHeadlines??[],t.findingHeadlineDiagnostics),g=new Map(e.rows.filter(r=>r.target==="finding").map(r=>[r.index,{headline:r.headline,ifLeft:r.ifLeft}])),m=new Map(e.rows.filter(r=>r.target==="structure").map(r=>[r.index,{headline:r.headline,ifLeft:r.ifLeft}])),R=m.size?t.structures.map((r,w)=>m.has(w)?{...r,...m.get(w)}:r):t.structures,x=g.size?t.findings.map((r,w)=>g.has(w)?{...r,...g.get(w)}:r):t.findings,d=i.findingQuality?.config.switches.ranking?z(x,a?.assessments??[]):void 0;return{repoKey:s,findings:d?.ordered??x,structures:R,graph:t.graph,warnings:t.warnings,...l?{proposalCounts:l}:{},...e.diagnostics?{findingHeadlineDiagnostics:e.diagnostics}:{},skippedFiles:i.inspectPlan?.skipped??[],passes:i.inspectPlan?.passes.length??1,findingCheck:y,...d?{ranking:{defaultIds:d.defaultIds,hiddenIds:d.hiddenIds,emptyMessage:d.emptyMessage}}:{}}}async function J(s,t,i,l=B){let a={...i.state,repos:i.repos,mapped:i.fragments.map(({fragment:e})=>e),findingsRaw:i.findings,warnings:i.state?.warnings??[],splitCheckPriced:!0,splitFindingsPriced:!0},y=S(t,l);for(;;){let e=await j({phase:"structuring",state:a,settings:s,execution:{scopeConcurrency:4,forLocal:!0}},y);if(a=A(a,e),e.next==="persisting")return{state:a,structures:a.structuresRaw??[],warnings:a.warnings??[]}}}function W(s,t){I(t)&&s.requestTools.headlinePlan(_([]))}async function U(s,t,i={}){let{settings:l,qualityConfig:a}=s;W(t,l);let y=E(l);if(!Object.keys(s.files).length)throw new F("empty_folder","No admitted source files were found.");let e={repos:[{key:s.repoKey,kind:"fs",files:s.files,...s.root!==void 0?{root:s.root}:{}}],warnings:s.warnings??[],...s.fragment?{mapped:[s.fragment]}:{}},g=S(t,t.progress);for(;;){let d=await O({phase:"mapping",state:e,settings:l,execution:{scopeConcurrency:4,forLocal:!0,preparation:{capUsd:20,confirmPrice:!1,qualityConfig:a}}},g);if(e=A(e,d),d.next!=="mapping")break}e={...e,analysisFlags:{...y,sourceNotes:!i.findingsOnly&&y.sourceNotes},findingQuality:{config:a},warnings:[...e.warnings??[],...a.diagnostics]};let m="inspecting";for(g.progress.checkpoint=async(d,r)=>{e={...e,...d,...r?{passResults:{...e.passResults,[r.index]:r.result}}:{}},await t.progress.checkpoint(d,r)};m!=="structuring";){let r=await(m==="inspecting"?H:Q)({phase:m,state:e,settings:l,execution:{scopeConcurrency:4,passConcurrency:4,forLocal:!0}},g);e=A(e,r),m=r.next}let R=()=>N({phase:"persisting",state:e,settings:l,execution:{scopeConcurrency:4}});if(!i.findingsOnly){let d=C(s.repoKey,R(),e,s.proposalCounts),r=e.findingsRaw;e={...(await J(l,t,{repos:e.repos,fragments:[{repoKey:s.repoKey,fragment:e.mapped[0]}],graph:d.graph,findings:d.findings,state:e},g.progress)).state,findingsRaw:r}}e=A(e,await T({phase:"persisting",state:e,settings:l,execution:{scopeConcurrency:4,forLocal:!0}},g));let x=R();return await i.resultSink?.(x),C(s.repoKey,x,e,s.proposalCounts)}import{createHash as X}from"node:crypto";async function Y(s,t,i){let l=new Map,a=new Map,y=[],e,g=[],m=()=>{if(i.signal?.throwIfAborted(),e)throw k(e)},R=async f=>{m();try{return await i.list(f)}catch{throw i.signal?.throwIfAborted(),k("unavailable")}},x=async f=>{let u=[],o=new Set,h=new Set,c=new Set,p=f;for(;;){if(m(),p.snapshot!==t.manifest.snapshot||p.commit!==t.manifest.commit)throw k("bad_request");for(let n of p.files){let b=l.get(n.id);if(o.has(n.path)||h.has(n.id)||b&&(b.hash!==n.hash||b.size!==n.size))throw k("bad_request");o.add(n.path),h.add(n.id);let q={...n};l.set(n.id,q),u.push(q)}if(p.complete)return u;if(!p.cursor||c.has(p.cursor))throw k("bad_request");c.add(p.cursor),p=await R(p.cursor)}},d=f=>f.map(({id:u,path:o,size:h})=>({path:o,size:h,ref:u})),r=v(async f=>{if(i.signal?.throwIfAborted(),e)return f.map(()=>null);let u=[...new Set(f.map(o=>o.ref))].filter(o=>!a.has(o)).map(o=>l.get(o));if(u.length){let o;try{o=await i.read(u)}catch{return i.signal?.throwIfAborted(),e="unavailable",f.map(()=>null)}i.signal?.throwIfAborted();let h=new Map(u.map(c=>[c.id,c]));for(let c of o){let p=h.get(c.id);if(!p||c.text!==null&&!c.refusal&&(Buffer.byteLength(c.text)!==p.size||X("sha256").update(c.text).digest("hex")!==p.hash)){e="bad_request";break}h.delete(c.id),a.set(c.id,{text:c.refusal?null:c.text,bytesRead:c.bytesRead,...c.refusal?{refusal:c.refusal}:{}})}if(h.size&&(e="bad_request"),e)return f.map(()=>null)}return f.map(o=>a.get(o.ref)?.text??null)}),w=async f=>{let u=await r(f);return u===null?null:P(s,f,async()=>u)};try{let f=await x(t.manifest),u=await K(s,{repoKey:t.repoKey,entries:d(f),read:w,localListing:!0,repository:{context:async()=>t.selectedRoot===null?null:{selectedRoot:t.selectedRoot},list:async()=>{let n=await R(null),b=await x(n);return y=b,{entries:d(b),truncated:n.truncated,entriesVisited:n.entriesVisited}},read:async n=>(await w(n),a.get(n.ref)??{text:null,bytesRead:0})}});m();let o={repoKey:t.repoKey,...u},h=new Map(f.map(n=>[L(n.path,o.root),n]));o.root!==void 0&&y.forEach(n=>h.set(n.path,n));let c=Object.keys(o.files).map(n=>{let b=h.get(n);if(!b)throw k("bad_request");return{...b,path:n}}),{calls:p}=V(s,o);return g=c.map(n=>n.id),{source:o,finalFiles:c,calls:p}}finally{a.clear(),l.clear(),i.finish?.(g)}}async function Le(s,t,i={}){let l=s.settings,a=G(l,t.requestTools);return U({...s,settings:l,qualityConfig:a},t,i)}export{Y as prepareRelayAnalysis,Le as runEngineAnalysis};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { realpath, stat } from "node:fs/promises";
|
|
3
|
+
import { dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { analysisScopeSchema, analysisSelectionRequestSchema } from "../analysis-core/contracts/analysis-selection.js";
|
|
5
|
+
import { fileScopeEnabled, fileScopeRequested, selectionModeEnabled } from "../adapters/settings.js";
|
|
6
|
+
import { resolveFolderPath } from "../adapters/folder-path.js";
|
|
7
|
+
import { INVALID_SCOPE_MESSAGE, INVALID_SELECTION_MESSAGE } from "../contract/scope-choice.js";
|
|
8
|
+
import { cliRefusals } from "../contract/cli-refusals.js";
|
|
9
|
+
function within(root, path) {
|
|
10
|
+
const rel = relative(root, path);
|
|
11
|
+
return rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
12
|
+
}
|
|
13
|
+
function localPath(root, path) {
|
|
14
|
+
return relative(root, path).split(sep).join("/");
|
|
15
|
+
}
|
|
16
|
+
function folderSelection(path, launchRoot) {
|
|
17
|
+
const parsed = analysisSelectionRequestSchema.safeParse({ kind: "folder", launchRoot,
|
|
18
|
+
folder: localPath(launchRoot, path) || "." });
|
|
19
|
+
return { kind: "folder", path, launchRoot, outputAnchor: path, factsFolder: path, selectionKey: path,
|
|
20
|
+
...(parsed.success ? { request: parsed.data } : {}) };
|
|
21
|
+
}
|
|
22
|
+
/** Selection coordinates are shared by reading, Git facts, outputs, and recovery. Membership stays in core. */
|
|
23
|
+
export async function resolveAnalysisSelection(path, cwd, settings, scope) {
|
|
24
|
+
if (fileScopeRequested(settings) && !fileScopeEnabled(settings))
|
|
25
|
+
throw new Error(cliRefusals.release_unavailable);
|
|
26
|
+
if (!fileScopeEnabled(settings)) {
|
|
27
|
+
if (scope !== undefined)
|
|
28
|
+
throw new Error(INVALID_SCOPE_MESSAGE);
|
|
29
|
+
const [selected, launchRoot] = await Promise.all([resolveFolderPath(resolve(cwd, path)), resolveFolderPath(cwd)]);
|
|
30
|
+
return folderSelection(selected, launchRoot);
|
|
31
|
+
}
|
|
32
|
+
let selected;
|
|
33
|
+
let launchRoot;
|
|
34
|
+
let info;
|
|
35
|
+
let launchInfo;
|
|
36
|
+
const lexicalPath = resolve(cwd, path);
|
|
37
|
+
try {
|
|
38
|
+
[selected, launchRoot] = await Promise.all([realpath(lexicalPath), resolveFolderPath(cwd)]);
|
|
39
|
+
info = await stat(selected);
|
|
40
|
+
if (!info.isDirectory())
|
|
41
|
+
launchInfo = await stat(launchRoot);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Without a usable file type, the folder runner or MCP guard owns the path failure.
|
|
45
|
+
launchRoot = await resolveFolderPath(cwd).catch(() => resolve(cwd));
|
|
46
|
+
if (scope !== undefined)
|
|
47
|
+
throw new Error(INVALID_SCOPE_MESSAGE);
|
|
48
|
+
return folderSelection(lexicalPath, launchRoot);
|
|
49
|
+
}
|
|
50
|
+
// Folder analysis keeps its earlier coordinates; only file selections use the launch boundary.
|
|
51
|
+
if (info.isDirectory()) {
|
|
52
|
+
if (scope !== undefined)
|
|
53
|
+
throw new Error(INVALID_SCOPE_MESSAGE);
|
|
54
|
+
return folderSelection(selected, launchRoot);
|
|
55
|
+
}
|
|
56
|
+
if (!info.isFile() || !within(resolve(cwd), lexicalPath) || !within(launchRoot, selected)
|
|
57
|
+
|| selected === parse(selected).root || !launchInfo?.isDirectory())
|
|
58
|
+
throw new Error(INVALID_SELECTION_MESSAGE);
|
|
59
|
+
const entryPath = localPath(launchRoot, selected);
|
|
60
|
+
let chosen;
|
|
61
|
+
if (scope !== undefined) {
|
|
62
|
+
const parsed = analysisScopeSchema.safeParse(scope);
|
|
63
|
+
if (!parsed.success || parsed.data.entry !== entryPath)
|
|
64
|
+
throw new Error(INVALID_SCOPE_MESSAGE);
|
|
65
|
+
const imports = parsed.data.imports;
|
|
66
|
+
chosen = { ...parsed.data, imports: Array.isArray(imports) ? imports.length ? [...imports].sort() : "none" : imports };
|
|
67
|
+
}
|
|
68
|
+
const request = analysisSelectionRequestSchema.safeParse({ kind: "file", launchRoot, entry: entryPath,
|
|
69
|
+
...(chosen === undefined ? {} : { scope: chosen }) });
|
|
70
|
+
if (!request.success)
|
|
71
|
+
throw new Error(INVALID_SELECTION_MESSAGE);
|
|
72
|
+
const outputAnchor = dirname(selected);
|
|
73
|
+
const entryHash = createHash("sha256").update(entryPath).digest("hex");
|
|
74
|
+
const selectionKey = `file:${createHash("sha256").update(JSON.stringify([launchRoot, entryPath,
|
|
75
|
+
chosen ? [chosen.snapshot, chosen.imports] : null])).digest("hex")}`;
|
|
76
|
+
return { kind: "file", path: selected, launchRoot, entryPath, outputAnchor,
|
|
77
|
+
outputDir: join(outputAnchor, ".counterfact/files", entryHash), factsFolder: launchRoot, selectionKey, request: request.data };
|
|
78
|
+
}
|
|
79
|
+
/** Entry points resolve coordinates once; downstream stages reuse the same captured description. */
|
|
80
|
+
export async function resolveRunSelection(path, cwd, settings, options = {}) {
|
|
81
|
+
if (!selectionModeEnabled(settings)) {
|
|
82
|
+
if (options.scope !== undefined)
|
|
83
|
+
throw new Error(INVALID_SCOPE_MESSAGE);
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return options.selection ?? resolveAnalysisSelection(path, cwd, settings, options.scope);
|
|
87
|
+
}
|
|
88
|
+
export function analysisSaveOptions(selection, outputDir) {
|
|
89
|
+
return { defaultFileOutput: selection?.kind === "file" && outputDir === undefined,
|
|
90
|
+
scope: selection?.request?.kind === "file" ? selection.request.scope : undefined };
|
|
91
|
+
}
|
|
@@ -11,6 +11,10 @@ import { readFile } from "node:fs/promises";
|
|
|
11
11
|
import { resolve } from "node:path";
|
|
12
12
|
import { loadAgentProposal } from "../../contract/agent-proposal.js";
|
|
13
13
|
import { formatSavedFindings } from "../finding-display.js";
|
|
14
|
+
import { scopeChoicesEnabled } from "../../adapters/settings.js";
|
|
15
|
+
import { resolveRunSelection } from "../analysis-selection.js";
|
|
16
|
+
import { renderScopeChoices } from "../scope-choices.js";
|
|
17
|
+
import { progressLine } from "../../contract/scope-choice.js";
|
|
14
18
|
// Only a real pause says "paused"; an unreviewed release or an upload-only server cannot start.
|
|
15
19
|
const unavailable = START_FAILURE_MESSAGE;
|
|
16
20
|
function requireLocal(value) {
|
|
@@ -31,8 +35,8 @@ function requireLocal(value) {
|
|
|
31
35
|
if (value.mode !== "local")
|
|
32
36
|
throw new ApiError(503, "unavailable", unavailable);
|
|
33
37
|
}
|
|
34
|
-
export function parseAnalyzeOptions(args) {
|
|
35
|
-
let path, proposalFile;
|
|
38
|
+
export function parseAnalyzeOptions(args, choices = false) {
|
|
39
|
+
let path, proposalFile, scopeFile;
|
|
36
40
|
for (let index = 0; index < args.length; index++) {
|
|
37
41
|
const arg = args[index];
|
|
38
42
|
if (arg === "--proposal" && proposalFile === undefined) {
|
|
@@ -41,15 +45,22 @@ export function parseAnalyzeOptions(args) {
|
|
|
41
45
|
throw new Error();
|
|
42
46
|
proposalFile = value;
|
|
43
47
|
}
|
|
48
|
+
else if (choices && arg === "--scope" && scopeFile === undefined) {
|
|
49
|
+
const value = args[++index];
|
|
50
|
+
if (!value || value.startsWith("-"))
|
|
51
|
+
throw new Error();
|
|
52
|
+
scopeFile = value;
|
|
53
|
+
}
|
|
44
54
|
else if (!arg.startsWith("-") && path === undefined)
|
|
45
55
|
path = arg;
|
|
46
56
|
else
|
|
47
57
|
throw new Error();
|
|
48
58
|
}
|
|
49
|
-
return { path: path ?? ".", options: proposalFile === undefined ? {} : { proposalFile } };
|
|
59
|
+
return { path: path ?? ".", options: { ...(proposalFile === undefined ? {} : { proposalFile }), ...(scopeFile === undefined ? {} : { scopeFile }) } };
|
|
50
60
|
}
|
|
51
61
|
export async function analyze(path, options, ctx) {
|
|
52
62
|
const startup = ctx.startup;
|
|
63
|
+
const scope = options.scope;
|
|
53
64
|
const proposal = await loadAgentProposal(async () => options.proposalFile === undefined ? options.proposal
|
|
54
65
|
: JSON.parse(await readFile(resolve(ctx.cwd ?? process.cwd(), options.proposalFile), "utf8")), startup.settings);
|
|
55
66
|
requireLocal(await ctx.api.request("checks/mode"));
|
|
@@ -60,7 +71,8 @@ export async function analyze(path, options, ctx) {
|
|
|
60
71
|
const token = await ctx.token?.();
|
|
61
72
|
if (!token)
|
|
62
73
|
throw new ApiError(401, "unauthorized", cliApiMessages.unauthorized);
|
|
63
|
-
const
|
|
74
|
+
const selection = await resolveRunSelection(path, ctx.cwd ?? process.cwd(), startup.settings, options);
|
|
75
|
+
const folder = selection?.path ?? resolveAgentFolder(path, ctx.cwd);
|
|
64
76
|
const config = Object.freeze({ ...startup.transport, CF_RELAY_URL: startup.transport.CF_RELAY_URL ?? release.relayUrl,
|
|
65
77
|
CF_LOCAL_RELAY: "1", CF_CONSOLE_URL: ctx.api.baseUrl, CF_CONSOLE_TOKEN: token });
|
|
66
78
|
const controller = new AbortController();
|
|
@@ -72,13 +84,23 @@ export async function analyze(path, options, ctx) {
|
|
|
72
84
|
ctx.write("\r\u001b[2K");
|
|
73
85
|
progressShown = false;
|
|
74
86
|
} };
|
|
87
|
+
let choice;
|
|
75
88
|
try {
|
|
76
|
-
|
|
89
|
+
const code = await (ctx.relayRuntime?.run ?? runRelayCheck)(folder, {
|
|
77
90
|
settings: startup.settings, config, release, cwd: ctx.cwd, connect: development?.connect ?? ctx.relayRuntime?.connect,
|
|
91
|
+
...(ctx.relayRuntime?.selectionProvider ? { selectionProvider: ctx.relayRuntime.selectionProvider } : {}),
|
|
78
92
|
...(proposal ? { proposal } : {}),
|
|
93
|
+
...(selection ? { selection } : {}), ...(scope ? { scope } : {}),
|
|
79
94
|
signal: ctx.signal ? AbortSignal.any([controller.signal, ctx.signal]) : controller.signal,
|
|
80
95
|
stdout() { }, stderr() { },
|
|
81
|
-
onStart: () => { ctx.onCheckStart?.(); ctx.write(
|
|
96
|
+
onStart: () => { ctx.onCheckStart?.(); ctx.write(`\r\u001b[2K${progressLine(selection, "terminal")}`); progressShown = true; },
|
|
97
|
+
...(scopeChoicesEnabled(startup.settings) ? { onScopeChoice: (value) => {
|
|
98
|
+
choice = value;
|
|
99
|
+
clearProgress();
|
|
100
|
+
ctx.onScopeChoice?.(value);
|
|
101
|
+
} } : {}),
|
|
102
|
+
onNotice: message => { clearProgress(); ctx.write(`${message}\n`); },
|
|
103
|
+
onSaving: () => { clearProgress(); ctx.write("\r\u001b[2KSaving the results…"); progressShown = true; },
|
|
82
104
|
onLocalSaved: result => {
|
|
83
105
|
if (result.ignoreAdded) {
|
|
84
106
|
clearProgress();
|
|
@@ -99,6 +121,9 @@ export async function analyze(path, options, ctx) {
|
|
|
99
121
|
ctx.write(`Full results: ${result.url}\n`);
|
|
100
122
|
},
|
|
101
123
|
});
|
|
124
|
+
if (choice && !ctx.onScopeChoice && selection)
|
|
125
|
+
ctx.write(await renderScopeChoices(choice, selection));
|
|
126
|
+
return code;
|
|
102
127
|
}
|
|
103
128
|
finally {
|
|
104
129
|
clearProgress();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { OutputPathError } from "../adapters/output-paths.js";
|
|
2
|
+
import { FINISH_FAILURE_MESSAGE } from "../contract/cli-refusals.js";
|
|
3
|
+
import { completionRecoveryDecision, observedCompletionTiming } from "./completion-recovery.js";
|
|
4
|
+
import { ResultsUploadError } from "./results-upload.js";
|
|
5
|
+
/** Keep delivery ahead of report writes, including when private storage is unavailable. */
|
|
6
|
+
export async function deliverCompletedResults(operations) {
|
|
7
|
+
const result = { uploaded: false };
|
|
8
|
+
let storageError, uploadError;
|
|
9
|
+
try {
|
|
10
|
+
await operations.persist(false);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
storageError = error;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
result.saved = await operations.submit();
|
|
17
|
+
result.uploaded = true;
|
|
18
|
+
try {
|
|
19
|
+
await operations.persist(true);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
storageError ??= error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
uploadError = error;
|
|
27
|
+
if (error instanceof ResultsUploadError) {
|
|
28
|
+
result.outcome = error.outcome;
|
|
29
|
+
result.timing = error.timing;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
result.paths = await operations.saveReports();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
result.localErrorMessage = "The local report couldn't be written.";
|
|
37
|
+
}
|
|
38
|
+
if (storageError) {
|
|
39
|
+
const message = storageError instanceof OutputPathError ? storageError.message : FINISH_FAILURE_MESSAGE;
|
|
40
|
+
result.localErrorMessage = result.localErrorMessage ? `${message}\n${result.localErrorMessage}` : message;
|
|
41
|
+
}
|
|
42
|
+
result.error = storageError ?? uploadError ?? (result.localErrorMessage ? new Error(result.localErrorMessage) : undefined);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
/** Cleanup consumes the same decision as upload and writes only while the runner owns the folder. */
|
|
46
|
+
export async function recoverCompletedResults(input, operations) {
|
|
47
|
+
const timing = observedCompletionTiming(input.timing ?? {}, input.statusLookup, input.payload);
|
|
48
|
+
const decision = completionRecoveryDecision({ ...input, timing });
|
|
49
|
+
if (input.canWrite) {
|
|
50
|
+
try {
|
|
51
|
+
if (decision.action === "saved")
|
|
52
|
+
await operations.markUploaded();
|
|
53
|
+
else if (decision.action === "give-up")
|
|
54
|
+
await operations.retire();
|
|
55
|
+
else if (decision.action === "retry" && input.retryEnabled && input.completionStored)
|
|
56
|
+
await operations.keepPending?.(timing);
|
|
57
|
+
}
|
|
58
|
+
catch { /* A local write cannot change a confirmed server outcome. */ }
|
|
59
|
+
}
|
|
60
|
+
const recoveryMessage = "message" in decision && (input.completionStored || decision.action === "give-up") ? decision.message : undefined;
|
|
61
|
+
const message = input.localErrorMessage && recoveryMessage ? `${input.localErrorMessage}\n${recoveryMessage}` : recoveryMessage ?? input.localErrorMessage;
|
|
62
|
+
return { decision, message };
|
|
63
|
+
}
|
|
@@ -1,18 +1,72 @@
|
|
|
1
|
-
|
|
1
|
+
import { cliRefusals, NOT_ALLOWED_MESSAGE, SIGN_IN_EXPIRED_MESSAGE, CHECK_CONFLICT_MESSAGE, PENDING_RESULTS_MESSAGE, UNSAVED_RESULTS_MESSAGE } from "../contract/cli-refusals.js";
|
|
2
|
+
export const OTHER_SETUP_RESULTS_MESSAGE = "A saved result from another Counterfact setup was left untouched.";
|
|
3
|
+
export const COMPLETION_SETTINGS_MISMATCH_MESSAGE = "This folder has a saved result for a different Counterfact project or address. Run the analysis again with the original settings to save it.";
|
|
2
4
|
export const matchesCheck = (status, identity) => status.checkId === identity.checkId && status.projectId === identity.projectId;
|
|
5
|
+
export function observedCompletionTiming(timing, lookup, payload) {
|
|
6
|
+
const status = lookup?.kind === "found" ? lookup.status : undefined;
|
|
7
|
+
if (!status || !payload || !matchesCheck(status, payload) || !status.absoluteExpiresAt)
|
|
8
|
+
return timing;
|
|
9
|
+
return { ...timing, absoluteExpiresAt: Math.min(timing.absoluteExpiresAt ?? Infinity, Date.parse(status.absoluteExpiresAt)) };
|
|
10
|
+
}
|
|
11
|
+
export function completionDeadline(timing, lookup, payload, outcome) {
|
|
12
|
+
const observed = observedCompletionTiming(timing, lookup, payload);
|
|
13
|
+
const reachable = lookup?.kind === "found" || lookup?.kind === "failed" && lookup.httpStatus !== undefined
|
|
14
|
+
|| outcome && "httpStatus" in outcome && outcome.httpStatus !== undefined;
|
|
15
|
+
return Math.min(observed.completedAt === undefined ? Infinity : observed.completedAt + 2 * 60 * 60_000, reachable ? Infinity : observed.absoluteExpiresAt ?? Infinity);
|
|
16
|
+
}
|
|
17
|
+
export function completionRetryDeadline(timing, lookup, payload, outcome) {
|
|
18
|
+
return Math.min(completionDeadline(timing, lookup, payload, outcome), timing.retryStartedAt === undefined ? Infinity : timing.retryStartedAt + 10 * 60_000);
|
|
19
|
+
}
|
|
20
|
+
/** HTTP status owns certainty; proxy text and unfamiliar server codes cannot discard paid work. */
|
|
3
21
|
export function completionRecoveryDecision(input) {
|
|
22
|
+
const { statusLookup, uploadOutcome, payload, retryEnabled, timing = {}, now = Date.now() } = input;
|
|
23
|
+
const uploadSaved = uploadOutcome.kind === "saved" || uploadOutcome.kind === "decided" && uploadOutcome.decision.action === "saved";
|
|
4
24
|
if (input.localMismatch)
|
|
5
|
-
return {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
return !retryEnabled ? { action: "retry", automatic: false, message: COMPLETION_SETTINGS_MISMATCH_MESSAGE }
|
|
26
|
+
: !uploadSaved && now >= completionDeadline(timing) ? { action: "give-up" }
|
|
27
|
+
: { action: "leave", message: OTHER_SETUP_RESULTS_MESSAGE };
|
|
28
|
+
const status = statusLookup.kind === "found" ? statusLookup.status : undefined;
|
|
29
|
+
const matching = status && matchesCheck(status, payload);
|
|
30
|
+
if (uploadSaved
|
|
31
|
+
|| retryEnabled && uploadOutcome.kind === "refused" && uploadOutcome.httpStatus !== undefined && uploadOutcome.httpStatus >= 200 && uploadOutcome.httpStatus < 300
|
|
32
|
+
|| matching && status.uploadState === "saved")
|
|
33
|
+
return { action: "saved" };
|
|
34
|
+
// With retry off, trusted terminal status retires unsaved work using the original refusal.
|
|
35
|
+
if (!retryEnabled)
|
|
36
|
+
return matching && status.uploadState === "missing" && ["closed", "expired"].includes(status.state)
|
|
37
|
+
? { action: "give-up" } : { action: "retry", automatic: false };
|
|
38
|
+
if (uploadOutcome.kind === "decided" && uploadOutcome.decision.action === "give-up")
|
|
39
|
+
return uploadOutcome.decision;
|
|
40
|
+
if (status && !matching)
|
|
41
|
+
return { action: "give-up", code: "check_conflict", message: CHECK_CONFLICT_MESSAGE };
|
|
42
|
+
if (now >= completionDeadline(timing, statusLookup, payload, uploadOutcome)) {
|
|
43
|
+
return { action: "give-up", message: UNSAVED_RESULTS_MESSAGE };
|
|
44
|
+
}
|
|
45
|
+
const refusals = [uploadOutcome.kind === "refused" ? uploadOutcome : undefined]
|
|
46
|
+
.filter(value => value !== undefined);
|
|
47
|
+
const uncertain = ({ code, httpStatus, transportFailure }) => transportFailure || (httpStatus === undefined
|
|
48
|
+
? code === "unavailable"
|
|
49
|
+
: httpStatus === 408 || httpStatus === 429 || httpStatus >= 500 && httpStatus <= 599 || httpStatus === 409 && code === "reservation_closing"
|
|
50
|
+
|| httpStatus < 400 || httpStatus >= 600);
|
|
51
|
+
const refusal = refusals.find(value => !uncertain(value));
|
|
52
|
+
if (refusal) {
|
|
53
|
+
// Guidance is explicit per code; copy edits never decide whether results survive.
|
|
54
|
+
const messages = {
|
|
55
|
+
check_conflict: CHECK_CONFLICT_MESSAGE,
|
|
56
|
+
not_allowed: NOT_ALLOWED_MESSAGE,
|
|
57
|
+
unauthorized: SIGN_IN_EXPIRED_MESSAGE,
|
|
58
|
+
invalid_body: cliRefusals.invalid_body,
|
|
59
|
+
cli_update_required: cliRefusals.cli_update_required,
|
|
60
|
+
local_checks_paused: cliRefusals.local_checks_paused,
|
|
61
|
+
};
|
|
62
|
+
return { action: "give-up", code: refusal.code, message: Object.hasOwn(messages, refusal.code)
|
|
63
|
+
? refusal.code === "check_conflict" ? messages[refusal.code] : `${messages[refusal.code]}\n${UNSAVED_RESULTS_MESSAGE}`
|
|
64
|
+
: UNSAVED_RESULTS_MESSAGE };
|
|
65
|
+
}
|
|
66
|
+
if (matching && status.uploadState === "missing" && status.settlement === "released")
|
|
67
|
+
return { action: "give-up",
|
|
68
|
+
code: status.state === "expired" ? "reservation_expired" : "reservation_closed", message: UNSAVED_RESULTS_MESSAGE };
|
|
69
|
+
if (uploadOutcome.kind === "decided")
|
|
70
|
+
return uploadOutcome.decision;
|
|
71
|
+
return { action: "retry", automatic: now < completionRetryDeadline(timing, statusLookup, payload, uploadOutcome) && refusals.some(value => uncertain(value)), message: PENDING_RESULTS_MESSAGE };
|
|
18
72
|
}
|
package/dist/cli/context.js
CHANGED
|
@@ -8,7 +8,7 @@ import { userEmail } from "./git.js";
|
|
|
8
8
|
import { terminalSignInInput } from "./sign-in-input.js";
|
|
9
9
|
import { readFindingSettings } from "./finding-settings.js";
|
|
10
10
|
export function commandContext(options = {}) {
|
|
11
|
-
const startup = readCliSettings(options.env, options.emailSignIn);
|
|
11
|
+
const startup = options.startup ?? readCliSettings(options.env, options.emailSignIn);
|
|
12
12
|
const homeDir = options.homeDir ?? homedir();
|
|
13
13
|
const baseUrl = (options.baseUrl ?? startup.baseUrl ?? DEFAULT_URL).replace(/\/+$/, "");
|
|
14
14
|
const api = new ApiClient(baseUrl, () => readCredentials(homeDir, api.baseUrl), undefined, options.signal);
|
|
@@ -20,6 +20,7 @@ export function commandContext(options = {}) {
|
|
|
20
20
|
startup, signal: options.signal, relayRuntime: options.relayRuntime, cwd: options.cwd ?? process.cwd(),
|
|
21
21
|
token: () => readCredentials(homeDir, api.baseUrl), onCheckComplete: options.onCheckComplete, onCheckStart: options.onCheckStart, onAgentChoice: options.onAgentChoice,
|
|
22
22
|
onCheckFailure: options.onCheckFailure,
|
|
23
|
+
onScopeChoice: options.onScopeChoice,
|
|
23
24
|
api, homeDir, write, openBrowser: options.openBrowser ?? openBrowser,
|
|
24
25
|
signInInput: options.signInInput ?? terminalSignInInput(), readEmail: options.readEmail ?? userEmail,
|
|
25
26
|
sleep: options.sleep ?? (async (ms) => { await delay(ms, undefined, { signal: options.signal }); }), now: options.now ?? Date.now,
|