bostrat-node 1.10.0 → 1.10.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/bin/bostrat-blueprint +1 -1
- package/dist/index.js +8 -3
- package/package.json +1 -1
package/bin/bostrat-blueprint
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var d=process.env.BOSTRAT_AGENT_URL||`http://127.0.0.1:${process.env.BOSTRAT_AGENT_PORT||3362}`;async function l(e,n,
|
|
2
|
+
var d=process.env.BOSTRAT_AGENT_URL||`http://127.0.0.1:${process.env.BOSTRAT_AGENT_PORT||3362}`;async function l(e,n,c){let o=await fetch(`${d}${n}`,{method:e,headers:c?{"content-type":"application/json"}:void 0,body:c?JSON.stringify(c):void 0}),t=await o.json().catch(()=>({}));if(!o.ok)throw new Error(t.error||`HTTP ${o.status}`);return t}function r(e){console.error(`[bostrat-blueprint] ${e}`),process.exit(1)}function u(e){if(e){console.log(` parsed: ${e.sections.recognized} recognized section(s), ${e.items.total} item(s) (${e.items.bindable} bindable)`);for(let n of e.issues??[])console.log(` \u26A0 ${n.message}`)}}var i=process.argv.slice(2),s=i.shift();if(s==="add"||s==="update"){let e=null,n=null,c=null,o=null;for(let t=0;t<i.length;t++)i[t]==="--circuit"?e=i[++t]:i[t]==="--new-circuit"?n=i[++t]:i[t]==="--name"?c=i[++t]:o=i[t];o||r(`usage: bostrat-blueprint ${s} [--circuit <name-or-id>] [--new-circuit "<name>"] [--name "<title>"] <file.md>`);try{let t=await(await import("node:fs/promises")).readFile(o,"utf8"),a=await l("POST","/api/blueprints/publish",{cwd:process.cwd(),circuit:e,newCircuit:n,name:c,markdown:t});console.log(`[bostrat-blueprint] published \u201C${a.blueprint.name}\u201D v${a.blueprint.version} on circuit \u201C${a.circuit.name}\u201D`),u(a.report),a.blueprint.version===1&&console.log(" The circuit page now carries this blueprint; PRs/commits mentioning BP ids show as evidence \u2014 tick [x] + a *(done \u2026)* note in the doc when an item lands.")}catch(t){r(t.message)}}else if(s==="show"||s==="report")try{let e=await l("GET",`/api/blueprints/show?cwd=${encodeURIComponent(process.cwd())}${i[0]?`&circuit=${encodeURIComponent(i[0])}`:""}`);if(console.log(`[bostrat-blueprint] \u201C${e.blueprint.name}\u201D v${e.blueprint.version} (circuit ${e.blueprint.circuitId})`),u(e.report),s==="show")for(let n of e.items)console.log(` ${n.bindable?n.itemId.padEnd(8):"(no id)".padEnd(8)} ${n.sectionKind.padEnd(14)} ${n.text}`)}catch(e){r(e.message)}else if(s==="tag"){i.length||r("usage: bostrat-blueprint tag <BP-id> [<BP-id>\u2026]");try{let e=await l("POST","/api/blueprints/tag",{cwd:process.cwd(),itemIds:i});console.log(`[bostrat-blueprint] tagged this Track onto ${e.itemIds.join(", ")}`),console.log(" (association + cost attribution \u2014 completion still comes from merged PRs or a manual tick)")}catch(e){r(e.message)}}else r("usage: bostrat-blueprint <add|update|show|report|tag> \u2026 (add [--circuit <ref>] <file.md>)");
|
package/dist/index.js
CHANGED
|
@@ -191,7 +191,9 @@ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.t
|
|
|
191
191
|
`)){if(o.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1,hunks:[]},r=null,t.push(n);continue}if(n)if(o.startsWith("--- ")&&!r){let s=o.slice(4).trim();n.oldPath=s==="/dev/null"?null:s.replace(/^a\//,"")}else if(o.startsWith("+++ ")&&!r){let s=o.slice(4).trim();n.newPath=s==="/dev/null"?null:s.replace(/^b\//,"")}else if(o.startsWith("Binary files"))n.binary=!0;else if(o.startsWith("@@")){let s=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(o);if(!s)continue;let a=Number(s[1]),i=s[2]==null?1:Number(s[2]),c=Number(s[3]),l=s[4]==null?1:Number(s[4]);i>0&&n.deleted.push([a,i]),n.added+=l,r={oldStart:a,oldCount:i,newStart:c,newCount:l,del:[],add:[]},n.hunks.push(r)}else r&&o.startsWith("-")?r.del.push(o.slice(1)):r&&o.startsWith("+")&&r.add.push(o.slice(1))}return t}function PF(e,t){let n=nw(e),r=nw(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Td&&(n=n.slice(0,Td)),r.length>Td&&(r=r.slice(0,Td));let o=new Array(r.length+1),s=new Array(r.length+1);for(let a=0;a<=r.length;a++)o[a]=a;for(let a=1;a<=n.length;a++){s[0]=a;let i=n.charCodeAt(a-1);for(let c=1;c<=r.length;c++){let l=i===r.charCodeAt(c-1)?0:1;s[c]=Math.min(o[c]+1,s[c-1]+1,o[c-1]+l)}[o,s]=[s,o]}return 1-o[r.length]/Math.max(n.length,r.length)}function DF(e,t=ST){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!nw(r[s]).length){n.add(a);continue}s<o.length&&PF(r[s],o[s])>=t&&n.add(a)}return n}function BF(e){let t=[...e].sort((r,o)=>r-o),n=[];for(let r of t){let o=n[n.length-1];o&&o[0]+o[1]===r?o[1]+=1:n.push([r,1])}return n}function jF(e){let t=new Map,n=null;for(let r of String(e||"").split(`
|
|
192
192
|
`)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function bT(e,t){let{stdout:n}=await tw(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
|
|
193
193
|
`);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
|
|
194
|
-
`)}}async function AT(e,t,{fixKey:n=null,window:r=lo,resolveOrigin:o=null,context:s={}}={}){let a=await bT(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=wT(a.message),l=n?Ed(n):c.epoch,u=l?Sa(l):null,{stdout:d}=await tw(e,["diff","-U0","--no-color","-M","-C",i,t]),p=NF(d),f=0,w=0,m=0,g=0,y=0,b=0,k=0,S=new Map;for(let I of p){if(I.binary)continue;let j=I.oldPath||I.newPath||"",K=I.deleted.reduce((W,[,Y])=>W+Y,0),R=CF(j);if(R==="excluded"){m+=K;continue}if(R==="docs"){g+=K,y+=I.added;continue}if(R==="config"){b+=K;continue}f+=I.added;let E=new Set;for(let W of I.hunks||[])for(let Y of DF(W))E.add(Y);k+=E.size;let C=[];for(let[W,Y]of I.deleted)for(let me=W;me<W+Y;me++)E.has(me)||C.push(me);if(w+=C.length,!I.oldPath||!C.length)continue;let P;try{let W=["blame","-w","-M","-C","--line-porcelain"];for(let[Y,me]of BF(C))W.push("-L",`${Y},${Y+me-1}`);W.push(i,"--",I.oldPath),P=jF((await tw(e,W)).stdout)}catch{continue}for(let{sha:W,time:Y}of P.values()){let me=S.get(W)??{lines:0,time:Y};me.lines+=1,S.set(W,me)}}let $=[],M=0,L=new Map;for(let[I,{lines:j,time:K}]of S){let R=L.get(I);if(!R){try{R=await bT(e,I)}catch{R=null}L.set(I,R)}let E=R?wT(R.message):{epoch:null},C=E.epoch,P=E.provider,W=E.model;if(!C&&o){let ne=await o(I,R);ne?.trackId&&ne?.boxId!=null&&(C={trackId:ne.trackId,boxId:ne.boxId,epoch:ne.epoch??0},P=P??ne.provider??null,W=W??ne.model??null)}if(!C){M+=j;continue}let Y=Number.isFinite(K)?K:R?.ts??a.ts,me=Math.max(0,(a.ts-Y)/gF),_e=Sa(C),Pe=_e===u?"self":xF(me,r);$.push({sha:I,key:_e,trackId:C.trackId,boxId:C.boxId,epoch:C.epoch,provider:P??null,model:W??null,lines:j,ageDays:Math.round(me*100)/100,class:Pe,decay:Pe==="rework"?1:Pe==="drift"?Math.round(vF(me,{window:r})*1e3)/1e3:0})}$.sort((I,j)=>j.lines-I.lines);let B=$d({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),A=sw({heuristic:B,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:m,cosmeticDeleted:k,docsDeleted:g,docsAdded:y,configDeleted:b,codeDelta:f+w+k>0,origins:$,unattributedLines:M,ghost:w===0&&f>0,heuristic:B,intent:A}}function TT(e,{minLines:t=ow}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return Aa.has(n)?hc(e)>=t:!1}function hc(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function ew(e){let t=e.genUsd;return{...e,genUsd:wn(t),reworkChargedUsd:wn(e.reworkChargedUsd),reworkPendingUsd:wn(e.reworkPendingUsd),trueUsd:wn(t+e.reworkChargedUsd),multiplier:t>0?wn((t+e.reworkChargedUsd)/t):null}}function ET(e,{window:t=lo,boxMeta:n={}}={}){let r=e||[],o=r.filter(A=>A.type==="cost.recorded"),s=r.filter(A=>A.type==="code.committed"),a=r.filter(A=>A.type==="code.rework"),i=A=>Array.isArray(A?.shas)&&A.shas.length?A.shas:A?.sha?[A.sha]:[],c=new Map,l=new Set;for(let A of r)if(A.type==="rework.cause.offered")for(let I of i(A.payload))l.add(I);else if(A.type==="rework.cause.answered"&&A.payload?.cause)for(let I of i(A.payload))c.set(I,A.payload.cause);else if(A.type==="rework.cause.retracted")for(let I of i(A.payload))c.delete(I);let u={},d=(A,I,j)=>Sa({trackId:A,boxId:I,epoch:j??0}),p=(A,I={})=>{if(!u[A]){let K=Ed(A)||{};u[A]={key:A,...K,provider:null,model:null,...Qh()}}let j=u[A];return I.provider&&!j.provider&&(j.provider=I.provider),I.model&&!j.model&&(j.model=I.model),j};for(let A of o){if(!A.boxId)continue;let I=d(A.trackId,A.boxId,A.epoch),{usd:j,model:K}=Xt(A),R=p(I,{provider:A.provider,model:K!=="unknown"?K:null});R.genUsd+=j}let f=new Map;for(let A of s){let I=`${A.trackId}/${A.boxId}`;(f.get(I)??f.set(I,[]).get(I)).push({...A,ts:A.payload?.ts??A.ts})}for(let A of f.values())A.sort((I,j)=>I.ts-j.ts);let w=(A,I,j,K)=>{let R=f.get(`${A}/${I}`)||[],E=-1/0;for(let W of R)W.ts<K&&(E=W.ts);let C=0,P=0;for(let W of o)W.trackId!==A||W.boxId!==I||(W.epoch??0)===(j??0)&&(W.ts<=E||W.ts>K||(C+=Xt(W).usd,P++));return{usd:C,turns:P,from:Number.isFinite(E)?E:null}},m={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},b=0,k=[],S=[],$={},M={},L=new Set;for(let A of a){let I=A.payload||{};if(!I.sha||L.has(I.sha))continue;if(L.add(I.sha),I.codeDelta===!1){b++;continue}let j=Ed(I.fixKey)||{trackId:A.trackId,boxId:A.boxId,epoch:A.epoch??0},{usd:K,turns:R}=w(j.trackId,j.boxId,j.epoch,I.ts??A.ts),E=bF.includes(I.intent?.intent)?I.intent.intent:"unknown";y[E]+=1;let C=null;c.has(I.sha)?C={cause:c.get(I.sha),level:"B",basis:"operator"}:(I.heuristic?.level&&I.heuristic.level!=="C"||I.heuristic)&&(C=I.heuristic);let P=C?.level??"none";g[P]=(g[P]||0)+1;let W=yF.has(P),Y=Number(I.deleted)||0,me=Array.isArray(I.origins)?I.origins:[],_e=me.filter(ne=>ne.class==="rework").reduce((ne,Ve)=>ne+Ve.lines,0),Pe={sha:I.sha,subject:I.subject??"",ts:I.ts??A.ts,trackId:A.trackId,fixKey:I.fixKey??null,fixProvider:I.fixProvider??A.provider??null,fixUsd:wn(K),fixTurns:R,linesReworked:_e,unattributedLines:Number(I.unattributedLines)||0,ghost:I.ghost===!0,intent:{intent:E,basis:I.intent?.basis??null},verdict:C?{cause:C.cause,level:P,basis:C.basis??null}:null,charged:wn(0),origins:[]};if(E==="planned"||C?.cause===Id){m.planned+=K;for(let ne of me)ne.class==="rework"&&Pe.origins.push({key:ne.key,provider:ne.provider??null,model:ne.model??null,lines:ne.lines,ageDays:ne.ageDays,class:ne.class,usd:0})}else if(I.ghost||Y===0)m.ghost+=K;else{let ne=0;for(let ve of me){let ce=ve.lines/Y,re=K*ce;if(ne+=re,ve.class==="self"){m.self+=re;continue}let Ce=ve.class==="rework"?1:Number(ve.decay)||0,J=re*Ce;if(m.decayed+=re-J,J<=0)continue;let he=p(ve.key,{provider:ve.provider,model:ve.model});he.fixes+=1,he.linesReworked+=ve.class==="rework"?ve.lines:0;let Fe=C?.cause&&mc.includes(C.cause)?C.cause:"unclassified";he.causes[Fe]+=1,W?(he.reworkChargedUsd+=J,m.charged+=J,Pe.charged=wn(Pe.charged+J)):(he.reworkPendingUsd+=J,m.pending+=J),Pe.origins.push({key:ve.key,provider:he.provider,model:he.model,lines:ve.lines,ageDays:ve.ageDays,class:ve.class,usd:wn(J)})}let Ve=Math.max(0,K-ne);m.unattributed+=Ve}k.push(Pe),!c.has(I.sha)&&l.has(I.sha)&&S.push(I.sha)}for(let A of Object.values(u)){let I=A.provider||"unknown",j=A.model||"unknown",K=R=>{R.genUsd+=A.genUsd,R.reworkChargedUsd+=A.reworkChargedUsd,R.reworkPendingUsd+=A.reworkPendingUsd,R.linesReworked+=A.linesReworked,R.fixes+=A.fixes;for(let E of Object.keys(R.causes))R.causes[E]+=A.causes[E]};K($[I]||=Qh()),K(M[j]||=Qh())}k.sort((A,I)=>I.ts-A.ts);let B=Object.values(u).map(A=>{let I=n[`${A.trackId}/${A.boxId}`]||{};return ew({...A,trackName:I.trackName??null,label:I.label??null})}).sort((A,I)=>I.reworkChargedUsd+I.reworkPendingUsd-(A.reworkChargedUsd+A.reworkPendingUsd)||I.genUsd-A.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${ST} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:b,byEpoch:Object.fromEntries(B.map(A=>[A.key,A])),epochs:B,byProvider:Object.fromEntries(Object.entries($).map(([A,I])=>[A,ew(I)])),byModel:Object.fromEntries(Object.entries(M).map(([A,I])=>[A,ew(I)])),buckets:Object.fromEntries(Object.entries(m).map(([A,I])=>[A,wn(I)])),fixUsdTotal:wn(Object.values(m).reduce((A,I)=>A+I,0)),fixes:k,verdicts:g,pendingTaps:S,commits:s.length}}var hF,wF,tw,kT,xT,vT,gF,lo,rw,ow,mc,Id,yF,bF,Aa,ST,kF,SF,gT,AF,TF,EF,IF,_F,yT,$F,RF,OF,MF,nw,Td,wn,Qh,Rd=q(()=>{Yr();hF=mF(fF),wF=64*1024*1024,tw=(e,t)=>hF("git",["-C",e,...t],{maxBuffer:wF,timeout:6e4}),kT="Bostrat-Epoch",xT="Bostrat-Model",vT="Bostrat-Fix-Cause",gF=24*36e5,lo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,rw=90,ow=3,mc=Object.freeze(["defect","design","requirements","style"]),Id="not-a-fix",yF=new Set(["A","B","E"]),bF=Object.freeze(["fix","likely-fix","planned","unknown"]),Aa=new Set(["fix","likely-fix"]),ST=.8;kF={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};SF=/^revert\b|^revert "/i,gT=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,AF=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,TF=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;EF=/^([a-z]+)(\([^)]*\))?!?:\s/i,IF=new Set(["fix","hotfix","bugfix","revert"]),_F=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),yT=/\bBP-[A-Z]*\d+\b/i,$F=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);RF=[/(^|\/)\.bostrat\//,/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Gemfile\.lock|go\.sum|composer\.lock)$/,/\.min\.(js|css)$/,/\.map$/,/\.snap$/,/(^|\/)(node_modules|dist|build|vendor|\.next|target)\//],OF=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],MF=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];nw=e=>String(e??"").replace(/\s+/g," ").trim(),Td=400;wn=e=>Math.round(e*1e4)/1e4,Qh=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as LF}from"node:child_process";import{promisify as FF}from"node:util";function IT(e,t=Date.now()){return Ff(e,t)??0}function HF(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function _T(e,t,{now:n=Date.now()}={}){let r=IT(t,n),o=await G(e);return _d({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:HF(o,t.name,r)})}function WF(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function qF(e,t,n,r){let o=Array.isArray(t?.epochs)?t.epochs:[],s=r>0?o[r-1]:null,a=s?.endReason?.code??(typeof s?.endReason=="string"?s.endReason:null),i=WF(n,t.name),c=i?ar(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function GF(e,t){try{let{stdout:n}=await aw(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function KF(e){try{let{stdout:t}=await aw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function $T(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await G(e);if(a.some(w=>w.type==="code.committed"&&w.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:w}=await aw(r,["show","-s","--format=%ct",n]),m=Number(w.trim())*1e3;Number.isFinite(m)&&m>0&&(i=m)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=IT(t,i),l=await GF(r,n),u=await KF(r),d=await N(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:u,...l,ts:i}}),p=null,f=!1;try{let w=await AT(r,n,{fixKey:Sa({trackId:e.id,boxId:t.name,epoch:c}),window:lo,context:{...qF(e,t,a,c),ref:u,provider:t.agent??null}});if(w&&(p=await N(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:d.id,payload:w}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&TT(w))){let g=hc(w),y=w.origins.filter(b=>b.class==="rework").slice(0,3);await N(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:{sha:n,subject:w.subject,linesReworked:g,origins:y.map(b=>({key:b.key,provider:b.provider,model:b.model,lines:b.lines,ageDays:b.ageDays})),heuristic:w.heuristic,intent:w.intent,ts:i}}),f=!0}}catch(w){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${w?.message||w}`)}return{recorded:!0,event:d,rework:p,offered:f}}function RT(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function OT(e,t,n){if(!mc.includes(n)&&n!==Id)throw new Error(`bad cause "${n}" (${mc.join("|")}|${Id})`);let r=await G(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(RT(r,t))throw new Error("already answered");return N(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function MT(e,t){let n=await G(e);if(!RT(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return N(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function Od(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await G(e);if(c.some(b=>b.type==="rework.cause.offered"&&b.payload?.pr?.number===n&&(t==null||b.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let b of c)if(b.type==="rework.cause.offered")for(let k of Array.isArray(b.payload?.shas)?b.payload.shas:[b.payload?.sha])k&&l.add(k);let u=new Map;for(let b of c)b.type==="code.committed"&&b.payload?.sha&&u.set(b.payload.sha,b.payload.ref??null);let d=sw({heuristic:$d({subject:r}),subject:r,ref:o}),p=[];for(let b of c){if(b.type!=="code.rework")continue;let k=b.payload||{};if(!k.sha||l.has(k.sha)||k.codeDelta===!1||o&&u.has(k.sha)&&u.get(k.sha)!==o)continue;let S=k.intent?.intent??"unknown";(Aa.has(S)||S==="unknown"&&Aa.has(d.intent))&&hc(k)!==0&&p.push(k)}let f=p.reduce((b,k)=>b+hc(k),0);if(f<ow)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let b of p)for(let k of b.origins??[]){if(k.class!=="rework")continue;let S=w.get(k.key)??{key:k.key,provider:k.provider??null,model:k.model??null,lines:0,ageDays:k.ageDays};S.lines+=k.lines,S.ageDays=Math.min(S.ageDays,k.ageDays),w.set(k.key,S)}let m=p.map(b=>b.sha),g=p.map(b=>b.heuristic).find(b=>b&&b.level!=="C")??$d({subject:r})??p.map(b=>b.heuristic).find(Boolean)??null,y=Aa.has(d.intent)?d:p.find(b=>Aa.has(b.intent?.intent))?.intent??d;return await N(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:m[m.length-1],shas:m,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((b,k)=>k.lines-b.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:m}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var UF,aw,Md=q(()=>{ye();Iu();Rd();UF=FF(LF),aw=(e,t)=>UF("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as VF}from"node:child_process";import{promisify as zF}from"node:util";async function iw(e,t,{midTurn:n=is,pollMs:r=JF,capMs:o=YF}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function jT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){CT.lastIndex=n;let o=CT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
|
|
194
|
+
`)}}async function AT(e,t,{fixKey:n=null,window:r=lo,resolveOrigin:o=null,context:s={}}={}){let a=await bT(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=wT(a.message),l=n?Ed(n):c.epoch,u=l?Sa(l):null,{stdout:d}=await tw(e,["diff","-U0","--no-color","-M","-C",i,t]),p=NF(d),f=0,w=0,m=0,g=0,y=0,b=0,k=0,S=new Map;for(let I of p){if(I.binary)continue;let j=I.oldPath||I.newPath||"",K=I.deleted.reduce((W,[,Y])=>W+Y,0),R=CF(j);if(R==="excluded"){m+=K;continue}if(R==="docs"){g+=K,y+=I.added;continue}if(R==="config"){b+=K;continue}f+=I.added;let E=new Set;for(let W of I.hunks||[])for(let Y of DF(W))E.add(Y);k+=E.size;let C=[];for(let[W,Y]of I.deleted)for(let me=W;me<W+Y;me++)E.has(me)||C.push(me);if(w+=C.length,!I.oldPath||!C.length)continue;let P;try{let W=["blame","-w","-M","-C","--line-porcelain"];for(let[Y,me]of BF(C))W.push("-L",`${Y},${Y+me-1}`);W.push(i,"--",I.oldPath),P=jF((await tw(e,W)).stdout)}catch{continue}for(let{sha:W,time:Y}of P.values()){let me=S.get(W)??{lines:0,time:Y};me.lines+=1,S.set(W,me)}}let $=[],M=0,L=new Map;for(let[I,{lines:j,time:K}]of S){let R=L.get(I);if(!R){try{R=await bT(e,I)}catch{R=null}L.set(I,R)}let E=R?wT(R.message):{epoch:null},C=E.epoch,P=E.provider,W=E.model;if(!C&&o){let ne=await o(I,R);ne?.trackId&&ne?.boxId!=null&&(C={trackId:ne.trackId,boxId:ne.boxId,epoch:ne.epoch??0},P=P??ne.provider??null,W=W??ne.model??null)}if(!C){M+=j;continue}let Y=Number.isFinite(K)?K:R?.ts??a.ts,me=Math.max(0,(a.ts-Y)/gF),_e=Sa(C),Pe=_e===u?"self":xF(me,r);$.push({sha:I,key:_e,trackId:C.trackId,boxId:C.boxId,epoch:C.epoch,provider:P??null,model:W??null,lines:j,ageDays:Math.round(me*100)/100,class:Pe,decay:Pe==="rework"?1:Pe==="drift"?Math.round(vF(me,{window:r})*1e3)/1e3:0})}$.sort((I,j)=>j.lines-I.lines);let B=$d({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),A=sw({heuristic:B,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:m,cosmeticDeleted:k,docsDeleted:g,docsAdded:y,configDeleted:b,codeDelta:f+w+k>0,origins:$,unattributedLines:M,ghost:w===0&&f>0,heuristic:B,intent:A}}function TT(e,{minLines:t=ow}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return Aa.has(n)?hc(e)>=t:!1}function hc(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function ew(e){let t=e.genUsd;return{...e,genUsd:wn(t),reworkChargedUsd:wn(e.reworkChargedUsd),reworkPendingUsd:wn(e.reworkPendingUsd),trueUsd:wn(t+e.reworkChargedUsd),multiplier:t>0?wn((t+e.reworkChargedUsd)/t):null}}function ET(e,{window:t=lo,boxMeta:n={}}={}){let r=e||[],o=r.filter(A=>A.type==="cost.recorded"),s=r.filter(A=>A.type==="code.committed"),a=r.filter(A=>A.type==="code.rework"),i=A=>Array.isArray(A?.shas)&&A.shas.length?A.shas:A?.sha?[A.sha]:[],c=new Map,l=new Set;for(let A of r)if(A.type==="rework.cause.offered")for(let I of i(A.payload))l.add(I);else if(A.type==="rework.cause.answered"&&A.payload?.cause)for(let I of i(A.payload))c.set(I,A.payload.cause);else if(A.type==="rework.cause.retracted")for(let I of i(A.payload))c.delete(I);let u={},d=(A,I,j)=>Sa({trackId:A,boxId:I,epoch:j??0}),p=(A,I={})=>{if(!u[A]){let K=Ed(A)||{};u[A]={key:A,...K,provider:null,model:null,...Qh()}}let j=u[A];return I.provider&&!j.provider&&(j.provider=I.provider),I.model&&!j.model&&(j.model=I.model),j};for(let A of o){if(!A.boxId)continue;let I=d(A.trackId,A.boxId,A.epoch),{usd:j,model:K}=Xt(A),R=p(I,{provider:A.provider,model:K!=="unknown"?K:null});R.genUsd+=j}let f=new Map;for(let A of s){let I=`${A.trackId}/${A.boxId}`;(f.get(I)??f.set(I,[]).get(I)).push({...A,ts:A.payload?.ts??A.ts})}for(let A of f.values())A.sort((I,j)=>I.ts-j.ts);let w=(A,I,j,K)=>{let R=f.get(`${A}/${I}`)||[],E=-1/0;for(let W of R)W.ts<K&&(E=W.ts);let C=0,P=0;for(let W of o)W.trackId!==A||W.boxId!==I||(W.epoch??0)===(j??0)&&(W.ts<=E||W.ts>K||(C+=Xt(W).usd,P++));return{usd:C,turns:P,from:Number.isFinite(E)?E:null}},m={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},b=0,k=[],S=[],$={},M={},L=new Set;for(let A of a){let I=A.payload||{};if(!I.sha||L.has(I.sha))continue;if(L.add(I.sha),I.codeDelta===!1){b++;continue}let j=Ed(I.fixKey)||{trackId:A.trackId,boxId:A.boxId,epoch:A.epoch??0},{usd:K,turns:R}=w(j.trackId,j.boxId,j.epoch,I.ts??A.ts),E=bF.includes(I.intent?.intent)?I.intent.intent:"unknown";y[E]+=1;let C=null;c.has(I.sha)?C={cause:c.get(I.sha),level:"B",basis:"operator"}:(I.heuristic?.level&&I.heuristic.level!=="C"||I.heuristic)&&(C=I.heuristic);let P=C?.level??"none";g[P]=(g[P]||0)+1;let W=yF.has(P),Y=Number(I.deleted)||0,me=Array.isArray(I.origins)?I.origins:[],_e=me.filter(ne=>ne.class==="rework").reduce((ne,Ve)=>ne+Ve.lines,0),Pe={sha:I.sha,subject:I.subject??"",ts:I.ts??A.ts,trackId:A.trackId,fixKey:I.fixKey??null,fixProvider:I.fixProvider??A.provider??null,fixUsd:wn(K),fixTurns:R,linesReworked:_e,unattributedLines:Number(I.unattributedLines)||0,ghost:I.ghost===!0,intent:{intent:E,basis:I.intent?.basis??null},verdict:C?{cause:C.cause,level:P,basis:C.basis??null}:null,charged:wn(0),origins:[]};if(E==="planned"||C?.cause===Id){m.planned+=K;for(let ne of me)ne.class==="rework"&&Pe.origins.push({key:ne.key,provider:ne.provider??null,model:ne.model??null,lines:ne.lines,ageDays:ne.ageDays,class:ne.class,usd:0})}else if(I.ghost||Y===0)m.ghost+=K;else{let ne=0;for(let ve of me){let ce=ve.lines/Y,re=K*ce;if(ne+=re,ve.class==="self"){m.self+=re;continue}let Ce=ve.class==="rework"?1:Number(ve.decay)||0,J=re*Ce;if(m.decayed+=re-J,J<=0)continue;let he=p(ve.key,{provider:ve.provider,model:ve.model});he.fixes+=1,he.linesReworked+=ve.class==="rework"?ve.lines:0;let Fe=C?.cause&&mc.includes(C.cause)?C.cause:"unclassified";he.causes[Fe]+=1,W?(he.reworkChargedUsd+=J,m.charged+=J,Pe.charged=wn(Pe.charged+J)):(he.reworkPendingUsd+=J,m.pending+=J),Pe.origins.push({key:ve.key,provider:he.provider,model:he.model,lines:ve.lines,ageDays:ve.ageDays,class:ve.class,usd:wn(J)})}let Ve=Math.max(0,K-ne);m.unattributed+=Ve}k.push(Pe),!c.has(I.sha)&&l.has(I.sha)&&S.push(I.sha)}for(let A of Object.values(u)){let I=A.provider||"unknown",j=A.model||"unknown",K=R=>{R.genUsd+=A.genUsd,R.reworkChargedUsd+=A.reworkChargedUsd,R.reworkPendingUsd+=A.reworkPendingUsd,R.linesReworked+=A.linesReworked,R.fixes+=A.fixes;for(let E of Object.keys(R.causes))R.causes[E]+=A.causes[E]};K($[I]||=Qh()),K(M[j]||=Qh())}k.sort((A,I)=>I.ts-A.ts);let B=Object.values(u).map(A=>{let I=n[`${A.trackId}/${A.boxId}`]||{};return ew({...A,trackName:I.trackName??null,label:I.label??null})}).sort((A,I)=>I.reworkChargedUsd+I.reworkPendingUsd-(A.reworkChargedUsd+A.reworkPendingUsd)||I.genUsd-A.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${ST} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:b,byEpoch:Object.fromEntries(B.map(A=>[A.key,A])),epochs:B,byProvider:Object.fromEntries(Object.entries($).map(([A,I])=>[A,ew(I)])),byModel:Object.fromEntries(Object.entries(M).map(([A,I])=>[A,ew(I)])),buckets:Object.fromEntries(Object.entries(m).map(([A,I])=>[A,wn(I)])),fixUsdTotal:wn(Object.values(m).reduce((A,I)=>A+I,0)),fixes:k,verdicts:g,pendingTaps:S,commits:s.length}}var hF,wF,tw,kT,xT,vT,gF,lo,rw,ow,mc,Id,yF,bF,Aa,ST,kF,SF,gT,AF,TF,EF,IF,_F,yT,$F,RF,OF,MF,nw,Td,wn,Qh,Rd=q(()=>{Yr();hF=mF(fF),wF=64*1024*1024,tw=(e,t)=>hF("git",["-C",e,...t],{maxBuffer:wF,timeout:6e4}),kT="Bostrat-Epoch",xT="Bostrat-Model",vT="Bostrat-Fix-Cause",gF=24*36e5,lo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,rw=90,ow=3,mc=Object.freeze(["defect","design","requirements","style"]),Id="not-a-fix",yF=new Set(["A","B","E"]),bF=Object.freeze(["fix","likely-fix","planned","unknown"]),Aa=new Set(["fix","likely-fix"]),ST=.8;kF={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};SF=/^revert\b|^revert "/i,gT=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,AF=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,TF=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;EF=/^([a-z]+)(\([^)]*\))?!?:\s/i,IF=new Set(["fix","hotfix","bugfix","revert"]),_F=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),yT=/\bBP-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/i,$F=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);RF=[/(^|\/)\.bostrat\//,/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Gemfile\.lock|go\.sum|composer\.lock)$/,/\.min\.(js|css)$/,/\.map$/,/\.snap$/,/(^|\/)(node_modules|dist|build|vendor|\.next|target)\//],OF=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],MF=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];nw=e=>String(e??"").replace(/\s+/g," ").trim(),Td=400;wn=e=>Math.round(e*1e4)/1e4,Qh=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as LF}from"node:child_process";import{promisify as FF}from"node:util";function IT(e,t=Date.now()){return Ff(e,t)??0}function HF(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function _T(e,t,{now:n=Date.now()}={}){let r=IT(t,n),o=await G(e);return _d({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:HF(o,t.name,r)})}function WF(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function qF(e,t,n,r){let o=Array.isArray(t?.epochs)?t.epochs:[],s=r>0?o[r-1]:null,a=s?.endReason?.code??(typeof s?.endReason=="string"?s.endReason:null),i=WF(n,t.name),c=i?ar(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function GF(e,t){try{let{stdout:n}=await aw(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function KF(e){try{let{stdout:t}=await aw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function $T(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await G(e);if(a.some(m=>m.type==="code.committed"&&m.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s,c=null;try{let{stdout:m}=await aw(r,["show","-s","--format=%ct%n%s",n]),[g,...y]=m.split(`
|
|
195
|
+
`),b=Number(g.trim())*1e3;Number.isFinite(b)&&b>0&&(i=b),c=y.join(`
|
|
196
|
+
`).trim().slice(0,300)||null}catch{return{recorded:!1,reason:"unknown-sha"}}let l=IT(t,i),u=await GF(r,n),d=await KF(r),p=await N(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:d,subject:c,...u,ts:i}}),f=null,w=!1;try{let m=await AT(r,n,{fixKey:Sa({trackId:e.id,boxId:t.name,epoch:l}),window:lo,context:{...qF(e,t,a,l),ref:d,provider:t.agent??null}});if(m&&(f=await N(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:m}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&TT(m))){let y=hc(m),b=m.origins.filter(k=>k.class==="rework").slice(0,3);await N(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:f.id,payload:{sha:n,subject:m.subject,linesReworked:y,origins:b.map(k=>({key:k.key,provider:k.provider,model:k.model,lines:k.lines,ageDays:k.ageDays})),heuristic:m.heuristic,intent:m.intent,ts:i}}),w=!0}}catch(m){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${m?.message||m}`)}return{recorded:!0,event:p,rework:f,offered:w}}function RT(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function OT(e,t,n){if(!mc.includes(n)&&n!==Id)throw new Error(`bad cause "${n}" (${mc.join("|")}|${Id})`);let r=await G(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(RT(r,t))throw new Error("already answered");return N(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function MT(e,t){let n=await G(e);if(!RT(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return N(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function Od(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await G(e);if(c.some(b=>b.type==="rework.cause.offered"&&b.payload?.pr?.number===n&&(t==null||b.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let b of c)if(b.type==="rework.cause.offered")for(let k of Array.isArray(b.payload?.shas)?b.payload.shas:[b.payload?.sha])k&&l.add(k);let u=new Map;for(let b of c)b.type==="code.committed"&&b.payload?.sha&&u.set(b.payload.sha,b.payload.ref??null);let d=sw({heuristic:$d({subject:r}),subject:r,ref:o}),p=[];for(let b of c){if(b.type!=="code.rework")continue;let k=b.payload||{};if(!k.sha||l.has(k.sha)||k.codeDelta===!1||o&&u.has(k.sha)&&u.get(k.sha)!==o)continue;let S=k.intent?.intent??"unknown";(Aa.has(S)||S==="unknown"&&Aa.has(d.intent))&&hc(k)!==0&&p.push(k)}let f=p.reduce((b,k)=>b+hc(k),0);if(f<ow)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let b of p)for(let k of b.origins??[]){if(k.class!=="rework")continue;let S=w.get(k.key)??{key:k.key,provider:k.provider??null,model:k.model??null,lines:0,ageDays:k.ageDays};S.lines+=k.lines,S.ageDays=Math.min(S.ageDays,k.ageDays),w.set(k.key,S)}let m=p.map(b=>b.sha),g=p.map(b=>b.heuristic).find(b=>b&&b.level!=="C")??$d({subject:r})??p.map(b=>b.heuristic).find(Boolean)??null,y=Aa.has(d.intent)?d:p.find(b=>Aa.has(b.intent?.intent))?.intent??d;return await N(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:m[m.length-1],shas:m,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((b,k)=>k.lines-b.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:m}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var UF,aw,Md=q(()=>{ye();Iu();Rd();UF=FF(LF),aw=(e,t)=>UF("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as VF}from"node:child_process";import{promisify as zF}from"node:util";async function iw(e,t,{midTurn:n=is,pollMs:r=JF,capMs:o=YF}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function jT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){CT.lastIndex=n;let o=CT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
|
|
195
197
|
`,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+rU(a)+"[ \\t]*$","m").exec(t.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;t=t.slice(0,i)+t.slice(u)}return t}function cw(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function FT(e){let t=jT(e),n=t.match(eU);if(!n)return null;let r=cw(t,n.index);return nU.test(r)?null:{repo:r.match(LT)?.[1]??null,head:r.match(oU)?.[1]??null}}function UT(e){let t=jT(e),n=t.match(tU);if(!n)return null;let r=cw(t,n.index),o=cw(t,n.index+n[0].length),s=null,a=o.trim().split(/\s+/).filter(Boolean);for(let i=0;i<a.length;i++){let c=a[i];if(c.startsWith("-")){aU.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(LT)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function cU(e,t,{exclude:n=()=>!1}={}){let r=async i=>{pr("observer");let{stdout:c}=await NT("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",iU],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw ao(l)&&io(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-XF&&!n(c)),s=await _n({slug:e}),a=o(await r(s));return!a.length&&s.GH_TOKEN&&(a=o(await r({}).catch(()=>[]))),a.sort((i,c)=>Date.parse(c.createdAt)-Date.parse(i.createdAt))}async function lU(e,t){if(t)return[t];let n=[];for(let r of HT(e)){let o=await Oe(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await nr().catch(()=>[])){let o=await Oe(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function HT(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function uU(e,t,n){let r=await va(e).catch(()=>[e.workspace?.branch].filter(Boolean)),o=t?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||sU(c.headRefName,e.id),i=[];for(let c of await lU(e,t?.repo??null)){let l;try{l=await cU(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await pt(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===e.id&&d.announced)return{settled:!0};if(d&&d.trackId!==e.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==e.id||d.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function WT(e){if(!e)return 0;let t=0;for(let n of mr)n.startsWith(`${e}|`)&&t++;return t}function qT(){for(let e of[...lw])e()}function GT(e,t,{delays:n=PT,turnEnd:r}={}){let o=FT(t.command);if(!o)return null;let s=!!UT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(mr.has(a))return null;mr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(m=>{let g=()=>{clearTimeout(y),lw.delete(g),m()},y=setTimeout(g,l);lw.add(g)});let u=await uU(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Ut({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!w&&!(f?.trackId===e.id&&await ur(d,p.number))?null:(await iw(t.box,t.agent,r),await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),p)}return null}finally{mr.delete(a)}})();return c.catch(()=>mr.delete(a)),c}function KT(e,t,{delays:n=PT,turnEnd:r,openedWait:o}={}){let s=UT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(mr.has(a))return null;mr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let d=[];if(c)d=[c];else{let w=HT(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let m of w){let g=await Oe(m).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await va(e).catch(()=>[])).filter(w=>w!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(w,m)=>{let g=await pt(c,w.number);return g&&g.trackId!==e.id?null:(g||await Ut({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await sc(c,w.number),m&&((await G(e).catch(()=>[])).some(k=>k.type==="pr.state.changed"&&(k.payload?.change==="auto-armed"||k.payload?.change==="merged")&&k.payload?.number===w.number)||(await iw(t.box,t.agent,r),await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:w.number,url:w.url,title:w.title,branch:w.headRefName,repo:c}}))),w)},f=null;for(let w of n){await new Promise(M=>setTimeout(M,w));let m=[];for(let M of d)try{pr("observer");let{stdout:L}=await NT("gh",["pr","view",String(l),"--repo",M,"--json",dU],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await _n({slug:M})}}),B=JSON.parse(L||"null");B?.number&&m.push({slug:M,pr:B})}catch(L){ao(L)&&io(L)}let g=m.find(M=>M.pr.state==="MERGED")??(m.length===1?m[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(f=y,s.auto)return p(y,!0);continue}let b=await pt(c,y.number);if(b&&b.trackId!==e.id)return null;b||await Ut({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await iw(t.box,t.agent,r);let k=await G(e).catch(()=>[]);if(k.some(M=>M.type==="pr.state.changed"&&M.payload?.change==="merged"&&M.payload?.number===y.number))return null;let S=M=>M.some(L=>L.type==="pr.state.changed"&&L.payload?.change==="opened"&&L.payload?.number===y.number),$=0;if(!S(k)){if(FT(t.command)&&await ur(c,y.number)){let M=Date.now();$=M+1,await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:M,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await pt(c,y.number))?.announced){let M=o?.capMs??ZF,L=o?.pollMs??QF,B=Date.now()+M;for(;Date.now()<B&&(await new Promise(A=>setTimeout(A,L)),!S(await G(e).catch(()=>[]))););}}return await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),$),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await Od(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await wr(c,y.number).catch(()=>{}),await hr(c,y.number).catch(()=>{}),await oo(c,y.number,"merged"),y}return f?p(f,!1):null}finally{mr.delete(a)}})();return i.catch(()=>mr.delete(a)),i}var NT,PT,JF,YF,XF,ZF,QF,DT,BT,eU,tU,nU,CT,rU,LT,oU,sU,aU,iU,mr,lw,dU,Cd=q(()=>{ye();Pr();yt();ic();jn();gr();fc();cs();Md();NT=zF(VF),PT=[4e3,15e3,45e3],JF=2500,YF=5*6e4;XF=15e3,ZF=9e4,QF=2e3,DT=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,BT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,eU=new RegExp(`${DT}${BT}create\\b`),tU=new RegExp(`${DT}${BT}merge\\b`),nU=/\s--web\b/,CT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,rU=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");LT=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,oU=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,sU=hT;aU=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);iU="number,url,title,headRefName,createdAt";mr=new Set;lw=new Set;dU="number,url,title,headRefName,state"});import pU from"node:fs/promises";import dw from"node:path";import fU from"node:os";function uw(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function Nd(e){let t=mU.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=uw(n,"from"),s=o?o.replace(/^uds:/,""):null,a=VT(s);return{socket:s,pid:a,name:uw(n,"from-name"),mode:uw(n,"from-mode"),text:r.trim()}}function VT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function hU(){return process.env.CLAUDE_CONFIG_DIR?dw.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):dw.join(fU.homedir(),".claude","sessions")}async function wU(e){let t=VT(e);if(!t)return null;try{let n=await pU.readFile(dw.join(hU(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function zT(e,t){let n=await wU(e?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof t=="function")try{o=await t(n?.sessionId??null,r)??null}catch{o=null}return{socket:e?.socket??null,pid:n?.pid??e?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??e?.name??null,mode:e?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var mU,pw=q(()=>{mU=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function JT(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}async function YT(e,t,n=fw){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await yU(`${Ne(t)}${e}`,{headers:bU(t),signal:r.signal})}finally{clearTimeout(o)}}async function wc({env:e=process.env,force:t=!1,timeoutMs:n=fw}={}){if(!JT(e))return{followups:[],source:"unconfigured"};if(!t&&ls&&Date.now()-ls.at<gU)return{followups:ls.followups,source:"cache"};try{let r=await YT("/v1/followups?deleted=1",e,n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.followups)?o.followups:[];return ls={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return ls?{followups:ls.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function XT(e,{env:t=process.env,timeoutMs:n=fw}={}){if(!e)return{followup:null,source:"unconfigured"};if(!JT(t))return{followup:null,source:"unconfigured"};try{let r=await YT(`/v1/followups/${encodeURIComponent(e)}`,t,n);if(r.status===404)return{followup:null,source:"gone"};if(!r.ok)throw new Error(`plane ${r.status}`);return{followup:(await r.json())?.followup??null,source:"plane"}}catch(r){let o=ls?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var gU,fw,ls,yU,bU,ZT=q(()=>{yt();gU=6e4,fw=5e3,ls=null,yU=(...e)=>fetch(...e);bU=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function uo(e,t){if(mw.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}mw.add(e);try{return await t()}finally{mw.delete(e)}}var mw,gc=q(()=>{mw=new Set});import{randomUUID as us,createHash as kU}from"node:crypto";function Pd(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function iE(e){for(let[t,n]of AU)if(t.test(String(e||"")))return`a standing prompt must not embed this Track's specifics (${n}) \u2014 the card supplies them at fire time; arm a one-shot with \`offer\` instead`;return null}function nE(e,{at:t="",promptRequired:n=!0,standing:r=!1}={}){let o=e&&typeof e=="object"?e:{},s=ds(o.label).replace(/\s+/g," ");if(!s)throw new Error(`${t}label required (\u2264${hw} chars, e.g. "Deploy to Pi")`);if(s.length>hw)throw new Error(`${t}label must be \u2264${hw} characters`);let a=ds(o.prompt);if(n&&!a)throw new Error(`${t}prompt required \u2014 the full instruction a fresh session could execute`);if(Buffer.byteLength(a,"utf8")>QT)throw new Error(`${t}prompt must be \u2264${QT} bytes`);if(r){let l=iE(a);if(l)throw new Error(`${t}${l}`)}let i=o.standing==null||o.standing===""?"offerable":String(o.standing).trim().toLowerCase();if(!SU.includes(i))throw new Error(`${t}standing must be "offerable" or "never", got "${o.standing}"`);let c=ds(o.why).slice(0,oE)||null;return{label:s,prompt:a,why:c,standing:i}}function cE(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=ds(n.trigger)||(n.ship?"now":""),o=t?xU:sE.filter(p=>p!=="track.opened");if(!o.includes(r))throw new Error(`trigger must be one of ${o.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let s=n.ship&&r==="now"?IU(n.ship):null,a=n.items!=null;if(a&&s)throw new Error("a ship offer has its own card \u2014 `items` cannot be combined with a `ship` block");let i,c=null;if(a){if(!Array.isArray(n.items)||!n.items.length)throw new Error("items must be a non-empty array of {label, prompt, why?, standing?}");if(n.items.length>tE)throw new Error(`items must be \u2264${tE} \u2014 one item per step the operator might run, save or skip separately`);if(t&&n.items.length>1)throw new Error("propose one standing follow-up at a time \u2014 a standing follow-up is one prompt");i=n.items.map((f,w)=>nE(f,{at:`items[${w}]: `,standing:t})),c=ds(n.why).slice(0,oE)||null;let p=new Set;for(let f of i){let w=Pd(f.label);if(p.has(w))throw new Error(`items must have distinct labels ("${f.label}" appears twice)`);p.add(w)}}else i=[nE(n,{promptRequired:!s,standing:t})];let l=i[0],u=c??l.why,d=t?EU(n.repo):null;return{label:l.label,prompt:l.prompt,trigger:r,why:u,planWhy:c,items:i,...d?{repo:d}:{},...s?{ship:s}:{}}}function TU(e){return e.standing==="never"?{promotable:!1,promotableReason:"one-off"}:iE(e.prompt)?{promotable:!1,promotableReason:"specifics"}:{promotable:!0,promotableReason:null}}function EU(e){if(e==null||e===""||e==="*")return null;let t=String(e).trim();if(!/^[\w.-]+\/[\w.-]+$/.test(t))throw new Error(`repo must be a forge slug like owner/name, got "${e}"`);return t}function IU(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):ww.slice();for(let i of n)if(!ww.includes(i))throw new Error(`ship.actions may only contain ${ww.join(" | ")}, got "${i}"`);if(!n.length)throw new Error("ship.actions must name at least one of commit | push | pr");let r=t.rebase==null?"none":String(t.rebase).trim();if(!["offered","none"].includes(r))throw new Error(`ship.rebase must be "offered" or "none", got "${t.rebase}"`);let o=null;if(t.toPr!=null&&t.toPr!==""){let i=Number(t.toPr);if(!Number.isInteger(i)||i<=0)throw new Error(`ship.toPr must be a PR number, got "${t.toPr}"`);o=i}let s=ds(t.base)||null,a=null;if(t.repos!=null){if(!Array.isArray(t.repos))throw new Error("ship.repos must be an array of checkout names");a=t.repos.map(i=>ds(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function Dd(e,{trigger:t=null}={}){let n=new Map;for(let r of e){let o=r.payload||{};if(r.type==="followup.armed"&&o.armId)o.replaces&&n.delete(o.replaces),n.set(o.armId,{...o,ts:o.ts??r.ts,boxId:r.boxId??null,provider:r.provider??null});else if(r.type==="followup.armed.cancelled"&&o.armId)n.delete(o.armId);else if(r.type==="followup.offered")for(let s of o.rows||[])s.armId&&n.delete(s.armId)}return[...n.values()].filter(r=>!t||r.trigger===t)}function lE(e){return{armId:e.armId,label:e.label,prompt:e.prompt,promptHash:aE(e.prompt),origin:"agent",why:e.why??null,groupId:e.groupId??null,seq:Number.isInteger(e.seq)?e.seq:0,standing:e.standing==="never"?"never":"offerable",...TU(e)}}async function uE(e,t,{pull:n=wc,ship:r={}}={}){if(yw(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead");let o=cE(t);if(o.ship)return{kind:"ship",...await MU(e,o,r)};let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(b=>b.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null},c=us(),l=(b,k,S={})=>({ts:Date.now(),armId:us(),trigger:o.trigger,label:b.label,prompt:b.prompt,why:b.why,standing:b.standing,groupId:c,seq:k,...o.planWhy?{planWhy:o.planWhy}:{},...S}),u={groupId:c,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,planWhy:o.planWhy};if(o.trigger==="now"){let b=us(),k=[];for(let[S,$]of o.items.entries()){let M=l($,S);await N(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:M}),k.push(M)}return await N(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:b,trigger:"now",repo:e.workspace?.repo||null,context:{},groupId:c,why:o.planWhy,rows:k.map(lE)}}),{kind:"now",offerId:b,armId:k[0].armId,items:k.map(S=>({armId:S.armId,label:S.label,standing:S.standing})),...u}}let d=e.workspace?.repo||null,{followups:p}=await n().catch(()=>({followups:[]})),f=await G(s),w=Dd(f,{trigger:o.trigger}),m=[],g=0;for(let b of o.items){let k=Pd(b.label),S=p.find(B=>B.status==="active"&&B.mode!=="off"&&B.trigger===o.trigger&&(B.repo==null||B.repo===d)&&B.dedupeKey===k);if(S){m.push({label:b.label,standing:b.standing,covered:{id:S.id,label:S.label}});continue}let $=w.filter(B=>Pd(B.label)===k),M=$.length?$[$.length-1].armId:null,L=l(b,g++,M?{replaces:M}:{});await N(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:L}),m.push({armId:L.armId,label:b.label,standing:b.standing,replaces:M})}let y=m.filter(b=>b.armId);return y.length?{kind:"armed",armId:y[0].armId,replaces:y[0].replaces,items:m,...u}:{kind:"covered",covered:m[0].covered,items:m,...u}}async function dE(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await G(n);if(!Dd(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await N(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function pE(e,t,{pull:n=wc}={}){if(yw(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=cE(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await G(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=Pd(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),f=d.find(g=>g.status!=="deleted");if(f)throw new Error(`"${f.label}" (${gw[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let w=us(),m=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await N(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:m?.agent??null,payload:{ts:Date.now(),proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function fE(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await G(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await N(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("followupId required \u2014 the follow-up is created on the plane before the card is answered");let i=a.payload;return await N(o,{type:"followup.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,followupId:String(r),label:i.label,trigger:i.trigger,repo:i.repo??null}}),await N(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",followupId:String(r)}}),{proposalId:t,action:"created",followupId:String(r)}}async function yc(e,t,n={},{pull:r=wc}={}){if(!e||yw(e))return null;let o={id:e.id,cwd:e.cwd},s=await G(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let y=S=>{let $=(S?.prs||[]).filter(M=>Number.isFinite(Number(M?.number))).map(M=>`${M?.repo??S?.repo??""}#${Number(M.number)}`);return Number.isFinite(Number(S?.prNumber))&&$.push(`${S?.repo??""}#${Number(S.prNumber)}`),$},b=new Set(y(n));if(s.some(S=>S.type==="followup.offered"&&S.payload?.trigger==="pr.merged"&&y(S.payload?.context).some($=>b.has($))))return null}let i=Dd(s,{trigger:t}),c=i.length?i[i.length-1].groupId??null:null,l=new Map(i.map((y,b)=>[y.armId,b])),u=y=>y.groupId&&y.groupId===c?0:1,d=i.slice().sort((y,b)=>u(y)-u(b)||l.get(y.armId)-l.get(b.armId)).slice(0,eE).map(lE),p=c?i.find(y=>y.groupId===c&&y.planWhy)?.planWhy??null:null,f=[];if(t!=="now"){let{followups:y}=await r().catch(()=>({followups:[]}));f=y.filter(b=>b.status==="active"&&b.mode!=="off"&&b.trigger===t&&(b.repo==null||b.repo===a)).sort((b,k)=>{let S=$=>$.stats?.offered?($.stats.accepted||0)/$.stats.offered:0;return S(k)-S(b)||(b.origin==="operator"?-1:0)-(k.origin==="operator"?-1:0)||(k.createdAt||0)-(b.createdAt||0)}).slice(0,vU).map(b=>({followupId:b.id,label:b.label,promptPreview:_U(b.prompt),promptHash:aE(b.prompt),origin:b.origin,repo:b.repo??null}))}let w=[...d,...f].slice(0,eE);if(!w.length)return null;let m=us(),g={ts:Date.now(),offerId:m,trigger:t,repo:a,context:{...n,repo:a},groupId:c,why:p,rows:w};return await N(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:g}),g}function $U(e,t){let n=t?.rows||[],r=a=>a.armId?`arm:${a.armId}`:`fu:${a.followupId}`,o=new Map(n.map(a=>[r(a),null])),s=(a,i)=>{o.has(a)&&o.get(a)==null&&o.set(a,i)};for(let a of e){if(a.type!=="followup.answered"||a.payload?.offerId!==t.offerId)continue;let i=a.payload,c=[];i.armId&&c.push(`arm:${i.armId}`),i.followupId&&c.push(`fu:${i.followupId}`);for(let l of Array.isArray(i.armIds)?i.armIds:[])c.push(`arm:${l}`);for(let l of Array.isArray(i.followupIds)?i.followupIds:[])c.push(`fu:${l}`);if(c.length)for(let l of c)s(l,i.action);else for(let l of o.keys())s(l,i.action)}return o}function rE(e){let t=e?.context||{},n=Array.isArray(t.prs)&&t.prs.length?t.prs:t.prNumber?[{number:t.prNumber,title:t.prTitle,url:t.prUrl,repo:t.repo}]:[],r=o=>`PR #${o.number}${o.title?` "${o.title}"`:""}${o.url?` (${o.url})`:""}${o.repo?` on ${o.repo}`:""}`;switch(e?.trigger){case"pr.merged":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} merged:`:"Follow-up the operator tapped after this Track's PR merged:";case"pr.opened":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} opened:`:"Follow-up the operator tapped after this Track's PR opened:";case"checks.green":return n.length?`Follow-up the operator tapped after CI went green on ${n.map(r).join(" and ")}:`:"Follow-up the operator tapped after CI went green:";case"ship.done":return"Follow-up the operator tapped after the ship you just ran completed:";default:return"Follow-up the operator tapped:"}}async function mE(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null,all:s=!1}={},a={}){if(!t)throw new Error("offerId required");return uo(`fu:${e.id}:${t}`,()=>OU(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s===!0},a))}async function OU(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s},a){let{sayToLead:i,unarchiveTrack:c,getFollowup:l=XT}=a,u={id:e.id,cwd:e.cwd},d=await G(u),p=d.find(A=>A.type==="followup.offered"&&A.payload?.offerId===t);if(!p)throw new Error("unknown offer");let f=p.payload.rows||[],w=$U(d,p.payload),m=RU(w,f);if(!m.length)throw new Error("offer already answered");let g=A=>N(u,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...A}}),y=async()=>{if(!e.archivedAt)return!1;if(!c)throw new Error("this Track is archived");return await c(e.id,{freshSession:!0}),e={...e,archivedAt:null},!0},b=A=>{let j=d.find(K=>K.type==="followup.armed"&&K.payload?.armId===A.armId)?.payload?.prompt??A.prompt;if(!j)throw new Error("the arm's prompt is missing from the log");return j};if(s){let A=p.payload.groupId??null,I=m.filter(W=>W.armId&&(!A||W.groupId===A)).sort((W,Y)=>(W.seq??0)-(Y.seq??0));if(!I.length)throw new Error("nothing to run together \u2014 no open items from this plan remain on the card");let j=I.map(W=>({row:W,prompt:b(W)})),K=await y();if(!i)throw new Error("sayToLead unavailable");let R=`${rE(p.payload).replace(/:$/,"")} \u2014 ${j.length} steps, in order:`,E=j.map((W,Y)=>`${Y+1}. ${W.row.label}
|
|
196
198
|
${W.prompt}`).join(`
|
|
197
199
|
|
|
@@ -447,8 +449,11 @@ markdown file and publish it with:
|
|
|
447
449
|
Structure it for tracking: optional \`name:\` frontmatter, then \`## Requirements\`
|
|
448
450
|
/ \`## Design\` / \`## Implementation\` sections whose checklist lines carry stable
|
|
449
451
|
\`[BP-*]\` id markers (e.g. \`- [ ] [BP-R1] Guests can check out\`). MINT EACH ID
|
|
450
|
-
ONCE AND NEVER RENUMBER OR REUSE IT \u2014 PR titles/branches
|
|
451
|
-
|
|
452
|
+
ONCE AND NEVER RENUMBER OR REUSE IT \u2014 PR titles/branches/commit subjects
|
|
453
|
+
mentioning an id associate the work as evidence (chips + cost) and cost
|
|
454
|
+
attribution keys on it; the doc's own checkbox is the completion state, so
|
|
455
|
+
tick \`[x]\` and prefix the item with a status note \`*(done 2026-08-20, PR #606 \u2014 \u2026)*\`
|
|
456
|
+
when it lands. On feedback revise the
|
|
452
457
|
SAME document and run \`bostrat-blueprint update <file.md>\` (declarative: send
|
|
453
458
|
the full new doc; each publish is a version) \u2014 never a near-duplicate. A circuit
|
|
454
459
|
has at most ONE blueprint. \`bostrat-blueprint show\` prints items + the
|
package/package.json
CHANGED