bostrat-node 1.8.6 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/index.js +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -112,7 +112,7 @@ Run it? (Y/n)`,"Y")).toLowerCase().startsWith("n"))return n.write(`aborted \u201
|
|
|
112
112
|
redeploy: fly deploy ${D} -c ${he.join(D,"fly.toml")} -a ${f} --ha=false
|
|
113
113
|
Vendor logins (Claude/Codex) are NOT set up here \u2014 you type those later, inside
|
|
114
114
|
boxes, and they land on this machine's volume, never on bostrat (box-auth-policy).
|
|
115
|
-
`),_(0)}var wn,so,St,Ve,Sn=v(()=>{wn="wss://plane.bostrat.ai/v1/node",so=ro(import.meta.url)("../package.json").version,St=`ghcr.io/globocodes/bostrat-node:${so}`;Ve=(e,{stdin:t,exec:n}={})=>new Promise((o,s)=>{if(n)return n(e,{stdin:t}).then(o,s);let c=no("fly",e,{timeout:6e5,maxBuffer:16*1024*1024},(u,p,_)=>u?s(Object.assign(u,{stdout:p,stderr:_})):o({stdout:p,stderr:_}));t!=null&&c.stdin?.end(t)})});function vn(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!lo.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let o=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(o))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return o}function uo(e){let t={};for(let[n,o]of Object.entries(e)){if(!Array.isArray(o)||o.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=o.map(s=>({...s,fromMs:vn(s.from,"from",n),toMs:vn(s.to,"to",n)}))}return t}var co,lo,Ra,Na,kn=v(()=>{co={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:null,input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},lo=/^\d{4}-\d{2}-\d{2}$/;Ra=uo(co),Na=Object.freeze({staleDays:90,leadDays:14,confirmDays:30})});var An=v(()=>{kn()});import $n from"node:fs/promises";import On from"node:path";import fo from"node:os";function Nn(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function In(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function Mn(e){let t=new Date(Nn(e));return t.setDate(t.getDate()+7),t.getTime()}function Pn(e){let t=new Date(In(e));return t.setMonth(t.getMonth()+1),t.getTime()}function yo(e=Date.now()){for(let[t,n]of Object.entries(mo)){let o=n.startOf(e);if(o!==Je[t]){Je[t]=o;for(let s of vt.values())s[t]=0;for(let s of xn)s.includes(`:${t}:`)&&!s.endsWith(`:${o}`)&&xn.delete(s)}}}function go(e){let t={};for(let[n,o]of Object.entries(e||{})){if(typeof n!="string"||!/^[a-z][a-z0-9-]{0,31}$/.test(n))throw new Error(`bad provider key "${n}"`);let s={};for(let c of["weeklyUsd","monthlyUsd"]){let u=o?.[c];if(u==null||u==="")continue;let p=Number(u);if(!Number.isFinite(p)||p<=0)throw new Error(`${n}.${c} must be a positive number or null`);s[c]=p}Object.keys(s).length&&(t[n]=s)}return t}async function Dn(e,{source:t="local",updatedAt:n=Date.now()}={}){ve={caps:go(e),updatedAt:n,source:t};try{await $n.mkdir(Rn,{recursive:!0}),await $n.writeFile(po(),JSON.stringify(ve,null,2))}catch{}return To()}function To(e=Date.now()){yo(e);let t=new Set([...vt.keys(),...Object.keys(ve?.caps||{})]),n={};for(let o of t){let s=vt.get(o);n[o]={weeklyUsd:En(s?.weekly||0),monthlyUsd:En(s?.monthly||0)}}return{caps:ve?.caps||{},configured:!!ve,seeded:wo,updatedAt:ve?.updatedAt??null,spent:n,windows:{weekly:{start:Je.weekly,resetsAt:Mn(e)},monthly:{start:Je.monthly,resetsAt:Pn(e)}},warnPct:ho}}var Rn,po,ho,mo,ve,wo,Je,vt,xn,En,Cn=v(()=>{Ye();An();Rn=process.env.BOSTRAT_STATE_DIR||On.join(process.env.HOME||fo.tmpdir(),".bostrat"),po=()=>On.join(Rn,"usage-caps.json"),ho=.8;mo={weekly:{startOf:Nn,nextStart:Mn,capKey:"weeklyUsd"},monthly:{startOf:In,nextStart:Pn,capKey:"monthlyUsd"}},ve=null,wo=!1,Je={weekly:0,monthly:0},vt=new Map,xn=new Set;En=e=>Math.round(e*1e4)/1e4});var Yn={};ut(Yn,{detectInstallKind:()=>Ae,detectProviderAuth:()=>Wn,startPlaneLink:()=>Mo,updateCommandFor:()=>Fe,versionLt:()=>ke});import Kn from"node:fs";import je from"node:fs/promises";import _o from"node:http";import V from"node:path";import Xe from"node:os";import{createRequire as bo}from"node:module";import kt from"ws";function Ae({env:e=process.env,pkgDir:t=V.resolve(V.dirname(new URL(import.meta.url).pathname),".."),exists:n=Kn.existsSync}={}){let o=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(o)?o:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(V.join(t,"..",".git"))?"git-checkout":"dev"}function ke(e,t){let n=String(e).split(".").map(Number),o=String(t).split(".").map(Number);if(n.some(Number.isNaN)||o.some(Number.isNaN))return!1;for(let s=0;s<Math.max(n.length,o.length);s++){let c=(n[s]||0)-(o[s]||0);if(c)return c<0}return!1}function Fe(e){switch(e){case"npm-global":return"npm install -g bostrat-node && restart the bostrat-node service";case"git-checkout":return"scripts/deploy-pi.sh (or The Bakery \u2192 Deploy to Pi \u2192 bostrat)";case"container":return"Links \u2192 Fly \u2192 Update (or the plane's auto-update while the node sleeps)";default:return"update this node's bostrat-node checkout/install"}}function Wn({home:e=process.env.HOME||Xe.homedir(),env:t=process.env}={}){let n=o=>{try{return Kn.statSync(o),!0}catch{return!1}};return{claude:n(V.join(e,".claude",".credentials.json")),codex:n(V.join(t.CODEX_HOME||V.join(e,".codex"),"auth.json"))}}function Mo({url:e,token:t,nodeId:n=Xe.hostname(),name:o=Xe.hostname(),listTracks:s,detectAgents:c=null,onTracksTransferred:u=null,sampleMetrics:p=null,metricsMs:_=Io,onUpdateAvailable:m=null,onUpdatePolicy:f=null,onHelloRefused:b=null,updatePolicy:x=null,installKind:g=Ae(),selfUrl:k=`http://127.0.0.1:${process.env.PORT||3362}`,onDegraded:A=null,onRecovered:K=null,onConnected:W=null,ingestMode:D=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:C=Eo,unackedRetryMs:T=xo,pingMs:z=$o,maxInflightEvents:we=Ro,httpTimeoutMs:ce=No,stallBackoffMinMs:Le=Oo,fetchImpl:It=globalThis.fetch,log:y=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof s!="function")throw new Error("plane-link: listTracks is required");e=Pe(e);let sr=k.replace(/^http/,"ws"),Mt=new Set,le=new Map,ue=new Map,tt=V.join(jn,"plane-link","cursor.json"),nt=V.join(jn,"plane-link","dead-letter.ndjson"),Pt=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),de={},ne={},$=new Map,Be=null,re=null,Q=0,Ee=0,Dt=0,Ct=Promise.resolve(),O="ws",ye=0,Y=!1,fe=0,rt=!1,B=se,ge=new Set,oe=[],j=null,X=null,q=!1,ot=!1,Oe=Fn,Re=null,Te=null,_e=null,ee=null,te=null,st=!1,Ue=0;async function ir(){try{de=JSON.parse(await je.readFile(tt,"utf8"))}catch{de={}}}function ar(){st=!0,!_e&&(_e=setTimeout(async()=>{if(_e=null,!!st){st=!1;try{await je.mkdir(V.dirname(tt),{recursive:!0}),await je.writeFile(tt,JSON.stringify(de))}catch(a){y.error("[plane-link] cursor flush failed:",a?.message||a)}}},Ao),_e.unref?.())}function N(a){return!X||X.readyState!==kt.OPEN?!1:(X.send(JSON.stringify(a)),!0)}function Ne(a){let l=Date.now();for(let{trackId:r,event:i}of a){let d=$.get(i.id);$.set(i.id,{trackId:r,seq:i.seq,event:i,sentAt:l,firstSentAt:d?.firstSentAt??l,retryAt:l+T,tries:(d?.tries??0)+1,nacks:d?.nacks??0})}return O==="http"?(dr(a),!0):N({v:I,ch:"events",type:"append",events:a})}function cr(a){let l=null;for(let r of $.values())r.trackId===a&&(l==null||r.seq<l)&&(l=r.seq);return l}function it(a){let l=ne[a];if(l==null)return;let r=cr(a),i=r==null?l:Math.min(l,r-1);i>(de[a]??0)&&(de[a]=i,ar())}function Ie(){if(Be=Date.now(),re!=null){let a=Date.now()-re;y.log(`[plane-link] spine sync recovered after ${Math.round(a/1e3)}s degraded (${Q} stall redial(s))`);let l=re;re=null,Q=0,Ee=0,Y=!1,fe=0;try{K?.({since:l,downMs:a})}catch(r){y.error(`[plane-link] onRecovered failed: ${r?.message||r}`)}}}function at(a){if(!Array.isArray(a)||!a.length)return;let l=new Set;for(let r of a){let i=$.get(r);i&&($.delete(r),(ne[i.trackId]??0)<i.seq&&(ne[i.trackId]=i.seq),l.add(i.trackId))}for(let r of l)it(r);Ie()}function jt(a,l){Dt++;let r={at:Date.now(),trackId:a.trackId,seq:a.seq,id:a.event?.id??null,type:a.event?.type??null,reason:l,event:a.event??null};y.error(`[plane-link] DEAD-LETTER ${a.trackId} seq ${a.seq} (${r.type??"?"}): plane rejected it permanently (${l}) \u2014 kept in ${nt}`),Ct=Ct.then(async()=>{await je.mkdir(V.dirname(nt),{recursive:!0}),await je.appendFile(nt,JSON.stringify(r)+`
|
|
115
|
+
`),_(0)}var wn,so,St,Ve,Sn=v(()=>{wn="wss://plane.bostrat.ai/v1/node",so=ro(import.meta.url)("../package.json").version,St=`ghcr.io/globocodes/bostrat-node:${so}`;Ve=(e,{stdin:t,exec:n}={})=>new Promise((o,s)=>{if(n)return n(e,{stdin:t}).then(o,s);let c=no("fly",e,{timeout:6e5,maxBuffer:16*1024*1024},(u,p,_)=>u?s(Object.assign(u,{stdout:p,stderr:_})):o({stdout:p,stderr:_}));t!=null&&c.stdin?.end(t)})});function vn(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!lo.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let o=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(o))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return o}function uo(e){let t={};for(let[n,o]of Object.entries(e)){if(!Array.isArray(o)||o.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=o.map(s=>({...s,fromMs:vn(s.from,"from",n),toMs:vn(s.to,"to",n)}))}return t}var co,lo,Ra,Na,kn=v(()=>{co={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:"2026-08-23",input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL). Superseded 2026-08-24 by the vendor's promotional cut (window below)."},{from:"2026-08-24",to:null,input:4,output:20,cacheWrite:5,cacheRead:.4,verifiedAt:"2026-08-24",note:"promotional pricing verified 2026-08-24 (developers.openai.com pricing), 'at least through November 21, 2026'; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},lo=/^\d{4}-\d{2}-\d{2}$/;Ra=uo(co),Na=Object.freeze({staleDays:90,leadDays:14,confirmDays:30})});var An=v(()=>{kn()});import $n from"node:fs/promises";import On from"node:path";import fo from"node:os";function Nn(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function In(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function Mn(e){let t=new Date(Nn(e));return t.setDate(t.getDate()+7),t.getTime()}function Pn(e){let t=new Date(In(e));return t.setMonth(t.getMonth()+1),t.getTime()}function yo(e=Date.now()){for(let[t,n]of Object.entries(mo)){let o=n.startOf(e);if(o!==Je[t]){Je[t]=o;for(let s of vt.values())s[t]=0;for(let s of xn)s.includes(`:${t}:`)&&!s.endsWith(`:${o}`)&&xn.delete(s)}}}function go(e){let t={};for(let[n,o]of Object.entries(e||{})){if(typeof n!="string"||!/^[a-z][a-z0-9-]{0,31}$/.test(n))throw new Error(`bad provider key "${n}"`);let s={};for(let c of["weeklyUsd","monthlyUsd"]){let u=o?.[c];if(u==null||u==="")continue;let p=Number(u);if(!Number.isFinite(p)||p<=0)throw new Error(`${n}.${c} must be a positive number or null`);s[c]=p}Object.keys(s).length&&(t[n]=s)}return t}async function Dn(e,{source:t="local",updatedAt:n=Date.now()}={}){ve={caps:go(e),updatedAt:n,source:t};try{await $n.mkdir(Rn,{recursive:!0}),await $n.writeFile(po(),JSON.stringify(ve,null,2))}catch{}return To()}function To(e=Date.now()){yo(e);let t=new Set([...vt.keys(),...Object.keys(ve?.caps||{})]),n={};for(let o of t){let s=vt.get(o);n[o]={weeklyUsd:En(s?.weekly||0),monthlyUsd:En(s?.monthly||0)}}return{caps:ve?.caps||{},configured:!!ve,seeded:wo,updatedAt:ve?.updatedAt??null,spent:n,windows:{weekly:{start:Je.weekly,resetsAt:Mn(e)},monthly:{start:Je.monthly,resetsAt:Pn(e)}},warnPct:ho}}var Rn,po,ho,mo,ve,wo,Je,vt,xn,En,Cn=v(()=>{Ye();An();Rn=process.env.BOSTRAT_STATE_DIR||On.join(process.env.HOME||fo.tmpdir(),".bostrat"),po=()=>On.join(Rn,"usage-caps.json"),ho=.8;mo={weekly:{startOf:Nn,nextStart:Mn,capKey:"weeklyUsd"},monthly:{startOf:In,nextStart:Pn,capKey:"monthlyUsd"}},ve=null,wo=!1,Je={weekly:0,monthly:0},vt=new Map,xn=new Set;En=e=>Math.round(e*1e4)/1e4});var Yn={};ut(Yn,{detectInstallKind:()=>Ae,detectProviderAuth:()=>Wn,startPlaneLink:()=>Mo,updateCommandFor:()=>Fe,versionLt:()=>ke});import Kn from"node:fs";import je from"node:fs/promises";import _o from"node:http";import V from"node:path";import Xe from"node:os";import{createRequire as bo}from"node:module";import kt from"ws";function Ae({env:e=process.env,pkgDir:t=V.resolve(V.dirname(new URL(import.meta.url).pathname),".."),exists:n=Kn.existsSync}={}){let o=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(o)?o:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(V.join(t,"..",".git"))?"git-checkout":"dev"}function ke(e,t){let n=String(e).split(".").map(Number),o=String(t).split(".").map(Number);if(n.some(Number.isNaN)||o.some(Number.isNaN))return!1;for(let s=0;s<Math.max(n.length,o.length);s++){let c=(n[s]||0)-(o[s]||0);if(c)return c<0}return!1}function Fe(e){switch(e){case"npm-global":return"npm install -g bostrat-node && restart the bostrat-node service";case"git-checkout":return"scripts/deploy-pi.sh (or The Bakery \u2192 Deploy to Pi \u2192 bostrat)";case"container":return"Links \u2192 Fly \u2192 Update (or the plane's auto-update while the node sleeps)";default:return"update this node's bostrat-node checkout/install"}}function Wn({home:e=process.env.HOME||Xe.homedir(),env:t=process.env}={}){let n=o=>{try{return Kn.statSync(o),!0}catch{return!1}};return{claude:n(V.join(e,".claude",".credentials.json")),codex:n(V.join(t.CODEX_HOME||V.join(e,".codex"),"auth.json"))}}function Mo({url:e,token:t,nodeId:n=Xe.hostname(),name:o=Xe.hostname(),listTracks:s,detectAgents:c=null,onTracksTransferred:u=null,sampleMetrics:p=null,metricsMs:_=Io,onUpdateAvailable:m=null,onUpdatePolicy:f=null,onHelloRefused:b=null,updatePolicy:x=null,installKind:g=Ae(),selfUrl:k=`http://127.0.0.1:${process.env.PORT||3362}`,onDegraded:A=null,onRecovered:K=null,onConnected:W=null,ingestMode:D=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:C=Eo,unackedRetryMs:T=xo,pingMs:z=$o,maxInflightEvents:we=Ro,httpTimeoutMs:ce=No,stallBackoffMinMs:Le=Oo,fetchImpl:It=globalThis.fetch,log:y=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof s!="function")throw new Error("plane-link: listTracks is required");e=Pe(e);let sr=k.replace(/^http/,"ws"),Mt=new Set,le=new Map,ue=new Map,tt=V.join(jn,"plane-link","cursor.json"),nt=V.join(jn,"plane-link","dead-letter.ndjson"),Pt=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),de={},ne={},$=new Map,Be=null,re=null,Q=0,Ee=0,Dt=0,Ct=Promise.resolve(),O="ws",ye=0,Y=!1,fe=0,rt=!1,B=se,ge=new Set,oe=[],j=null,X=null,q=!1,ot=!1,Oe=Fn,Re=null,Te=null,_e=null,ee=null,te=null,st=!1,Ue=0;async function ir(){try{de=JSON.parse(await je.readFile(tt,"utf8"))}catch{de={}}}function ar(){st=!0,!_e&&(_e=setTimeout(async()=>{if(_e=null,!!st){st=!1;try{await je.mkdir(V.dirname(tt),{recursive:!0}),await je.writeFile(tt,JSON.stringify(de))}catch(a){y.error("[plane-link] cursor flush failed:",a?.message||a)}}},Ao),_e.unref?.())}function N(a){return!X||X.readyState!==kt.OPEN?!1:(X.send(JSON.stringify(a)),!0)}function Ne(a){let l=Date.now();for(let{trackId:r,event:i}of a){let d=$.get(i.id);$.set(i.id,{trackId:r,seq:i.seq,event:i,sentAt:l,firstSentAt:d?.firstSentAt??l,retryAt:l+T,tries:(d?.tries??0)+1,nacks:d?.nacks??0})}return O==="http"?(dr(a),!0):N({v:I,ch:"events",type:"append",events:a})}function cr(a){let l=null;for(let r of $.values())r.trackId===a&&(l==null||r.seq<l)&&(l=r.seq);return l}function it(a){let l=ne[a];if(l==null)return;let r=cr(a),i=r==null?l:Math.min(l,r-1);i>(de[a]??0)&&(de[a]=i,ar())}function Ie(){if(Be=Date.now(),re!=null){let a=Date.now()-re;y.log(`[plane-link] spine sync recovered after ${Math.round(a/1e3)}s degraded (${Q} stall redial(s))`);let l=re;re=null,Q=0,Ee=0,Y=!1,fe=0;try{K?.({since:l,downMs:a})}catch(r){y.error(`[plane-link] onRecovered failed: ${r?.message||r}`)}}}function at(a){if(!Array.isArray(a)||!a.length)return;let l=new Set;for(let r of a){let i=$.get(r);i&&($.delete(r),(ne[i.trackId]??0)<i.seq&&(ne[i.trackId]=i.seq),l.add(i.trackId))}for(let r of l)it(r);Ie()}function jt(a,l){Dt++;let r={at:Date.now(),trackId:a.trackId,seq:a.seq,id:a.event?.id??null,type:a.event?.type??null,reason:l,event:a.event??null};y.error(`[plane-link] DEAD-LETTER ${a.trackId} seq ${a.seq} (${r.type??"?"}): plane rejected it permanently (${l}) \u2014 kept in ${nt}`),Ct=Ct.then(async()=>{await je.mkdir(V.dirname(nt),{recursive:!0}),await je.appendFile(nt,JSON.stringify(r)+`
|
|
116
116
|
`)}).catch(i=>y.error(`[plane-link] dead-letter write failed: ${i?.message||i}`))}function Ft(a,l,r,i=null){if(!Array.isArray(a)||!a.length)return;let d=new Set,h=Date.now();for(let w of a){let S=$.get(w);S&&(r?($.delete(w),jt(S,l),(ne[S.trackId]??0)<S.seq&&(ne[S.trackId]=S.seq),d.add(S.trackId)):(S.nacks++,S.retryAt=h+Math.max(1e3,Number(i)||T)))}for(let w of d)it(w);Ie()}function Lt(a=Date.now()){let l=1/0;for(let r of $.values())r.firstSentAt<l&&(l=r.firstSentAt);return l===1/0?0:a-l}function Bt(){if(!q||!$.size)return;let a=Date.now(),l=Lt(a);if(l<C||Be!=null&&a-Be<C||O==="http"&&Y||Ee>a)return;Q++;let r=Math.min(Le*2**(Q-1),Bn);if(re==null){re=a-l,y.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(l/1e3)}s with ${$.size} event(s) in flight (${O} door) \u2014 the plane is not answering appends`);try{A?.({since:re,unacked:$.size,oldestAgeMs:l,mode:O})}catch(i){y.error(`[plane-link] onDegraded failed: ${i?.message||i}`)}}if(O==="http"){Y=!0,fe=a+r,y.error(`[plane-link] ingest circuit OPEN (stall #${Q}); probing /v1/ingest/health in ${Math.round(r/1e3)}s`);return}Ee=a+r,y.error(`[plane-link] closing the link and redialing in ${Math.round(r/1e3)}s (stall redial #${Q})`);try{X?.terminate()}catch{}}function ct(){if(!q)return;let a=Date.now();if(O==="http"&&Y)return;let l=[...$.values()].filter(i=>i.event&&i.retryAt<=a&&!(O==="http"&&ge.has(i.trackId)));if(!l.length)return;l.sort((i,d)=>i.trackId===d.trackId?i.seq-d.seq:i.trackId<d.trackId?-1:1),y.log(`[plane-link] re-sending ${l.length} unacked event(s) the plane never confirmed`);let r=O==="http"?B:se;if(O==="http"){let i=new Map;for(let d of l)(i.get(d.trackId)??i.set(d.trackId,[]).get(d.trackId)).push(d);for(let[,d]of i){if(ye>=At)return;Ne(d.slice(0,r).map(h=>({trackId:h.trackId,event:h.event})))}return}for(let i=0;i<l.length;i+=r){let d=l.slice(i,i+r).map(h=>({trackId:h.trackId,event:h.event}));if(!Ne(d))return}}async function lr(a=null){for(;;){if(!q)return!1;let l=$.size<we,r=O!=="http"||ye<At&&!Y&&(!a||!ge.has(a));if(l&&r)return!0;await new Promise(i=>setTimeout(i,100))}}function lt(){if(j=null,!q||!oe.length)return;let a=oe;if(oe=[],O!=="http"){for(let r=0;r<a.length;r+=se)Ne(a.slice(r,r+se));return}let l=new Map;for(let r of a)(l.get(r.trackId)??l.set(r.trackId,[]).get(r.trackId)).push(r);for(let[r,i]of l){if(ge.has(r)||ye>=At||Y){oe.push(...i);continue}for(let d=0;d<i.length;d+=B)Ne(i.slice(d,d+B))}oe.length&&!j&&(j=setTimeout(lt,Un),j.unref?.())}let ur=a=>{let l=new Map;for(let{trackId:r,event:i}of a)(l.get(r)??l.set(r,[]).get(r)).push(i);return[...l].map(([r,i])=>({trackId:r,events:i}))},be=(a,l,r,{progress:i})=>{let d=Date.now();for(let{event:h}of a){let w=$.get(h.id);w&&(w.nacks++,w.retryAt=d+Math.max(1e3,r||T))}i&&Ie()};async function dr(a){let l=new Set(a.map(r=>r.trackId));for(let r of l)ge.add(r);ye++;try{let r=await It(`${Pt}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:ur(a)}),signal:AbortSignal.timeout(ce)}),i=(Number(r.headers.get("retry-after"))||0)*1e3;if(r.status===200){let d=await r.json();B=se;for(let h of d.results??[]){at(h.acked??[]);let w=(S,P)=>{let U=new Map;for(let E of S??[])(U.get(E.reason)??U.set(E.reason,[]).get(E.reason)).push(E.id);for(let[E,zt]of U)Ft(zt,E,P,d.retryAfterMs??null)};w(h.rejected,!0),w(h.deferred,!1)}at(d.discarded??[]),Ie();return}if(r.status===429){be(a,"overloaded",i||5e3,{progress:!0});return}if(r.status===413&&a.length>1){B=Math.max(1,Math.floor(a.length/2)),y.error(`[plane-link] ingest request too large (${a.length} events) \u2014 halving batches to ${B}`),be(a,"too_large",1e3,{progress:!0});return}if(r.status===413){let d=$.get(a[0].event.id);d&&($.delete(d.event.id),jt(d,"too_large"),(ne[d.trackId]??0)<d.seq&&(ne[d.trackId]=d.seq),it(d.trackId)),Ie();return}if(r.status===401||r.status===403){if(Date.now()-Ue>=Hn){Ue=Date.now();let d="";try{d=(await r.json())?.error??""}catch{}y.error(`[plane-link] plane refused ingest (HTTP ${r.status}${d?`: ${d}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}be(a,`http_${r.status}`,6e4,{progress:!1});return}if(r.status===400){y.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${a.length} event(s) for retry; this is a bug, not data`),be(a,"http_400",6e4,{progress:!1});return}be(a,`http_${r.status}`,i||5e3,{progress:!1})}catch(r){let i=r?.name==="TimeoutError"||r?.name==="AbortError";i&&a.length>1&&(B=Math.max(1,Math.floor(a.length/2)),y.error(`[plane-link] ingest request of ${a.length} event(s) outlived its ${ce} ms deadline \u2014 halving batches to ${B}`)),be(a,i?"timeout":"network",5e3,{progress:!1})}finally{ye--;for(let r of l)ge.delete(r)}}async function fr(){if(O!=="http"||!Y||!q||rt)return;let a=Date.now();if(!(fe>a)){rt=!0;try{let l=await It(`${Pt}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(ce)});if(!l.ok)throw new Error(`HTTP ${l.status}`);y.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Y=!1,fe=0,Ee=Date.now()+ce+T+1e3;for(let r of $.values())r.retryAt=Math.min(r.retryAt,Date.now());ct()}catch(l){Q++;let r=Math.min(Le*2**(Q-1),Bn);fe=Date.now()+r,y.error(`[plane-link] ingest door still not answering (${l?.message||l}); next probe in ${Math.round(r/1e3)}s`)}finally{rt=!1}}}function Ut(){let a=Date.now();return{mode:O,unacked:$.size,oldestUnackedAgeMs:Lt(a),lastProgressAt:Be,degradedSince:re,stallRedials:Q,deadLettered:Dt,http:O==="http"?{inFlight:ye,circuitOpen:Y,nextProbeInMs:Y?Math.max(0,fe-a):0,batchCap:B}:null}}async function Ht(){if(!p)return;let a;try{a=await p()}catch(l){y.error("[plane-link] metrics sample failed:",l?.message||l);return}a&&N({v:I,ch:"ctl",type:"metrics",metrics:{...a,planeLink:Ut()}})}function pr(){p&&(te&&clearInterval(te),Ht(),te=setInterval(Ht,_),te.unref?.())}async function hr(){let a;try{a=await s()}catch(l){y.error("[plane-link] backfill listTracks failed:",l?.message||l);return}N({v:I,ch:"ctl",type:"tracks",ids:a.filter(l=>!l.transferredTo).map(l=>l.id).filter(l=>typeof l=="string")});for(let l of a){if(!q)return;let r;try{r=await wt(l)}catch{continue}let i=de[l.id]??0,d=r.filter(w=>w.seq>i&&typeof w.id=="string"),h=O==="http"?B:se;for(let w=0;w<d.length;w+=h){if(!await lr(l.id))return;let S=d.slice(w,w+Math.min(h,O==="http"?B:se)).map(P=>({trackId:l.id,event:P}));if(!Ne(S))return}}}function Kt(a){!q||!a?.trackId||typeof a.id!="string"||(oe.push({trackId:a.trackId,event:a}),j||(j=setTimeout(lt,Un),j.unref?.()))}let Me=new Map;async function mr(a){let{reqId:l,method:r,path:i,headers:d={},body:h}=a,w=Object.fromEntries(Object.entries(d).filter(([,P])=>P!=null)),S=new AbortController;Me.set(l,S);try{if(a.host){await wr(a,w,S);return}let P=await fetch(k+i,{method:r,headers:w,body:h?Buffer.from(h,"base64"):void 0,signal:S.signal}),U=Object.fromEntries(P.headers);for(let E of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete U[E];if(U["content-type"]||(U["content-type"]="application/octet-stream"),N({v:I,ch:"control",type:"http_head",reqId:l,status:P.status,headers:U}),P.body){for await(let E of P.body)if(!N({v:I,ch:"control",type:"http_data",reqId:l,data:Buffer.from(E).toString("base64")}))break}N({v:I,ch:"control",type:"http_end",reqId:l,error:null})}finally{Me.delete(l)}}function wr(a,l,r){let{reqId:i,method:d,path:h,body:w}=a,S=new URL(k);return new Promise(P=>{let U=_o.request({host:S.hostname,port:S.port,method:d,path:h,headers:{...l,host:a.host},signal:r.signal},E=>{let{connection:zt,"keep-alive":bs,"transfer-encoding":Ss,upgrade:vs,...yr}=E.headers;N({v:I,ch:"control",type:"http_head",reqId:i,status:E.statusCode||502,headers:yr}),E.on("data",gr=>{N({v:I,ch:"control",type:"http_data",reqId:i,data:Buffer.from(gr).toString("base64")})||E.destroy()}),E.on("end",()=>{N({v:I,ch:"control",type:"http_end",reqId:i,error:null}),P()}),E.on("error",()=>{N({v:I,ch:"control",type:"http_end",reqId:i,error:"view upstream error"}),P()})});U.on("error",E=>{N({v:I,ch:"control",type:"http_end",reqId:i,error:E?.message||"view request failed"}),P()}),w&&U.write(Buffer.from(w,"base64")),U.end()})}function Wt(){if(ot)return;X=new kt(e,{headers:{authorization:`Bearer ${t}`}}),X.on("open",async()=>{let l=null;try{l=await c?.()||null}catch{l=null}N({v:I,ch:"ctl",type:"hello",nodeId:n,name:o,platform:process.platform,version:G,installKind:g,...typeof x=="function"?{updatePolicy:x()}:x?{updatePolicy:x}:{},providers:Wn(),...l?{agents:l}:{}})}),X.on("message",l=>{let r;try{r=JSON.parse(l)}catch{return}if(r.ch==="ctl"&&r.type==="hello_ok"){q=!0,Oe=Fn,Re=null,y.log(`[plane-link] connected to plane as ${n}`);try{W?.()}catch{}r.minNodeVersion&&G&&ke(G,r.minNodeVersion)&&y.error(`[plane-link] this node is bostrat-node ${G}; the plane asks for \u2265${r.minNodeVersion} \u2014 update with: ${Fe(g)}`);try{f?.(typeof r.updatePolicy=="string"?r.updatePolicy:null)}catch{}let i=typeof r.latestNodeVersion=="string"?r.latestNodeVersion:null;if(i&&G&&ke(G,i)&&!Mt.has(i)){Mt.add(i),y.log(`[plane-link] bostrat-node ${i} is available (this node runs ${G}) \u2014 ${Fe(g)}`);try{m?.({current:G,latest:i,min:r.minNodeVersion??null,installKind:g,required:!!(r.minNodeVersion&&ke(G,r.minNodeVersion))})}catch(h){y.error(`[plane-link] update notice failed: ${h?.message||h}`)}}let d=r.ingest==="http";O=D==="ws"?"ws":D==="http"||d?"http":"ws",D==="http"&&!d&&y.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),O==="http"&&y.log("[plane-link] spine rides the HTTPS ingest door"),Y=!1,fe=0,B=se,ee&&clearInterval(ee),ee=setInterval(()=>{N({v:I,ch:"ctl",type:"ping"}),Bt(),fr().catch(()=>{}),ct(),oe.length&&!j&<()},z),ee.unref?.(),pr(),hr().catch(h=>y.error("[plane-link] backfill failed:",h?.message||h));return}if(r.ch==="ctl"&&r.type==="hello_refused"){let i=typeof r.minNodeVersion=="string"?r.minNodeVersion:null,d=typeof r.latestNodeVersion=="string"?r.latestNodeVersion:null;y.error(`[plane-link] plane REFUSED this node: bostrat-node ${G??"?"} is below its minimum ${i??"?"} \u2014 ${r.fix||Fe(g)}`),Oe=Ln,Re=0;try{b?.({current:G,min:i,latest:d,fix:r.fix||Fe(g),installKind:g})}catch(h){y.error(`[plane-link] refusal handler failed: ${h?.message||h}`)}return}if(r.ch==="ctl"&&r.type==="update_policy"){try{f?.(typeof r.mode=="string"?r.mode:null)}catch{}return}if(r.ch==="ctl"&&r.type==="usage_caps"){Dn(r.caps??{},{source:"plane",updatedAt:r.updatedAt??Date.now()}).then(i=>y.log(`[plane-link] spend caps ${Object.keys(i.caps).length?`updated (${Object.keys(i.caps).join(", ")})`:"cleared"} from plane`)).catch(i=>y.error("[plane-link] spend-caps push rejected:",i?.message||i));return}if(r.ch==="ctl"&&r.type==="transferred"&&Array.isArray(r.tracks)){Promise.resolve().then(()=>u?.(r.tracks)).catch(i=>y.error("[plane-link] transfer notice failed:",i?.message||i));return}if(r.ch==="events"&&r.type==="ack"&&Array.isArray(r.ids)){at(r.ids);return}if(r.ch==="events"&&r.type==="nack"&&Array.isArray(r.ids)){Ft(r.ids,r.reason,r.permanent===!0,r.retryAfterMs??null);return}if(r.ch==="control"&&r.type==="http_open"){mr(r).catch(i=>N({v:I,ch:"control",type:"http_end",reqId:r.reqId,error:i?.message||"tunnel error"}));return}if(r.ch==="control"&&r.type==="http_cancel"){Me.get(r.reqId)?.abort();return}if(r.ch==="attach"&&r.type==="open"){let i=new kt(sr+r.path,Array.isArray(r.protocols)?r.protocols:[],r.host?{headers:{host:r.host}}:void 0);le.set(r.streamId,i),ue.set(r.streamId,[]),i.on("open",()=>{let h=ue.get(r.streamId)||[];ue.delete(r.streamId);for(let{buf:w,bin:S}of h)i.send(w,{binary:S})}),i.on("message",(h,w)=>{let S=w?h:Buffer.from(String(h));N({v:I,ch:"attach",type:"data",streamId:r.streamId,data:S.toString("base64"),...w?{bin:!0}:{}})});let d=()=>{ue.delete(r.streamId),le.delete(r.streamId)&&N({v:I,ch:"attach",type:"close",streamId:r.streamId})};i.on("close",d),i.on("error",d);return}if(r.ch==="attach"&&r.type==="data"){let i=le.get(r.streamId);if(!i)return;let d=Buffer.from(r.data,"base64"),h=r.bin===!0,w=ue.get(r.streamId);w?w.push({buf:d,bin:h}):i.send(d,{binary:h});return}if(r.ch==="attach"&&r.type==="close"){let i=le.get(r.streamId);le.delete(r.streamId),ue.delete(r.streamId),i?.close();return}});let a=()=>{q&&y.log("[plane-link] disconnected from plane"),q=!1,ee&&(clearInterval(ee),ee=null),te&&(clearInterval(te),te=null),$.clear(),ne={},oe=[],j&&(clearTimeout(j),j=null),ge.clear();for(let i of le.values())i.close();le.clear(),ue.clear();for(let i of Me.values())i.abort();if(Me.clear(),ot||Te)return;Re==null&&(Re=Date.now());let l=Date.now()-Re<So,r=Math.max(l?vo+Math.random()*ko:Oe,Ee-Date.now());Te=setTimeout(()=>{Te=null,Wt()},r),Te.unref?.(),l||(Oe=Math.min(Oe*2,Ln))};X.on("close",a),X.on("error",l=>{let r=/Unexpected server response: (\d+)/.exec(l?.message||"")?.[1];(r==="401"||r==="403")&&Date.now()-Ue>=Hn&&(Ue=Date.now(),y.error(`[plane-link] plane refused this node's credentials (HTTP ${r}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`)),a()})}return Ce.on("event",Kt),ir().then(Wt),{stop:()=>{ot=!0,Ce.off("event",Kt),Te&&clearTimeout(Te),_e&&clearTimeout(_e),ee&&clearInterval(ee),te&&clearInterval(te),j&&clearTimeout(j),N({v:I,ch:"ctl",type:"bye",reason:"shutdown"}),X?.close()},status:()=>({connected:q,nodeId:n,cursor:{...de},inflight:$.size,...Ut()}),_tick:()=>{Bt(),ct()}}}var G,jn,I,Fn,Ln,So,vo,ko,se,Ao,$o,xo,zn,Eo,Oo,Bn,Ro,Un,No,At,Io,Hn,$t=v(()=>{Ye();Cn();pt();G=(()=>{try{return bo(import.meta.url)("../package.json").version||null}catch{return null}})(),jn=process.env.BOSTRAT_STATE_DIR||V.join(process.env.HOME||Xe.tmpdir(),".bostrat");I=1,Fn=1e3,Ln=3e4,So=6e4,vo=1500,ko=500,se=100,Ao=2e3,$o=25e3,xo=6e4,zn=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},Eo=zn(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),Oo=3e4,Bn=10*6e4,Ro=400,Un=250,No=zn(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),At=4,Io=6e4,Hn=6e4});import{execFile as Po}from"node:child_process";import{promisify as Do}from"node:util";function qn(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}var rc,oc,sc,Gn=v(()=>{yt();rc=Do(Po),oc=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,sc=Promise.resolve()});var Qn={};ut(Qn,{ACTIONABLE_KINDS:()=>et,SELF_UPDATE_DIR:()=>xt,createAutoUpdater:()=>Go,inFlight:()=>Ot,readStatus:()=>Et,selfUpdatePlan:()=>Xn,settleSelfUpdate:()=>qo,startSelfUpdate:()=>Zn,underService:()=>Jn,updatePolicy:()=>Ho});import Vn from"node:fs";import ie from"node:fs/promises";import Co from"node:os";import M from"node:path";import{spawn as jo}from"node:child_process";import{createRequire as Fo}from"node:module";function Ho({kind:e=Ae(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:et.has(e)?e==="git-checkout"||Jn(t)?"auto":"prompt":"off"}function Jn(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}function Xn({kind:e,to:t,from:n=Ze,statusFile:o=Qe,logFile:s=M.join(xt,"last.log"),port:c=Number(process.env.PORT)||3362,npmPrefix:u=null,serviceName:p=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:_=typeof process.getuid=="function"?process.getuid():0,liveDir:m=process.env.BOSTRAT_LIVE_CHECKOUT||M.resolve(M.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:f=Date.now()}={}){if(!et.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let b=(K,W="")=>`write_status ${F(K)} ${W}`,x=process.platform==="darwin"?`launchctl kickstart -k gui/${_}/${p}`:`systemctl --user restart ${F(p)}`,g=`
|
|
117
117
|
health() {
|
|
118
118
|
for i in $(seq 1 45); do
|
package/dist/index.js
CHANGED
|
@@ -84,7 +84,7 @@ printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${Ha}/a
|
|
|
84
84
|
exit 0
|
|
85
85
|
`});import{execFile as gb}from"node:child_process";import{promisify as LO}from"node:util";import ul from"node:fs";import{randomUUID as yb}from"node:crypto";function ps(e){return new Promise(t=>setTimeout(t,e))}function ll(e,t){if(!t)return e;let n=o=>typeof o=="string"?o.split(t).join("<redacted>"):o,r=new Error(n(e?.message)||"command failed");return e?.code!==void 0&&(r.code=e.code),e?.stderr!==void 0&&(r.stderr=n(e.stderr)),r}function bb(e){return`/tmp/tmux-${e}/default`}function FO({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=bb(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function qa(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${Wa}=1`]}function Ga(e,t,n){let r=so(e),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(e);if(!r||o)return e;let s=`${e} --session-id ${t}`,a=/(^|\s)(--name|-n)(\s|=)/.test(e);return n&&!a&&Le(n)&&(s+=` --name ${n}`),s}function so(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function hr(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function WO(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:so(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function kb(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await xb(e,{loginShell:t});return r===dl?!0:r===ds?!1:n}async function xb(e,{loginShell:t=!1,timeoutMs:n=Rf}={}){if(!e)return ds;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Ce(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),dl}catch(s){return s?.killed||s?.signal?fs:s?.code===1||s?.code===127?ds:fs}}async function fl(e,{retries:t=qO,sleep:n=GO,probe:r=xb}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Rf});for(let a=0;s===fs&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:Rf*2});return s}function Z(...e){return["-S",It,...e]}async function wr(){if(!ul.existsSync(It))return!1;try{return await Ce(J,Z("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Ka(){if(await wr())return!0;try{ul.mkdirSync(It.replace(/\/[^/]+$/,""),{recursive:!0}),await Ce(J,Z("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await wr()}function Le(e){return typeof e=="string"&&KO.test(e)}async function Zt(){if(!ul.existsSync(It))return[];try{let e="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}|#{session_created}",{stdout:t}=await Ce(J,Z("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
|
|
86
86
|
`).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,f,d,p,h]=r.split("|"),w=Number(i),g=Number(h);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(w)?n-w*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:f||null,agent:d||(l==="1"?"claude":null),alternateOn:p==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!HO.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ke(e){return(await Zt()).find(n=>n.name===e)||null}function YO(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=zO&&VO.test(t)}function pl(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function vb(e){try{let{stdout:t}=await Ce(J,Z("list-sessions","-F","#{session_name}"));return t.split(`
|
|
87
|
-
`).map(n=>n.trim()).includes(e)}catch{return!1}}function ZO(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[];for(let
|
|
87
|
+
`).map(n=>n.trim()).includes(e)}catch{return!1}}function ZO(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[],r=s=>/[A-Za-z0-9_]/.test(s);for(let s=1;s<=t.length-3;s++)r(t[s-1])===r(t[s])&&n.push(t.slice(s));if(!n.length)return null;let o=n.map(s=>s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${o.join("|")})`)}async function QO(e,t){let n=Date.now()+Va(),r=ZO(t),o=!1,s=0;for(;;){if(await ps(JO),s+=1,!await vb(e))return;let a=await De(e,{lines:15}),i=!o&&XO.test(a)&&!!r?.test(a),c=!o&&!!r?.test(a);if(!i&&!c&&s>1&&!await Bn(e))return;if(i){o=!0,await ue({flow:"spawn",phase:"launch-retry",sessionName:e,agent:hr(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Ce(J,Z("send-keys","-t",e,"C-u")),await Ce(J,Z("send-keys","-t",e,"-l",t)),await Ce(J,Z("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ue({flow:"spawn",phase:"launch-failed",sessionName:e,agent:hr(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function gr(e,t=UO,n={}){if(!YO(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=pl(r);if(!Le(o))throw new Error("resulting tmux session name is invalid");if(!await Ka())throw new Error(`host tmux server not running on ${It} and auto-start failed \u2014 start one: ${J} -S ${It} new-session -d -s keeper "sleep 2147483647"`);if(await vb(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Of,a=n.agent||hr(s),i=!!n.resumeSessionId,c=n.resumeSessionId||yb(),l=i?s:Ga(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),f=a==="claude"&&so(s),d=n.firstRun===!0;d||(f&&await cr(t),a==="codex"&&await ts(t),a==="cursor"&&await ns(t),await qy(t),n.freshWorkspace!==!0&&await sl(t));let p=f&&!d?Uc():null,h=uy(),w=["-e",`${Mn}=${h}`];w.push(...mb({nodeUrl:hb()})),p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&w.push(...qa());try{await Ce(J,Z("new-session","-d","-s",o,"-c",t,...w))}catch(g){throw ll(p?ll(g,p):g,h)}return await ao(o),await Ce(J,Z("set-option","-t",o,"@bostrat-session","1")),await Ce(J,Z("set-option","-t",o,"@bostrat-title",r)),await Ce(J,Z("set-option","-t",o,"@bostrat-sid",c)),await Ce(J,Z("set-option","-t",o,"@bostrat-agent",a)),await Ce(J,Z("send-keys","-t",o,l,"Enter")),WO(l)&&QO(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:h}}async function Qt(e){if(!Le(e))throw new Error("invalid session name");await Ce(J,Z("kill-session","-t",e))}async function Sb(e,t){if(Le(e))try{let n=t?Z("set-option","-t",e,"@bostrat-sid",t):Z("set-option","-u","-t",e,"@bostrat-sid");await Ce(J,n)}catch{}}async function De(e,{lines:t=40}={}){if(!Le(e))return"";try{let n=Z("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Ce(J,n);return String(r||"")}catch{return""}}async function Tb(e){if(!Le(e))return 0;try{let{stdout:t}=await Ce(J,Z("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
|
|
88
88
|
`).filter(Boolean).length}catch{return 0}}async function ao(e,{cols:t=nC,rows:n=rC}={}){if(!Le(e))return!0;if(await Tb(e))return!1;try{let r=await Ab(e);if(r.cols===t&&r.rows===n)return!0;await Ce(J,Z("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Ce(J,Z("set-window-option","-t",e,"window-size","latest")),await ps(80)}catch{}return!0}async function oC(e){if(!Le(e))return 0;try{let{stdout:t}=await Ce(J,Z("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Bn(e){let t=await oC(e);if(!t)return!1;try{return await Ce("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Ab(e){if(!Le(e))return{cols:0,rows:0};try{let{stdout:t}=await Ce(J,Z("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function ml(e,{cols:t=eC,rows:n=tC}={}){if(Le(e)&&!await Tb(e))try{let r=await Ab(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Ce(J,Z("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Ce(J,Z("set-window-option","-t",e,"window-size","latest")),await ps(80))}catch{}}async function jn(e){return await ml(e),De(e,{lines:et})}async function He(e,t,{settleMs:n=40,kind:r}={}){if(!Le(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>sC.has(s));for(let s=0;s<o.length;s++)await Ce(J,Z("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await ps(n);return ue({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function ms(e,t,{kind:n}={}){if(!Le(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await Ce(J,Z("send-keys","-t",e,"-N",String(r),"BSpace")),ue({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function wl(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!Le(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await Ce(J,Z("send-keys","-t",e,"-l",s)),n>0&&await ps(n);ue({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function aC(e,t){return new Promise((n,r)=>{let o=gb(J,Z(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function iC(e,t){let n=`bostrat-${yb().slice(0,8)}`;await aC(["load-buffer","-b",n,"-"],t),await Ce(J,Z("paste-buffer","-p","-d","-b",n,"-t",e))}async function tt(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!Le(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await iC(e,t):await Ce(J,Z("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await ps(a),await Ce(J,Z("send-keys","-t",e,"Enter"))}ue({flow:"tmux",phase:"send",sessionName:e,kind:o||"text",textLen:typeof t=="string"?t.length:0,textHead:typeof t=="string"?t.slice(0,120):"",enter:n,submitDelayMs:r,...s?{paste:!0}:{}}).catch(()=>{})}var Ce,J,wb,It,UO,Of,Wa,Cf,HO,dl,ds,fs,Rf,qO,GO,Mf,KO,VO,zO,Va,JO,XO,eC,tC,et,nC,rC,sC,hl,ut=H(()=>{Ia();Wc();qc();Pa();al();hn();es();$f();Ce=LO(gb);J=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";wb=typeof process.getuid=="function"?process.getuid():0,It=FO({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return ul.existsSync(bb(wb))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:wb}),UO=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Of=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",Wa="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";Cf="bostrat-usage-probe",HO=new Set([Cf]);dl="present",ds="absent",fs="unknown",Rf=5e3,qO=[250,1e3,3e3],GO=e=>new Promise(t=>setTimeout(t,e));Mf={claude:"npm install -g @anthropic-ai/claude-code",codex:"npm install -g @openai/codex","cursor-agent":"curl https://cursor.com/install -fsS | bash",gh:"apt install gh (Debian: enable cli.github.com/packages) / brew install gh \u2014 see https://github.com/cli/cli#installation"};KO=/^[A-Za-z0-9_.-]{1,64}$/;VO=/^[A-Za-z0-9 ._↻-]+$/,zO=64;Va=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,JO=1e3,XO=/not found|Unknown command/i;eC=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,tC=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,et=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,nC=Number(process.env.BOSTRAT_BOX_COLS)||120,rC=Number(process.env.BOSTRAT_BOX_ROWS)||40;sC=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);hl=1600});import za from"node:fs";import pC from"node:fs/promises";import hs from"node:path";import mC from"node:os";function Df(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function Bf(e){let t=hs.join(Pf,Df(e)),n;try{n=za.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=hs.join(t,o);try{let{mtimeMs:a}=za.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function en(e,t){if(!t)return null;let n=hs.join(Pf,Df(e),`${t}.jsonl`);return za.existsSync(n)?n:null}function Cb(e){if(!e)return[];let t=hs.join(Pf,Df(e)),n;try{n=za.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=za.statSync(hs.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function At(e,t=131072){let n=await pC.open(e,"r");try{let{size:r}=await n.stat(),o=Math.max(0,r-t),s=r-o;if(s===0)return"";let a=Buffer.alloc(s);return await n.read(a,0,s,o),a.toString("utf8")}finally{await n.close()}}function wC(e){let t=e.split(`
|
|
89
89
|
`);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function Ya(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=en(e,t),o=!0,!r)return null}else if(n){if(r=Bf(e),o=!1,!r)return null}else return null;let s;try{s=wC(await At(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Ob,s.model),i=Ob[s.model]||hC;return{source:"transcript",exact:o,model:s.model,windowKnown:a,window:i,occupancy:s.occupancy,pct:Math.min(1,s.occupancy/i),transcript:r}}var Ob,hC,Pf,tn=H(()=>{Ob={"claude-opus-5":1e6,"claude-opus-4-8":1e6,"claude-opus-4-7":1e6,"claude-opus-4-6":1e6,"claude-sonnet-5":1e6,"claude-sonnet-4-6":1e6,"claude-haiku-4-5":2e5,"claude-fable-5":1e6},hC=2e5,Pf=process.env.BOSTRAT_CLAUDE_PROJECTS||hs.join(mC.homedir(),".claude","projects")});function gC(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
|
|
90
90
|
`){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function Ja(e){let t=[],n="",r=null,o=!1,s=()=>{if(o){if(/^\d*[<>]/.test(n)||n.startsWith(">")){n="",o=!1;return}t.push(n),n="",o=!1}};for(let a=0;a<e.length;a++){let i=e[a];if(r){i===r&&e[a-1]!=="\\"?r=null:n+=i,o=!0;continue}if(i==="'"||i==='"'){r=i,o=!0;continue}if(i==="<"&&e[a+1]==="<")return s(),t.push("<<"),t;if(/\s/.test(i)){s();continue}n+=i,o=!0}return s(),t}function Xa(e){let t=e;for(;t.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0]);)t=t.slice(1);for(;t.length&&(t[0]==="sudo"||t[0]==="time"||t[0]==="env");)t=t.slice(1);return t}function Pe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(Pb(o)){t.has(o)&&r++;continue}n.push(o)}return n}function Db(e){let t=e.indexOf("-n"),n=t!==-1?e[t+1]:null;if(!n)return null;let r=/^(\d+),(\d+)p$/.exec(n)||/^(\d+)p$/.exec(n);return r?r[2]?{from:r[1],to:r[2]}:{from:r[1],to:r[1]}:null}function kC(e){let t=Db(e),n=dt(Pe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${We(n)}`:`Read lines ${t.from}\u2013${t.to} of ${We(n)}`:e.includes("-i")&&n?`Edit ${We(n)}`:null}function jf(e){if(e.includes("--files")){let s=dt(Pe(e,Mb)[0]);return s&&s!=="."?`List files in ${ws(s)}`:"List files"}let t=Pe(e,Mb),n=t[0];if(!n)return null;let r=dt(t.slice(1).find(s=>s!==".")),o=gs(n,40);return r?`Search for \u201C${o}\u201D in ${ws(r)}`:`Search for \u201C${o}\u201D`}function Lf(e){let t=Pe(e,new Set(["--prefix"])),n=t[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?t[1]?`Run ${t[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function Ff(e,t){if(e.includes("-e")||e.includes("--eval")||e.includes("-c")||e[1]==="-"||e.includes("<<"))return`Run an inline ${t} script`;if(e.includes("--test"))return"Run tests";let n=Pe(e)[0];return n?`Run ${We(n)}`:null}function xC(e){let t=Pe(e),n=t[0],r=t.find(a=>/\.(service|timer|socket|target)$/.test(a))||t[1],o=r?r.replace(/\.service$/,""):"a service";return{status:`Check ${o} status`,show:`Inspect ${o}`,restart:`Restart ${o}`,start:`Start ${o}`,stop:`Stop ${o}`,"daemon-reload":"Reload systemd"}[n]||null}function Nb(e){return e.find(t=>/^https?:\/\//.test(t))||null}function TC(e){let t=Xa(Ja(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(We(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return Uf(t[2]);let n=We(t[0]);if(SC.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=vC[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function Uf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
|
|
@@ -118,7 +118,7 @@ exit 0
|
|
|
118
118
|
`);return e}function fk(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function ik(e){let t=new Error(`${e} isn't running in this box \u2014 its pane is sitting at a bare shell (the launch command was likely swallowed at shell startup, or the CLI exited). Relaunch it from the Terminal tab, or stop and reopen the box, then send again.`);return t.code="cli-not-running",t}async function ck(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await ao(e).catch(()=>{});;){let l=rp(await De(e),o);if(SM(t,l)){await s?.(),await wn(ks);return}if(ze[t]?.up&&!ze[t].up.test(l))if(await Bn(e)){if(c??=Date.now(),Date.now()-c>=Va()){let u=ik(t);throw ue({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,idleMs:Date.now()-c,error:u.message}).catch(()=>{}),u}}else c=null;else c=null;if(r&&t==="claude"&&hM.test(l)&&!ze.claude.up.test(l)){ue({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{});return}if(t==="codex"&&mM.test(l)&&!ze.codex.up.test(l)&&i<3){if(!Qf(e,"codex-trust")){await wn(vl);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await tt(e,"",{enter:!0,kind:"codex-trust-accept"}),await wn(ks);continue}if(t==="cursor"&&pM.test(l)&&!ze.cursor.up.test(l)&&i<3){if(!Qf(e,"cursor-trust")){await wn(vl);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await tt(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await wn(ks);continue}if(t==="codex"&&i<3){let u=gM(l);if(u){if(!Qf(e,`codex-update:${u.from}->${u.to}`)){await wn(vl);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await tt(e,"3",{enter:!1,kind:"codex-update-skip"}),ek({sessionName:e,from:u.from,to:u.to}),await wn(ks);continue}}if(Date.now()>a){if(np(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=ze.codex.auth.test(l)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&ze.cursor.auth.test(l)?u="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&ze.claude.auth.test(l)?u="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&ze.claude.block.test(l)&&(u='claude is waiting on its "Press Enter to continue" screen \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again'),ue({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Bn(e)){let u=ik(t);throw ue({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),ue({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!ze[t]?.block?.test(l),paneUp:!!ze[t]?.up?.test(l),paneBusy:!!ze[t]?.busy?.test(uk(ze[t],l))}).catch(()=>{}),await wn(ks);return}await wn(vl)}}function op({agent:e,agentCmd:t}={}){let n=t?hr(t):hr(e||"");return{label:n,realClaude:t?so(t):n==="claude",realCodex:t?/codex/.test(t)&&!/fake-codex|fake-lead/.test(t):n==="codex",realCursor:t?/cursor/.test(t)&&!/fake-cursor|fake-box/.test(t):n==="cursor"}}function pk({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=op({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function ti({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=op({agent:n,agentCmd:r});return!t||!s&&!a?null:br({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).catch(()=>{})}async function br({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=lM(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:f,realCursor:d}=op({agent:r,agentCmd:o});if(u&&e&&await cr(e),f&&e&&await ts(e),d&&e&&await ns(e),(u||f||d)&&n){await ck(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});return}let p=ze[r]?r:ze[l]?l:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&p){await ck(n,p,s,{launchEcho:i});return}await wn(ks)}var lM,vl,ks,uM,dM,ze,pM,mM,hM,wM,yM,Sl,bM,lk,xM,vM,ni=H(()=>{ut();Ia();Wc();qc();kl();xl();hn();lM=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,vl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,ks=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,uM=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,dM=/^\s*tab to queue message\b/;ze={claude:{up:/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/,busy:/esc to interrupt/,busyScope:"footer",busyAlt:/^[·✢✳✶✻✽✺✹✸✷]\s+[A-Z][\w '’-]{1,40}…/m,auth:/Select login method:|Paste code here if prompted|OAuth error:|Choose the text style that looks best|Quick safety check: Is this a project you created/,block:/Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/m},codex:{up:{test:fM},busy:/esc to interrupt|\bWorking \(/,block:/Update available![\s\S]*\b(?:Update now|Skip until next version)\b[\s\S]*Press enter to continue/,auth:/Sign in with ChatGPT[\s\S]*Press enter to continue|Finish signing in via your browser|Paste or type your API key|Successfully logged in\.[\s\S]*Press Enter to continue\./},cursor:{up:/Run Everything|Add a follow-up|Plan, search, build anything/,busy:/ctrl\+c to stop|^\s*[⠁-⣿]+\s+\S/m,block:/Workspace Trust Required|Trust this workspace|\[a\]\s*Trust|Trusting workspace/,auth:/Press any key to log in|click this link to log in|Scan this QR code to log in|Signing in with the browser/}},pM=/Trust this workspace|\[a\]\s*Trust/,mM=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,hM=/Resume from summary/i,wM=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;yM=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Sl=new Map;bM=68,lk=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;xM=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,vM=15});function _M(e){return typeof e!="string"||!e?!1:e.includes(`
|
|
119
119
|
`)?!0:Buffer.byteLength(e,"utf8")>=EM}function gn(e,t){return e==="codex"?{enter:!0,submitDelayMs:TM,..._M(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:AM}:{enter:!0}}var TM,AM,EM,ri=H(()=>{TM=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),AM=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),EM=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function oi(e,t){if(e==="codex")return CM(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
|
|
120
120
|
`).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(mk.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(mk.test(n[c])){o=c;break}if(o<0)return null;let s=n.slice(o+1,r);if(!s.length)return null;let a=s[0].match(IM);if(!a)return null;let i=[a[1].trim(),...s.slice(1).map(c=>c.trim())].filter(Boolean);return i.length?i.join(" "):null}function CM(e){let t=String(e).replace(/\r/g,"").split(`
|
|
121
|
-
`).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){($M.test(t[o])||RM.test(t[o]))&&!sp.test(t[o])?n=o:sp.test(t[o])&&/\[Pasted Content \d+ chars\]/.test(t[o])&&(n=o+1);break}if(n<=0)return null;let r=[];for(let o=n-1;o>=0&&n-o<=60;o--){let s=t[o],a=s.match(sp);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(OM.test(s))return null;r.unshift(s)}return null}function ap(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Ve(n.replace(MM,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Ve(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Ve(e){return String(e||"").replace(/\s+/g," ").trim()}function hk(e,t,{slackMs:n=2e4}={}){let r=Ve(t?.text);if(!r||typeof t?.at!="number")return!1;let o=Array.isArray(e)?e:[],s=o.findIndex(a=>a?.role==="user"&&typeof a.ts=="number"&&a.ts>=t.at-n&&Ve(a.text).includes(r));return s>=0&&s<o.length-1}function wk(e,t,n,{busy:r=!1}={}){let o=oi(e,n);return o&&Al(t,o)||o&&e==="codex"&&ap(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Al(e,t){let n=Ve(e),r=Ve(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var mk,IM,sp,$M,RM,OM,MM,El=H(()=>{mk=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,IM=/^❯[ ]?(.*)$/,sp=/^\s*›[ ]?(.*)$/,$M=/\S+ · \S/,RM=/^\s*(?:\? for shortcuts|tab to queue message)\b/,OM=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;MM=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ai({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say"},a={}){if(!NM.has(t))return!0;let i=a.waitForUp??pk({agent:t,agentCmd:n}),c=a.capture||(I=>De(I,{lines:et})),l=a.pressEnter||(I=>He(I,["Enter"],{kind:"submit-retry"})),u=a.sleep||jM,f=a.now||Date.now,d=a.log||(I=>ue(I).catch(()=>{})),p=a.maxMs??BM(),h=f()+p,w={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},g=0,b=0,v=0,x=!1;for(await u(si[0]);;){let I=await c(e).catch(()=>""),P=vs(t,I),B=xs(t,I),j=wk(t,r,I,{busy:B});if(j==="submitted")return!0;if(i&&(!P||j==="stuck"&&B)){if(f()>=h)return j==="stuck"?(d({...w,phase:"submit-failed",reason:"stuck-at-deadline",retries:g}),!1):(d({...w,phase:"submit-unverified",reason:x?"cli-down":"cli-never-up",retries:g,waitedMs:p}),!0);await u(PM);continue}if(x=!0,j==="stuck"){if(g>=DM)return d({...w,phase:"submit-failed",retries:g}),!1;g+=1,b=0,v=0,await l(e),d({...w,phase:"submit-retry",attempt:g}),await u(si[0]);continue}if(b+=1,b>=si.length||f()>=h)return!0;v+=1,await u(si[Math.min(v,si.length-1)])}}var NM,si,PM,DM,BM,jM,ip=H(()=>{ut();ni();El();hn();NM=new Set(["claude","codex"]),si=[250,450,700],PM=500,DM=2,BM=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},jM=e=>new Promise(t=>setTimeout(t,e))});function gk(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function Ln(e){let t=gk(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of LM){let o=0;for(let s of FM[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function yk(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))UM.has(r)&&(t+=o||0),HM.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function ii(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}function bk(e){let t=gk(e).trim();return t?qM.test(t)?!0:t.split(/\s+/).length<=WM:!1}var LM,FM,UM,HM,WM,qM,_l=H(()=>{LM=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],FM={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope (it |this |that |them )?out\b/,/\btalk (me |us )?through\b/,/\b(give|show|tell) me\b/,/\bwhat about\b/,/\bwhy\b/,/\btake a look\b/,/\bwalk (me |us )?through\b/,/\bexplain\b/,/\bdo we (still |even )?need\b/,/\bis there (a|an|any)\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/,/\bkeeps? getting\b/,/\bdoesn'?t (seem|look) right\b/,/\bseems? (wrong|off|broken)\b/,/\b(too slow|slower than|much slower)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/]};UM=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),HM=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);WM=12,qM=/^\s*(ok(ay)?|yes|yep|yeah|sure|go ahead|go|proceed|continue|next|begin|start|do it|do that|try again|try once more|again|ship it|perfect|great|good|nice|thanks|lock(ed)? (it |that |those )?in|option [a-z]\b|where are we|what'?s the status)\b/i});function Sk(e){let t=ii(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||GM.has(r)||n.push(r);return n}function KM(e){let t=[];for(let n of e||[]){let r=n.payload||{},o=String(r.text||"").trim();if(n.type==="turn.user"){if(n.source==="hook"||!o)continue;t.push(vk(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(vk(n,"assistant",o))}}return t}function vk(e,t,n){let r=Ln(n);return{id:e.id,seq:e.seq,ts:e.payload?.ts??e.ts,role:t,boxId:e.boxId??null,provider:e.provider??null,text:n,tags:r?[r.category]:[]}}function ci(e){let t=KM(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=Sk(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function Il(e,t,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!e||!e.N)return[];let i=[...new Set(Sk(t))];if(!i.length)return[];let c=new Map;for(let u of i){let f=e.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(e.N-d+.5)/(d+.5));for(let[h,w]of f){let g=e.lengths[h],b=w+kk*(1-xk+xk*(g/(e.avgdl||1))),v=p*(w*(kk+1)/b);c.set(h,(c.get(h)||0)+v)}}let l=[];for(let[u,f]of c){let d=e.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var kk,xk,GM,cp=H(()=>{_l();kk=1.5,xk=.75,GM=new Set("a an and are as at be been but by for from had has have he her his i if in into is it its of on or our so than that the their them then there these they this those to was were will with would you your we".split(" "))});import $l from"node:fs/promises";import Tk from"node:path";async function VM(e){let t=Tk.join(e,".bostrat","events"),n;try{n=await $l.readdir(t)}catch{return ci([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await $l.readFile(Tk.join(t,o),"utf8");for(let a of s.split(`
|
|
121
|
+
`).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){($M.test(t[o])||RM.test(t[o]))&&!sp.test(t[o])?n=o:sp.test(t[o])&&/\[Pasted Content \d+ chars\]/.test(t[o])&&(n=o+1);break}if(n<=0)return null;let r=[];for(let o=n-1;o>=0&&n-o<=60;o--){let s=t[o],a=s.match(sp);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(OM.test(s))return null;r.unshift(s)}return null}function ap(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Ve(n.replace(MM,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Ve(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Ve(e){return String(e||"").replace(/\s+/g," ").trim()}function hk(e,t,{slackMs:n=2e4}={}){let r=Ve(t?.text);if(!r||typeof t?.at!="number")return!1;let o=Array.isArray(e)?e:[],s=o.findIndex(a=>a?.role==="user"&&typeof a.ts=="number"&&a.ts>=t.at-n&&Ve(a.text).includes(r));return s>=0&&s<o.length-1}function wk(e,t,n,{busy:r=!1}={}){let o=oi(e,n);return o&&Al(t,o)||o&&e==="codex"&&ap(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Al(e,t){let n=Ve(e),r=Ve(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var mk,IM,sp,$M,RM,OM,MM,El=H(()=>{mk=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,IM=/^❯[ ]?(.*)$/,sp=/^\s*›[ ]?(.*)$/,$M=/\S+ · \S/,RM=/^\s*(?:\? for shortcuts|tab to queue message)\b/,OM=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;MM=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ai({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say"},a={}){if(!NM.has(t))return!0;let i=a.waitForUp??pk({agent:t,agentCmd:n}),c=a.capture||(I=>De(I,{lines:et})),l=a.pressEnter||(I=>He(I,["Enter"],{kind:"submit-retry"})),u=a.sleep||jM,f=a.now||Date.now,d=a.log||(I=>ue(I).catch(()=>{})),p=a.maxMs??BM(),h=f()+p,w={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},g=0,b=0,v=0,x=!1;for(await u(si[0]);;){let I=await c(e).catch(()=>""),P=vs(t,I),B=xs(t,I),j=wk(t,r,I,{busy:B});if(j==="submitted")return!0;if(i&&(!P||j==="stuck"&&B)){if(f()>=h)return j==="stuck"?(d({...w,phase:"submit-failed",reason:"stuck-at-deadline",retries:g}),!1):(d({...w,phase:"submit-unverified",reason:x?"cli-down":"cli-never-up",retries:g,waitedMs:p}),!0);await u(PM);continue}if(x=!0,j==="stuck"){if(g>=DM)return d({...w,phase:"submit-failed",retries:g}),!1;g+=1,b=0,v=0,await l(e),d({...w,phase:"submit-retry",attempt:g}),await u(si[0]);continue}if(b+=1,b>=si.length||f()>=h)return!0;v+=1,await u(si[Math.min(v,si.length-1)])}}var NM,si,PM,DM,BM,jM,ip=H(()=>{ut();ni();El();hn();NM=new Set(["claude","codex"]),si=[250,450,700],PM=500,DM=2,BM=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},jM=e=>new Promise(t=>setTimeout(t,e))});function gk(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function Ln(e){let t=gk(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of LM){let o=0;for(let s of FM[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function yk(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))UM.has(r)&&(t+=o||0),HM.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function ii(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}function bk(e){let t=gk(e).trim();return t?qM.test(t)?!0:t.split(/\s+/).length<=WM:!1}var LM,FM,UM,HM,WM,qM,_l=H(()=>{LM=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],FM={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope (it |this |that |them )?out\b/,/\btalk (me |us )?through\b/,/\b(give|show|tell) me\b/,/\bwhat about\b/,/\bwhy\b/,/\btake a look\b/,/\bwalk (me |us )?through\b/,/\bexplain\b/,/\bdo we (still |even )?need\b/,/\bis there (a|an|any)\b/,/\bhow often\b/,/\bdo we (currently|already)\b/,/\bwould it be (valuable|useful|worth)\b/,/\bis it possible\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/,/\bkeeps? getting\b/,/\bdoesn'?t (seem|look) right\b/,/\bseems? (wrong|off|broken)\b/,/\b(too slow|slower than|much slower)\b/,/\bfail(ed|ing|s)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/,/\b(linked[ -]?in|social( media)?) post\b/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/,/\b(unzip|decompress|untar)\b/]};UM=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),HM=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);WM=12,qM=/^\s*(ok(ay)?|yes|yep|yeah|sure|go ahead|go|proceed|continue|next|begin|start|do it|do that|try again|try once more|again|ship it|perfect|great|good|nice|thanks|lock(ed)? (it |that |those )?in|option [a-z]\b|where are we|what'?s the status)\b/i});function Sk(e){let t=ii(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||GM.has(r)||n.push(r);return n}function KM(e){let t=[];for(let n of e||[]){let r=n.payload||{},o=String(r.text||"").trim();if(n.type==="turn.user"){if(n.source==="hook"||!o)continue;t.push(vk(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(vk(n,"assistant",o))}}return t}function vk(e,t,n){let r=Ln(n);return{id:e.id,seq:e.seq,ts:e.payload?.ts??e.ts,role:t,boxId:e.boxId??null,provider:e.provider??null,text:n,tags:r?[r.category]:[]}}function ci(e){let t=KM(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=Sk(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function Il(e,t,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!e||!e.N)return[];let i=[...new Set(Sk(t))];if(!i.length)return[];let c=new Map;for(let u of i){let f=e.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(e.N-d+.5)/(d+.5));for(let[h,w]of f){let g=e.lengths[h],b=w+kk*(1-xk+xk*(g/(e.avgdl||1))),v=p*(w*(kk+1)/b);c.set(h,(c.get(h)||0)+v)}}let l=[];for(let[u,f]of c){let d=e.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var kk,xk,GM,cp=H(()=>{_l();kk=1.5,xk=.75,GM=new Set("a an and are as at be been but by for from had has have he her his i if in into is it its of on or our so than that the their them then there these they this those to was were will with would you your we".split(" "))});import $l from"node:fs/promises";import Tk from"node:path";async function VM(e){let t=Tk.join(e,".bostrat","events"),n;try{n=await $l.readdir(t)}catch{return ci([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await $l.readFile(Tk.join(t,o),"utf8");for(let a of s.split(`
|
|
122
122
|
`))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return ci(r)}function zM(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
|
|
123
123
|
${o}`.trim()||t.slice(0,2e3)}function YM(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Il(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),f=u.length>800?u.slice(0,800)+"\u2026":u,d=`- **${l}:** ${f}`;if(i+d.length>r||(a.push(d),i+=d.length,a.length>=n))break}return a.length?["",`## ${Ak}, not a summary)`,"_Auto-selected from the Track's event log by lexical relevance to the Objective / Next steps. Verbatim excerpts, not re-summarization (docs/memory-segmentation-indexing-scope.md \xA71.3)._","",...a,""].join(`
|
|
124
124
|
`):""}async function Ek(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await $l.readFile(t,"utf8");if(a.includes(Ak))return{appended:!1,reason:"already-enriched"};let i=await VM(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=YM(i,zM(a),{k:r,maxChars:o,exclude:s});return c?(await $l.appendFile(t,`
|
|
@@ -152,7 +152,7 @@ enumerable options.
|
|
|
152
152
|
|
|
153
153
|
[\u2026 brief truncated]`}var PN,DN,qk,BN,jN,FN,Gk,Kk,zk=H(()=>{yp();PN=12,DN=2e3,qk=48e3,BN=30,jN=10;FN=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},Gk=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;Kk={failover:"**This is a reconstruction, not a checkpoint.** The node this Track lived on went offline without a clean handoff; bostrat assembled this brief from the durable event log. Treat every claim below as a lead, not a fact \u2014 **verify the repository state first** (git status, git log, the diff against the last pushed ref) before continuing work.","in-place":"**This is a reconstruction, not a checkpoint.** The previous lead ended without writing one (out of credits, capped, or unresponsive); bostrat assembled this status from the Track's event log. You are in the SAME live workspace \u2014 uncommitted work is present locally. **Run git status and git log first** and treat every claim below as a lead, not a fact.",get recover(){return this.failover},transfer:"**This Track was MOVED to a new machine while it was alive.** The previous node checkpointed and pushed its work as part of the move; this workspace was re-created from that push (uncommitted work re-applied when possible). **Run git status and git log to confirm what carried over**, then continue the objective below."}});import WN from"node:fs";import xr from"node:fs/promises";import vr from"node:path";function n0(e){let t=oo(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=Yk?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,Yk).toString("utf8").replace(/�+$/,"")}
|
|
154
154
|
|
|
155
|
-
[\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function ZN(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(Xk.test(s)){if(r.length>=c0)continue;let a=XN(s.replace(Xk,"").replace(/[.;,:]+$/,""),l0,YN);a&&r.push(a)}else r.length||n.push(s);let o=n.join(" ").replace(/\s+/g," ").replace(/[:\-–—]+$/,"").trim();if(!o)throw new Error("beat file has no summary line");return o.length>Jk&&(o=`${o.slice(0,Jk-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function u0(e,t,{timeoutMs:n=9e4}={}){let r=vr.join(t,VN),o=vr.join(r,zN);await xr.mkdir(r,{recursive:!0});let s=await Ml(o),a=await ke(e);if(!a)throw new Error(`session "${e}" not found`);return await Nl(e,a,JN(o)),await g0(o,s,n),ZN(await xr.readFile(o,"utf8"))}function d0(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===o0||n===i0;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(r0)||n===qN||r.startsWith(s0)||r.startsWith(a0)}function f0(e){let t=[];for(let r of e?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-QN;t.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&t.push({box:r.to,from:s,to:o})}let n=e?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&t.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&t.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),t}function p0(e,t){let n=[];for(let r of e?.boxes||[]){let o=t?.(r.name);o?.startedAt&&n.push({box:r.name,from:o.startedAt,to:o.finishedAt||Date.now()+1e12})}return n}function m0(e,{windows:t=[]}={}){if(d0(e.role,e.text))return!0;if(e.role!=="assistant"||!e.ts)return!1;for(let n of t)if(e.box===n.box&&e.ts>=n.from&&e.ts<=n.to)return!0;return!1}function Pl(e){return bp.get(e)||null}async function h0(e){let t=bp.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:vr.join(n.cwd,e0,t0)};return bp.set(e,r),nP(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function nP(e,t){e.step="summarize",await w0(e.name,t),e.step="clear";let n=await ke(e.name);await Nl(e.name,n,"/clear"),await vp(eP),e.step="resume",await Nl(e.name,n,KN),e.step="done",e.finishedAt=Date.now()}async function w0(e,t,{timeoutMs:n=tP}={}){let r=vr.join(t,e0),o=vr.join(r,t0);await xr.mkdir(r,{recursive:!0});let s=await Ml(o),a=await ke(e);await ue({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Nl(e,a,GN(o)),await g0(o,s,n),await ue({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Ml(o)});let i=await Ek(t,o,{exclude:u=>d0(u.role,u.text)});await ue({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await $({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await xr.readFile(o,"utf8");await $({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...n0(u),ts:Date.now()}})}catch{}}await kf(t);let l=await rP(r,o);return c&&await ib(c,l||o,{box:e,agent:a?.agent??null}),o}async function kp(e,{timeoutMs:t}={}){let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return w0(e,n.cwd,t?{timeoutMs:t}:void 0)}async function xp(e,t,{trackName:n="this Track"}={}){let r=await W({id:e,cwd:t}),o=Vk(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=vr.join(t,Zk);return await xr.mkdir(vr.dirname(s),{recursive:!0}),await xr.writeFile(s,o,"utf8"),await $({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...n0(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Zk}async function Ml(e){try{return(await xr.stat(e)).mtimeMs}catch{return 0}}async function g0(e,t,n){let r=Date.now()+n;for(;;){if(await Ml(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await vp(2e3)}}async function rP(e,t){try{if(!WN.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=vr.join(e,`${n}.md`);return await xr.copyFile(t,r),r}catch{return null}}function vp(e){return new Promise(t=>setTimeout(t,e))}function Qk(e){return e==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":""}async function Nl(e,t,n){if(t){let o=Qk(t.agent);await br({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ke(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await He(e,["Escape"],{kind:"drive-wipe"}),await vp(150),await ms(e,hl,{kind:"drive-wipe"}),await tt(e,n,{kind:"orchestration-drive",...gn(r.agent,n)}),await ai({sessionName:e,agent:r.agent,agentCmd:Qk(r.agent),text:n,flow:"orchestration-drive"})}var e0,t0,Yk,r0,o0,s0,qN,GN,KN,a0,i0,VN,zN,Jk,c0,l0,YN,JN,Xk,XN,QN,eP,tP,bp,Zk,Sp=H(()=>{ut();ni();hn();ri();ip();_k();Pa();ge();al();zk();e0=".bostrat/handoff",t0="latest.md",Yk=32*1024;r0="Checkpoint: write a work-in-progress handoff",o0="HANDOFF WRITTEN",s0="Resume from .bostrat/handoff/latest.md",qN="/clear",GN=e=>`${r0} to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file) so a FRESH Claude context with none of this conversation can resume seamlessly. Use these sections: Objective; Done (with file paths); In progress (exact state); Next steps (ordered); Key files & commands; Open decisions/blockers; Resume instruction (one line). Be concrete and self-contained \u2014 assume the reader has none of this chat. When the file is written, reply only with ${o0} and take no further action.`,KN=`${s0}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,a0="Beat: write a",i0="BEAT WRITTEN",VN=".bostrat/arc",zN="beat.txt",Jk=200,c0=4,l0=5,YN=36,JN=e=>`${a0} short summary of what this workstream accomplished, to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file). Format the file as: FIRST LINE = one sentence of at most 18 words, plain past tense, saying the outcome \u2014 no heading, no bullet, no trailing list. THEN, only if this workstream covered several separable pieces of work, up to ${c0} further lines, each starting with "- " and naming ONE piece in at most ${l0} words \u2014 a label, not a sentence (e.g. "- stale working flag on poll"). Write nothing else in the file. When the file is written, reply only with ${i0} and take no further action.`,Xk=/^(?:[-–—*•·]|\d+[.)])\s+/,XN=(e,t,n)=>{let r=e.split(/\s+/).filter(Boolean).slice(0,t).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};QN=6e5;eP=3500,tP=3e5,bp=new Map;Zk=".bostrat/handoff/status-latest.md"});function Tr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Dl.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let r=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return r}function k0(e){let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=r.map(o=>({...o,fromMs:Tr(o.from,"from",n),toMs:Tr(o.to,"to",n)}))}return t}function Ap(e){if(e==null)return Date.now();if(typeof e=="number")return Number.isFinite(e)?e:null;if(e instanceof Date){let n=e.getTime();return Number.isFinite(n)?n:null}let t=Date.parse(String(e));return Number.isFinite(t)?t:null}function sP(e){if(!e)return null;let t=String(e).trim();return Sr[t]?t:y0[t]?y0[t]:Object.keys(Sr).find(r=>t.startsWith(r))||null}function aP(e){if(!e||e===Sr)return oP;let t=b0.get(e);return t||(t=k0(e),b0.set(e,t)),t}function x0(e,t,n={}){let{table:r,speed:o}=n,s=aP(r),a=r&&r!==Sr?s[e]?e:null:sP(e);if(!a)return null;let i=Ap(t);if(i===null)return null;let c=s[a].find(l=>i>=l.fromMs&&i<=l.toMs)||null;return c?o==null||o==="standard"?c:o==="fast"&&c.fast?{...c.fast,fromMs:c.fromMs,toMs:c.toMs,verifiedAt:c.verifiedAt,note:c.note,speed:"fast"}:null:null}function yn(e,t={},n,r){let o=x0(e,n,r);return o?((t.input||0)*o.input+(t.output||0)*o.output+(t.cacheWrite||0)*o.cacheWrite+(t.cacheRead||0)*o.cacheRead)/1e6:0}function iP(e=Sr){let t=[];for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0){t.push(`${n}: must be a non-empty array of windows`);continue}let o;try{o=r.map(a=>({fromMs:Tr(a.from,"from",n),toMs:Tr(a.to,"to",n)}))}catch(a){t.push(String(a.message));continue}let s=r.filter(a=>a.to==null);s.length!==1?t.push(`${n}: expected exactly 1 open-ended window (to: null), found ${s.length}`):r[r.length-1].to!=null&&t.push(`${n}: the open-ended window must be last`),r[0].from!=null&&t.push(`${n}: the first window must be open at the start (from: null)`);for(let a=0;a<o.length;a++){if(o[a].fromMs>o[a].toMs&&t.push(`${n}: window ${a} ends before it begins (${r[a].from} \u2192 ${r[a].to})`),a===0)continue;let i=o[a-1],c=o[a];c.fromMs<=i.toMs?t.push(`${n}: windows ${a-1} and ${a} overlap (${r[a-1].to} / ${r[a].from})`):c.fromMs-i.toMs>2&&t.push(`${n}: gap between windows ${a-1} and ${a} (${r[a-1].to} \u2192 ${r[a].from})`),r[a].from||t.push(`${n}: window ${a} must declare a from bound`)}for(let a of r){a.note||t.push(`${n}: every window needs a note recording what was verified and when`),Dl.test(String(a.verifiedAt??""))||t.push(`${n}: every window needs a verifiedAt (YYYY-MM-DD) \u2014 the date its rates were checked against the vendor's published page`);for(let i of["input","output","cacheWrite","cacheRead"])(typeof a[i]!="number"||!Number.isFinite(a[i])||a[i]<0)&&t.push(`${n}: window ${i} must be a non-negative number, got ${JSON.stringify(a[i])}`),a.fast&&(typeof a.fast[i]!="number"||!Number.isFinite(a.fast[i])||a.fast[i]<0)&&t.push(`${n}: fast variant ${i} must be a non-negative number, got ${JSON.stringify(a.fast?.[i])}`)}}return t}function lP({now:e=Date.now(),table:t=Sr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...cP,...n},a=[],i=Ap(e);if(i===null)return[`pricingFreshness: unparseable now ${JSON.stringify(e)}`];for(let[c,l]of Object.entries(t)){if(!Array.isArray(l))continue;let u;try{u=l.map(f=>({...f,fromMs:Tr(f.from,"from",c),toMs:Tr(f.to,"to",c),verifiedMs:Dl.test(String(f.verifiedAt??""))?Date.parse(`${f.verifiedAt}T00:00:00.000Z`):NaN}))}catch(f){a.push(String(f.message));continue}for(let f of u){if(!Number.isFinite(f.verifiedMs)){a.push(`${c}: window ${f.from??"\u2026"} \u2192 ${f.to??"now"} has no verifiedAt`);continue}let d=i>=f.fromMs&&i<=f.toMs,p=f.fromMs>i&&f.fromMs-i<=o*Tp;d&&i-f.verifiedMs>r*Tp&&a.push(`${c}: current rate last verified ${f.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),p&&f.fromMs-f.verifiedMs>s*Tp&&a.push(`${c}: scheduled rate change on ${f.from} was last verified ${f.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function As({now:e=Date.now(),table:t=Sr,...n}={}){let r=Ap(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Tr(l.from,"from",i),f=Tr(l.to,"to",i);r>=u&&r<=f&&Dl.test(String(l.verifiedAt??""))&&(!o||l.verifiedAt<o)&&(o=l.verifiedAt),u>r&&s.push({model:i,from:l.from,verifiedAt:l.verifiedAt??null})}s.sort((i,c)=>i.from<c.from?-1:1);let a=[...iP(t),...lP({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Sr,y0,Dl,oP,b0,v0,cP,Tp,Fn=H(()=>{Sr={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:null,input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},y0={opus:"claude-opus-5",opusplan:"claude-opus-5",default:"claude-opus-5",sonnet:"claude-sonnet-5",haiku:"claude-haiku-4-5",fable:"claude-fable-5","gpt-5.6":"gpt-5.6-sol"},Dl=/^\d{4}-\d{2}-\d{2}$/;oP=k0(Sr);b0=new WeakMap;v0=(e,t,n)=>x0(e,t,n)!==null;cP=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Tp=864e5});function uP(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function T0(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Ut(e){let t=e.payload?.model||"unknown",n=uP(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.payload?.speed||void 0,s=e.source==="vendor",a=r,i=!1;if(n&&!s){let u=yn(t,n,e.ts,o?{speed:o}:void 0);u>0&&(a=u,i=Math.abs(u-r)>1e-9)}let c=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,l=!a&&c>0&&!v0(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Ar(e,{boxLabels:t={}}={}){let n=(e||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=S0();for(let d of n){let{usd:p,model:h,tokens:w,repriced:g,unpriced:b,asRecorded:v}=Ut(d);i+=v;let x=d.provider||"unknown",I=d.boxId||"unattributed";if(g&&c++,b&&(l++,u.add(h)),a+=p,T0(f,w),r[h]||={usd:0,tokens:S0(),events:0},r[h].usd+=p,r[h].events+=1,T0(r[h].tokens,w),o[x]||={usd:0,events:0},o[x].usd+=p,o[x].events+=1,s[I]||={usd:0,events:0,provider:x,models:new Set,label:t[I]||I},s[I].usd+=p,s[I].events+=1,h!=="unknown"&&s[I].models.add(h),d.epoch!=null){let P=(s[I].epochs||={})[d.epoch]||={usd:0,events:0,provider:x,models:new Set};P.usd+=p,P.events+=1,P.provider=x,h!=="unknown"&&P.models.add(h)}}return{totalUsd:Es(a),asRecordedUsd:Es(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Bl(r,d=>({...d,usd:Es(d.usd)})),byProvider:Bl(o,d=>({...d,usd:Es(d.usd)})),byBox:Bl(s,d=>({usd:Es(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:Bl(d.epochs,p=>({usd:Es(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var S0,Es,Bl,Er=H(()=>{Fn();S0=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});Es=e=>Math.round(e*1e4)/1e4,Bl=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function dP(e){if(!Number.isFinite(e)||e<=0)return null;let t=e/864e5;if(t>=1)return`${Math.round(t)}d`;let n=e/36e5;return n>=1?`${Math.round(n)}h`:`${Math.max(1,Math.round(e/6e4))}m`}function A0(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Ep(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Ep(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${Ep(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Ar(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?dP(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Ep,E0=H(()=>{Er();Ep=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as fP}from"node:child_process";import{promisify as pP}from"node:util";import{randomUUID as mP}from"node:crypto";async function _p(e,t){let n=Date.now()+t;for(;;){if(await Bn(e))return!0;if(Date.now()>n)return!1;await di(wP)}}async function yP(e,t){let n=I0[t]||I0.default;n.escape&&(await He(e,["Escape"],{kind:"swap-exit"}),await di(150)),n.wipe&&await ms(e,hl,{kind:"swap-exit"}),await wl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=gn(t).submitDelayMs||0;await di(Math.max(r,250)),await He(e,["Enter"],{kind:"swap-exit"})}async function $0(e,t){try{let{stdout:n}=await fo(J,Z("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function R0(e){await fo(J,Z("respawn-pane","-k","-t",e))}async function Ip(e,t={}){if(!Le(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ke(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||hr(n),a=Number(t.exitTimeoutMs)||hP;await ue({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Bn(e)&&(await yP(e,o),!await _p(e,a)&&(i=!0,await ue({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await R0(e),!await _p(e,_0))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&so(n),l=c?Uc():null,u=await $0(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await fo(J,Z("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await fo(J,Z("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?ll(g,l):g}if(f&&!i&&(await R0(e),!await _p(e,_0)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||mP(),h=d?n:Ga(n,p,e),w=d?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return c&&await cr(r.cwd),s==="codex"&&await ts(r.cwd),s==="cursor"&&await ns(r.cwd),await ao(e),await fo(J,Z("set-option","-t",e,"@bostrat-sid",p)),await fo(J,Z("set-option","-t",e,"@bostrat-agent",s)),await di(gP),c&&qa().length&&(await $0(e,Wa)||await fo(J,Z("set-environment","-t",e,Wa,"1")).catch(()=>{}),await tt(e,`export ${Wa}=1`,{kind:"swap-env"}),await di(150)),await tt(e,h,{kind:"swap-launch"}),await ue({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:e,cwd:r.cwd,sessionId:p,agent:s,pinned:w,forced:i,envRespawned:f,launchCmd:h}}var fo,di,hP,_0,wP,gP,I0,O0=H(()=>{ut();Ia();Wc();qc();ri();hn();fo=pP(fP),di=e=>new Promise(t=>setTimeout(t,e)),hP=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,_0=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,wP=250,gP=400,I0={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});async function C0(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await At(e,t)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
|
|
155
|
+
[\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function ZN(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(Xk.test(s)){if(r.length>=c0)continue;let a=XN(s.replace(Xk,"").replace(/[.;,:]+$/,""),l0,YN);a&&r.push(a)}else r.length||n.push(s);let o=n.join(" ").replace(/\s+/g," ").replace(/[:\-–—]+$/,"").trim();if(!o)throw new Error("beat file has no summary line");return o.length>Jk&&(o=`${o.slice(0,Jk-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function u0(e,t,{timeoutMs:n=9e4}={}){let r=vr.join(t,VN),o=vr.join(r,zN);await xr.mkdir(r,{recursive:!0});let s=await Ml(o),a=await ke(e);if(!a)throw new Error(`session "${e}" not found`);return await Nl(e,a,JN(o)),await g0(o,s,n),ZN(await xr.readFile(o,"utf8"))}function d0(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===o0||n===i0;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(r0)||n===qN||r.startsWith(s0)||r.startsWith(a0)}function f0(e){let t=[];for(let r of e?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-QN;t.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&t.push({box:r.to,from:s,to:o})}let n=e?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&t.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&t.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),t}function p0(e,t){let n=[];for(let r of e?.boxes||[]){let o=t?.(r.name);o?.startedAt&&n.push({box:r.name,from:o.startedAt,to:o.finishedAt||Date.now()+1e12})}return n}function m0(e,{windows:t=[]}={}){if(d0(e.role,e.text))return!0;if(e.role!=="assistant"||!e.ts)return!1;for(let n of t)if(e.box===n.box&&e.ts>=n.from&&e.ts<=n.to)return!0;return!1}function Pl(e){return bp.get(e)||null}async function h0(e){let t=bp.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:vr.join(n.cwd,e0,t0)};return bp.set(e,r),nP(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function nP(e,t){e.step="summarize",await w0(e.name,t),e.step="clear";let n=await ke(e.name);await Nl(e.name,n,"/clear"),await vp(eP),e.step="resume",await Nl(e.name,n,KN),e.step="done",e.finishedAt=Date.now()}async function w0(e,t,{timeoutMs:n=tP}={}){let r=vr.join(t,e0),o=vr.join(r,t0);await xr.mkdir(r,{recursive:!0});let s=await Ml(o),a=await ke(e);await ue({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Nl(e,a,GN(o)),await g0(o,s,n),await ue({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Ml(o)});let i=await Ek(t,o,{exclude:u=>d0(u.role,u.text)});await ue({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await $({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await xr.readFile(o,"utf8");await $({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...n0(u),ts:Date.now()}})}catch{}}await kf(t);let l=await rP(r,o);return c&&await ib(c,l||o,{box:e,agent:a?.agent??null}),o}async function kp(e,{timeoutMs:t}={}){let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return w0(e,n.cwd,t?{timeoutMs:t}:void 0)}async function xp(e,t,{trackName:n="this Track"}={}){let r=await W({id:e,cwd:t}),o=Vk(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=vr.join(t,Zk);return await xr.mkdir(vr.dirname(s),{recursive:!0}),await xr.writeFile(s,o,"utf8"),await $({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...n0(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Zk}async function Ml(e){try{return(await xr.stat(e)).mtimeMs}catch{return 0}}async function g0(e,t,n){let r=Date.now()+n;for(;;){if(await Ml(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await vp(2e3)}}async function rP(e,t){try{if(!WN.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=vr.join(e,`${n}.md`);return await xr.copyFile(t,r),r}catch{return null}}function vp(e){return new Promise(t=>setTimeout(t,e))}function Qk(e){return e==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":""}async function Nl(e,t,n){if(t){let o=Qk(t.agent);await br({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ke(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await He(e,["Escape"],{kind:"drive-wipe"}),await vp(150),await ms(e,hl,{kind:"drive-wipe"}),await tt(e,n,{kind:"orchestration-drive",...gn(r.agent,n)}),await ai({sessionName:e,agent:r.agent,agentCmd:Qk(r.agent),text:n,flow:"orchestration-drive"})}var e0,t0,Yk,r0,o0,s0,qN,GN,KN,a0,i0,VN,zN,Jk,c0,l0,YN,JN,Xk,XN,QN,eP,tP,bp,Zk,Sp=H(()=>{ut();ni();hn();ri();ip();_k();Pa();ge();al();zk();e0=".bostrat/handoff",t0="latest.md",Yk=32*1024;r0="Checkpoint: write a work-in-progress handoff",o0="HANDOFF WRITTEN",s0="Resume from .bostrat/handoff/latest.md",qN="/clear",GN=e=>`${r0} to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file) so a FRESH Claude context with none of this conversation can resume seamlessly. Use these sections: Objective; Done (with file paths); In progress (exact state); Next steps (ordered); Key files & commands; Open decisions/blockers; Resume instruction (one line). Be concrete and self-contained \u2014 assume the reader has none of this chat. When the file is written, reply only with ${o0} and take no further action.`,KN=`${s0}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,a0="Beat: write a",i0="BEAT WRITTEN",VN=".bostrat/arc",zN="beat.txt",Jk=200,c0=4,l0=5,YN=36,JN=e=>`${a0} short summary of what this workstream accomplished, to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file). Format the file as: FIRST LINE = one sentence of at most 18 words, plain past tense, saying the outcome \u2014 no heading, no bullet, no trailing list. THEN, only if this workstream covered several separable pieces of work, up to ${c0} further lines, each starting with "- " and naming ONE piece in at most ${l0} words \u2014 a label, not a sentence (e.g. "- stale working flag on poll"). Write nothing else in the file. When the file is written, reply only with ${i0} and take no further action.`,Xk=/^(?:[-–—*•·]|\d+[.)])\s+/,XN=(e,t,n)=>{let r=e.split(/\s+/).filter(Boolean).slice(0,t).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};QN=6e5;eP=3500,tP=3e5,bp=new Map;Zk=".bostrat/handoff/status-latest.md"});function Tr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Dl.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let r=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return r}function k0(e){let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=r.map(o=>({...o,fromMs:Tr(o.from,"from",n),toMs:Tr(o.to,"to",n)}))}return t}function Ap(e){if(e==null)return Date.now();if(typeof e=="number")return Number.isFinite(e)?e:null;if(e instanceof Date){let n=e.getTime();return Number.isFinite(n)?n:null}let t=Date.parse(String(e));return Number.isFinite(t)?t:null}function sP(e){if(!e)return null;let t=String(e).trim();return Sr[t]?t:y0[t]?y0[t]:Object.keys(Sr).find(r=>t.startsWith(r))||null}function aP(e){if(!e||e===Sr)return oP;let t=b0.get(e);return t||(t=k0(e),b0.set(e,t)),t}function x0(e,t,n={}){let{table:r,speed:o}=n,s=aP(r),a=r&&r!==Sr?s[e]?e:null:sP(e);if(!a)return null;let i=Ap(t);if(i===null)return null;let c=s[a].find(l=>i>=l.fromMs&&i<=l.toMs)||null;return c?o==null||o==="standard"?c:o==="fast"&&c.fast?{...c.fast,fromMs:c.fromMs,toMs:c.toMs,verifiedAt:c.verifiedAt,note:c.note,speed:"fast"}:null:null}function yn(e,t={},n,r){let o=x0(e,n,r);return o?((t.input||0)*o.input+(t.output||0)*o.output+(t.cacheWrite||0)*o.cacheWrite+(t.cacheRead||0)*o.cacheRead)/1e6:0}function iP(e=Sr){let t=[];for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0){t.push(`${n}: must be a non-empty array of windows`);continue}let o;try{o=r.map(a=>({fromMs:Tr(a.from,"from",n),toMs:Tr(a.to,"to",n)}))}catch(a){t.push(String(a.message));continue}let s=r.filter(a=>a.to==null);s.length!==1?t.push(`${n}: expected exactly 1 open-ended window (to: null), found ${s.length}`):r[r.length-1].to!=null&&t.push(`${n}: the open-ended window must be last`),r[0].from!=null&&t.push(`${n}: the first window must be open at the start (from: null)`);for(let a=0;a<o.length;a++){if(o[a].fromMs>o[a].toMs&&t.push(`${n}: window ${a} ends before it begins (${r[a].from} \u2192 ${r[a].to})`),a===0)continue;let i=o[a-1],c=o[a];c.fromMs<=i.toMs?t.push(`${n}: windows ${a-1} and ${a} overlap (${r[a-1].to} / ${r[a].from})`):c.fromMs-i.toMs>2&&t.push(`${n}: gap between windows ${a-1} and ${a} (${r[a-1].to} \u2192 ${r[a].from})`),r[a].from||t.push(`${n}: window ${a} must declare a from bound`)}for(let a of r){a.note||t.push(`${n}: every window needs a note recording what was verified and when`),Dl.test(String(a.verifiedAt??""))||t.push(`${n}: every window needs a verifiedAt (YYYY-MM-DD) \u2014 the date its rates were checked against the vendor's published page`);for(let i of["input","output","cacheWrite","cacheRead"])(typeof a[i]!="number"||!Number.isFinite(a[i])||a[i]<0)&&t.push(`${n}: window ${i} must be a non-negative number, got ${JSON.stringify(a[i])}`),a.fast&&(typeof a.fast[i]!="number"||!Number.isFinite(a.fast[i])||a.fast[i]<0)&&t.push(`${n}: fast variant ${i} must be a non-negative number, got ${JSON.stringify(a.fast?.[i])}`)}}return t}function lP({now:e=Date.now(),table:t=Sr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...cP,...n},a=[],i=Ap(e);if(i===null)return[`pricingFreshness: unparseable now ${JSON.stringify(e)}`];for(let[c,l]of Object.entries(t)){if(!Array.isArray(l))continue;let u;try{u=l.map(f=>({...f,fromMs:Tr(f.from,"from",c),toMs:Tr(f.to,"to",c),verifiedMs:Dl.test(String(f.verifiedAt??""))?Date.parse(`${f.verifiedAt}T00:00:00.000Z`):NaN}))}catch(f){a.push(String(f.message));continue}for(let f of u){if(!Number.isFinite(f.verifiedMs)){a.push(`${c}: window ${f.from??"\u2026"} \u2192 ${f.to??"now"} has no verifiedAt`);continue}let d=i>=f.fromMs&&i<=f.toMs,p=f.fromMs>i&&f.fromMs-i<=o*Tp;d&&i-f.verifiedMs>r*Tp&&a.push(`${c}: current rate last verified ${f.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),p&&f.fromMs-f.verifiedMs>s*Tp&&a.push(`${c}: scheduled rate change on ${f.from} was last verified ${f.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function As({now:e=Date.now(),table:t=Sr,...n}={}){let r=Ap(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Tr(l.from,"from",i),f=Tr(l.to,"to",i);r>=u&&r<=f&&Dl.test(String(l.verifiedAt??""))&&(!o||l.verifiedAt<o)&&(o=l.verifiedAt),u>r&&s.push({model:i,from:l.from,verifiedAt:l.verifiedAt??null})}s.sort((i,c)=>i.from<c.from?-1:1);let a=[...iP(t),...lP({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Sr,y0,Dl,oP,b0,v0,cP,Tp,Fn=H(()=>{Sr={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:"2026-08-23",input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL). Superseded 2026-08-24 by the vendor's promotional cut (window below)."},{from:"2026-08-24",to:null,input:4,output:20,cacheWrite:5,cacheRead:.4,verifiedAt:"2026-08-24",note:"promotional pricing verified 2026-08-24 (developers.openai.com pricing), 'at least through November 21, 2026'; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},y0={opus:"claude-opus-5",opusplan:"claude-opus-5",default:"claude-opus-5",sonnet:"claude-sonnet-5",haiku:"claude-haiku-4-5",fable:"claude-fable-5","gpt-5.6":"gpt-5.6-sol"},Dl=/^\d{4}-\d{2}-\d{2}$/;oP=k0(Sr);b0=new WeakMap;v0=(e,t,n)=>x0(e,t,n)!==null;cP=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Tp=864e5});function uP(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function T0(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Ut(e){let t=e.payload?.model||"unknown",n=uP(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.payload?.speed||void 0,s=e.source==="vendor",a=r,i=!1;if(n&&!s){let u=yn(t,n,e.ts,o?{speed:o}:void 0);u>0&&(a=u,i=Math.abs(u-r)>1e-9)}let c=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,l=!a&&c>0&&!v0(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Ar(e,{boxLabels:t={}}={}){let n=(e||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=S0();for(let d of n){let{usd:p,model:h,tokens:w,repriced:g,unpriced:b,asRecorded:v}=Ut(d);i+=v;let x=d.provider||"unknown",I=d.boxId||"unattributed";if(g&&c++,b&&(l++,u.add(h)),a+=p,T0(f,w),r[h]||={usd:0,tokens:S0(),events:0},r[h].usd+=p,r[h].events+=1,T0(r[h].tokens,w),o[x]||={usd:0,events:0},o[x].usd+=p,o[x].events+=1,s[I]||={usd:0,events:0,provider:x,models:new Set,label:t[I]||I},s[I].usd+=p,s[I].events+=1,h!=="unknown"&&s[I].models.add(h),d.epoch!=null){let P=(s[I].epochs||={})[d.epoch]||={usd:0,events:0,provider:x,models:new Set};P.usd+=p,P.events+=1,P.provider=x,h!=="unknown"&&P.models.add(h)}}return{totalUsd:Es(a),asRecordedUsd:Es(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Bl(r,d=>({...d,usd:Es(d.usd)})),byProvider:Bl(o,d=>({...d,usd:Es(d.usd)})),byBox:Bl(s,d=>({usd:Es(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:Bl(d.epochs,p=>({usd:Es(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var S0,Es,Bl,Er=H(()=>{Fn();S0=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});Es=e=>Math.round(e*1e4)/1e4,Bl=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function dP(e){if(!Number.isFinite(e)||e<=0)return null;let t=e/864e5;if(t>=1)return`${Math.round(t)}d`;let n=e/36e5;return n>=1?`${Math.round(n)}h`:`${Math.max(1,Math.round(e/6e4))}m`}function A0(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Ep(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Ep(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${Ep(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Ar(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?dP(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Ep,E0=H(()=>{Er();Ep=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as fP}from"node:child_process";import{promisify as pP}from"node:util";import{randomUUID as mP}from"node:crypto";async function _p(e,t){let n=Date.now()+t;for(;;){if(await Bn(e))return!0;if(Date.now()>n)return!1;await di(wP)}}async function yP(e,t){let n=I0[t]||I0.default;n.escape&&(await He(e,["Escape"],{kind:"swap-exit"}),await di(150)),n.wipe&&await ms(e,hl,{kind:"swap-exit"}),await wl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=gn(t).submitDelayMs||0;await di(Math.max(r,250)),await He(e,["Enter"],{kind:"swap-exit"})}async function $0(e,t){try{let{stdout:n}=await fo(J,Z("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function R0(e){await fo(J,Z("respawn-pane","-k","-t",e))}async function Ip(e,t={}){if(!Le(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ke(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||hr(n),a=Number(t.exitTimeoutMs)||hP;await ue({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Bn(e)&&(await yP(e,o),!await _p(e,a)&&(i=!0,await ue({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await R0(e),!await _p(e,_0))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&so(n),l=c?Uc():null,u=await $0(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await fo(J,Z("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await fo(J,Z("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?ll(g,l):g}if(f&&!i&&(await R0(e),!await _p(e,_0)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||mP(),h=d?n:Ga(n,p,e),w=d?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return c&&await cr(r.cwd),s==="codex"&&await ts(r.cwd),s==="cursor"&&await ns(r.cwd),await ao(e),await fo(J,Z("set-option","-t",e,"@bostrat-sid",p)),await fo(J,Z("set-option","-t",e,"@bostrat-agent",s)),await di(gP),c&&qa().length&&(await $0(e,Wa)||await fo(J,Z("set-environment","-t",e,Wa,"1")).catch(()=>{}),await tt(e,`export ${Wa}=1`,{kind:"swap-env"}),await di(150)),await tt(e,h,{kind:"swap-launch"}),await ue({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:e,cwd:r.cwd,sessionId:p,agent:s,pinned:w,forced:i,envRespawned:f,launchCmd:h}}var fo,di,hP,_0,wP,gP,I0,O0=H(()=>{ut();Ia();Wc();qc();ri();hn();fo=pP(fP),di=e=>new Promise(t=>setTimeout(t,e)),hP=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,_0=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,wP=250,gP=400,I0={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});async function C0(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await At(e,t)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
|
|
156
156
|
`)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let f=l.timestamp?Date.parse(l.timestamp):null;for(let d of u)if(!(!d||typeof d!="object"))if(d.type==="tool_use"&&d.id){if(d.name==="Agent"){let p=d.input||{};o.set(d.id,{id:d.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:f,proven:!1})}else if(d.name==="Bash"&&d.input?.run_in_background===!0){let p=String(d.input.command||"").trim();o.set(d.id,{id:d.id,kind:"command",name:String(d.input.description||"").trim()||(p?ys(p):null),detail:p?ys(p):null,ts:f,proven:!0})}}else d.type==="tool_result"&&d.tool_use_id&&bP.test(kP(d.content))&&s.add(d.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var bP,kP,M0=H(()=>{tn();bs();bP=/^Async (?:agent|task) launched/i,kP=e=>{if(typeof e=="string")return e.trim();if(!Array.isArray(e))return"";let t=e.find(n=>n&&n.type==="text"&&typeof n.text=="string");return t?t.text.trim():""}});function _r(e,t){if(!e)return null;let n=String(e);if(t){let o=t.endsWith("/")?t:`${t}/`;if(n===t)return".";if(n.startsWith(o))return n.slice(o.length)||"."}let r=n.split("/").filter(Boolean);return n.startsWith("/")&&r.length>2?r.slice(-2).join("/"):n}function xP(e){let t=typeof e=="string"?e:String(e?.patch??e?.input??""),n=[];for(let r of t.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function N0(e,t,n){switch(e){case"Shell":{let r=String(t?.command||"").trim();return r?{command:r,description:String(t?.description||"").trim()}:null}case"Read":{let r=t?.path;if(!r)return null;let o=Number(t?.offset)||null,s=o&&Number(t?.limit)?o+Number(t.limit)-1:null;return{command:nn(`read ${_r(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${_s(r)}`:`Read ${_s(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?_r(t.path,n):null,s=t?.glob?` --glob ${$p(t.glob)}`:"",a=nn(String(r),40);return{command:nn(`grep ${$p(r)}${o&&o!=="."?` ${o}`:""}${s}`,140),description:o&&o!=="."?`Search for \u201C${a}\u201D in ${o}`:`Search for \u201C${a}\u201D`}}case"Glob":{let r=t?.glob_pattern;if(!r)return null;let o=t?.target_directory?_r(t.target_directory,n):null;return{command:nn(`glob ${$p(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${nn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:nn(`edit ${_r(t.path,n)}`,140),description:`Edit ${_s(t.path)}`}:null;case"Write":return t?.path?{command:nn(`write ${_r(t.path,n)}`,140),description:`Write ${_s(t.path)}`}:null;case"Delete":return t?.path?{command:nn(`delete ${_r(t.path,n)}`,140),description:`Delete ${_s(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>_r(s,n)).filter(Boolean);return{command:nn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=xP(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:nn(`apply_patch ${_r(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${_s(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:nn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var jl,nn,_s,$p,P0=H(()=>{jl=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),nn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,_s=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);$p=e=>`"${String(e).replace(/"/g,'\\"')}"`});import fi from"node:fs";import vP from"node:fs/promises";import po from"node:path";import SP from"node:os";import TP from"node:crypto";import AP from"node:zlib";function j0(e){let t=TP.createHash("md5").update(String(e)).digest("hex");return po.join(EP,t)}function L0(e){try{let t=JSON.parse(fi.readFileSync(po.join(e,"meta.json"),"utf8"));return{createdAtMs:Number(t.createdAtMs)||null,updatedAtMs:Number(t.updatedAtMs)||Number(t.createdAtMs)||null,hasConversation:t.hasConversation===!0}}catch{return null}}function _P(e){let t=j0(e),n;try{n=fi.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=po.join(t,o.name),a=po.join(s,"store.db");if(!fi.existsSync(a))continue;let i=L0(s);if(!i)continue;let c={id:o.name,dir:s,store:a,...i};(!r||c.hasConversation&&!r.hasConversation||c.hasConversation===r.hasConversation&&(c.updatedAtMs||0)>(r.updatedAtMs||0))&&(r=c)}return r}function Ll(e,t){if(!e)return null;if(t){let n=po.join(j0(e),t),r=po.join(n,"store.db");if(fi.existsSync(r))return{id:t,dir:n,store:r,...L0(n)||{createdAtMs:null,updatedAtMs:null}}}return _P(e)}function D0(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function IP(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=AP.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function $P(e){let t=[],n=0,r=e.length,o=()=>{let s=0,a=0;for(;n<r;){let i=e[n++];if(s+=(i&127)*2**a,!(i&128))break;a+=7}return s};for(;n<r;){let s=o(),a=s>>>3,i=s&7;if(i===2){let c=o(),l=e.subarray(n,n+c);n+=c,a===1&&c===32&&t.push(l.toString("hex"))}else if(i===0)o();else if(i===5)n+=4;else if(i===1)n+=8;else break}return t}function RP(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!jl.has(r.toolName))continue;let o=N0(r.toolName,r.args,t);!o||!o.command||n.push({id:r.toolCallId||null,tool:r.toolName,command:o.command,description:o.description||""})}return n}async function Rp(e,t){if(!B0)return Is;let{DatabaseSync:n}=B0,r;try{r=new n(e,{readOnly:!0})}catch{return Is}try{let o=r.prepare("SELECT value FROM meta WHERE key = '0'").get()||r.prepare("SELECT value FROM meta LIMIT 1").get();if(!o)return Is;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Is}let a=s.lastUsedModel||null,i=s.latestRootBlobId?D0(r,s.latestRootBlobId):null;if(!i)return{...Is,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of $P(i)){let h=IP(D0(r,p));if(!h)continue;let w=h.providerOptions?.cursor;if(w?.requestId&&d.push(w.requestId),w?.modelProviderMessageId&&d.push(w.modelProviderMessageId),h.role!=="assistant")continue;if(Array.isArray(h.content))for(let v of h.content){let x=v?.providerOptions?.cursor?.modelName;x&&(f=x)}l.push(...RP(h.content,t).map((v,x)=>({...v,id:v.id||`${p}:${x}`}))),u.push(...CP(h.content));let g=OP(h.content);if(!g)continue;let b=[...new Set(u)];u=[],c.push({id:p,text:g,tools:b.length?b:void 0,commands:l,model:f}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:d}}catch{return Is}finally{try{r.close()}catch{}}}function F0(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(fi.statSync(e.store).mtimeMs)}catch{n=Date.now()}let r=e.createdAtMs;(!r||r>n)&&(r=n-t*1e3);let o=Math.max(0,n-r);return{end:n,tsAt:s=>Math.round(r+o*(s+1)/t)}}async function U0(e,t,{limit:n=80}={}){let r=Ll(e,t);if(!r)return[];let{turns:o,model:s}=await Rp(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=F0(r,a.length);return a.map((c,l)=>({role:"assistant",text:c.text,tools:c.tools,ts:i(l),model:c.model||s,sourceId:c.id}))}async function H0(e,t){let n=Ll(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await Rp(n.store,e);return{chatId:n.id,requestIds:o,models:[...new Set(r.map(a=>a.model).filter(Boolean))],configuredModel:s,updatedAtMs:n.updatedAtMs||null}}async function W0(e,t,{limit:n=80}={}){let r=Ll(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await Rp(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=F0(r,a.length||1),l=[];a.forEach((u,f)=>{for(let d of u.commands)l.push({...d,summary:yr(d.command,d.description),ts:c(f)})});for(let u of s)l.push({...u,summary:yr(u.command,u.description),ts:i+1});return l}async function q0(e,t){let n=Ll(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await vP.stat(n.store)).mtimeMs)}catch{return null}}var EP,OP,CP,B0,Is,Op=H(()=>{bs();P0();EP=process.env.BOSTRAT_CURSOR_CHATS||po.join(SP.homedir(),".cursor","chats");OP=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
|
|
157
157
|
`).trim():"",CP=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],B0=process.getBuiltinModule?.("node:sqlite"),Is={turns:[],trailingCommands:[],model:null,requestIds:[]}});import MP from"node:fs/promises";function Pp(e){return G0.set(e.agent,e),e}function pi(e){return G0.get(e)||NP}async function Bp(e,t={}){return(await pi(e.agent).readMessages(e,t)).map(Dp(e))}async function K0(e,t={}){return(await pi(e.agent).readCommands(e,t)).map(Dp(e))}async function V0(e,t={}){return(await pi(e.agent).readJobs(e,t)).map(Dp(e))}var $s,Cp,Mp,Np,NP,G0,Dp,z0=H(()=>{tn();bl();bs();M0();Op();lo();$s=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},Cp=class extends $s{transcript(t){return!t?.cwd||!t?.sessionId?null:en(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?zf(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?jb(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?C0(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await MP.stat(n)).mtimeMs)}catch{return null}}},Mp=class extends $s{async readMessages(t,n){return U0(t.cwd,t.sessionId,n)}async readCommands(t,n){return W0(t.cwd,t.sessionId,n)}async updatedAt(t){return q0(t.cwd,t.sessionId)}},Np=class extends $s{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Hb(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Wb(t.cwd,this.sessionId(t),n)}async updatedAt(t){return qb(t.cwd,this.sessionId(t))}},NP=new $s("unknown"),G0=new Map;Pp(new Cp("claude",Wf));Pp(new Mp("cursor",jl));Pp(new Np("codex",Za));Dp=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function wo(e){let t=e.search(Up);return(t>=0?e.slice(0,t):e).trim()}function PP(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function DP(e){let t=String(e).trim();return!!(!t||ho.test(e)||Up.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function BP(e,t=""){let n=[],r=/([☐☒])\s+([^☐☒←→✔]+)/g,o;for(;(o=r.exec(e))!==null;)n.push({label:o[2].trim(),answered:o[1]==="\u2612",current:!1});if(!n.length)return null;let s=jP(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function jP(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(d=>d.length>3&&n.includes(d)).length;if(u)return u;let f=l.slice(0,8).trim();return f.length>=4&&n.includes(f)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function J0(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function LP(e,t=""){let n=String(e);if(!Z0.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
158
158
|
`),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let f=r[u].match(mo);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!ho.test(r[u])&&a.push(d)}}if(s.length<2)return null;let i=s.map(u=>({label:wo(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=["Switch model?",...a].join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:model-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Model",multiSelect:!1,options:i}]}}function UP(e,t=""){let n=String(e).replace(/\r/g,"").split(`
|
|
@@ -194,7 +194,7 @@ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.t
|
|
|
194
194
|
${h}`,v=await a(e.id,b,{kind:"followup-go"});return await p({action:"sent",...n?{followupId:n}:{armId:r},label:w,...o?{promoted:String(o)}:{},...g?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:g,queued:!!v?.queued}}async function WB(e,t,{changedRepos:n=null,probe:r=du,branchOf:o=Dr}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),b=s.repos?g.filter(v=>s.repos.includes(v.name)):g;l=b.length?b.map(v=>({name:v.name,slug:v.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,f=s.rebase==="offered",d=await r(e,{branch:u,rebase:f}).catch(()=>null),p=[...f?["rebase"]:[],...s.actions].filter(g=>Rr.includes(g));if(d&&d.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:d};let h=Vs(),w=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await $(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:h,ts:Date.now(),excerpt:w,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:d?.available,defaults:d?d.defaults.filter(g=>p.includes(g)||g==="rebase"):void 0,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||l,offered:d?p.filter(g=>d.available.includes(g)):p,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:h,branch:u,offered:p,available:d?.available??null,prState:d?.prState??null}}function US(e){let t=!1;for(let n of e)n.type==="pr.offered"&&(n.source==="cli"||n.payload?.via==="cli")?t=!0:(n.type==="turn.user"&&!n.payload?.kind||n.type==="pr.offer.answered")&&(t=!1);return t}function HS(e){let t=null;for(let n of e){let r=n.payload||{};n.type==="pr.offer.answered"?t=r.action&&r.action!=="dismiss"&&r.action!=="pr-exists"?r.offerId:null:n.type==="pr.exists.answered"?t=r.choice&&r.choice!=="dismiss"?r.offerId??t:null:(n.type==="turn.user"&&!r.kind||n.type==="followup.offered"&&r.trigger==="ship.done"&&r.context?.shipOfferId&&r.context.shipOfferId===t)&&(t=null)}return t}async function WS(e,{pull:t=Oi}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await W({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?Tu(s):[]}}var OS,CS,NB,MS,PB,Km,DB,qm,Gm,Ks,BB,Vm,UB,Au=H(()=>{ge();xo();Sm();Io();RS();OS=60,CS=8*1024,NB=200,MS=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],PB=MS.filter(e=>e!=="now"&&e!=="track.opened"),Km={now:"now","pr.merged":"after merge","ship.done":"after ship","pr.opened":"after PR opens","checks.green":"after CI goes green","track.opened":"when a Track opens"},DB=3,qm=["commit","push","pr"];Gm=e=>MB("sha256").update(String(e)).digest("hex").slice(0,16),Ks=e=>typeof e=="string"?e.trim():"",BB=[[/(^|[^\w&])#\d+\b/,"a PR/issue number"],[/https?:\/\/\S+/i,"a URL"],[/\b[0-9a-f]{7,40}\b/i,"a commit SHA"],[/\bv\d+\.\d+\.\d+\b/,"a release tag"]];Vm=e=>String(e?.name||"").startsWith("\u21BB");UB=e=>String(e||"").split(`
|
|
195
195
|
`).slice(0,3).join(`
|
|
196
196
|
`).slice(0,400)});import{randomUUID as qB}from"node:crypto";function Mi(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function qS(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function GS(e){return`job|${e.box}|id:${e.id}`}async function Ym(e){return zm.has(e.id)?zm.get(e.id):(Eu.has(e.id)||Eu.set(e.id,W(e).then(t=>{let n={keys:new Set,cmdN:0};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(Mi({role:o,sourceId:r.payload.sourceId})),n.keys.add(Mi({role:o,ts:r.payload.ts,text:r.payload.text}))}else if(r.type==="peer.message"&&r.source==="transcript")r.payload?.sourceId&&n.keys.add(Mi({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Mi({role:"user",ts:r.payload?.ts,text:r.payload?.keyText??""}));else if(r.type==="tool.called"&&r.source==="transcript"&&r.payload?.command){let o=r.payload;n.keys.add(qS({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>n.cmdN&&(n.cmdN=Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(GS({id:r.payload.id,box:r.boxId}));return zm.set(e.id,n),n}).finally(()=>Eu.delete(e.id))),Eu.get(e.id))}async function KS(e,t){let n=new Set;try{let r=(await Ym(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=Mi(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?vu(o.text):null;if(a){await $(e,{type:"peer.message",actor:"peer",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:a.text,ts:o.ts,keyText:String(o.text||"").slice(0,40),from:await SS(a,Ni),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Kb(o);if(i){await $(e,{type:"provider.error",actor:"system",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{cls:i.cls,code:i.code||void 0,status:i.status||void 0,requestId:i.requestId||void 0,text:o.text,ts:o.ts,model:o.model||null,boxRole:o.boxRole,sourceId:o.sourceId||void 0}}),ES(e,{provider:o.agent||null,cls:i.cls,status:i.status,text:o.text}).catch(()=>{});continue}if(o.role!=="user"&&o.box&&n.add(o.box),await $(e,{type:o.role==="user"?"turn.user":"turn.agent",actor:o.role==="user"?"user":"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:o.text,ts:o.ts,model:o.model||null,tools:o.tools||void 0,boxRole:o.boxRole,sourceId:o.sourceId||void 0,note:o.note||void 0,images:o.images?.length?o.images:void 0}}),o.role==="assistant"&&o.box===e.leadBox&&e.workspace?.branch){let c=Yx(o.text);if(c&&US(await W(e).catch(()=>[])))continue;if(c){let l=Zx(c),u;if(e.workspace?.kind==="multi"){let h=await Ro(e).catch(()=>[]);u=h.length?h.map(w=>({name:w.name,slug:w.repo??null})):void 0}let f=(e.workspace?.kind==="multi"?null:await Dr(e.cwd).catch(()=>null))||e.workspace.branch,d=await du(e,{branch:f,rebase:l}).catch(()=>null),p=d?null:Xx(c);if(d&&d.available.length===0)continue;await $(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:qB(),ts:o.ts,excerpt:c,branch:f,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:d?.available,defaults:d?.defaults,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||u,offered:d?.defaults||p?.offered||void 0,toPr:p?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function VS(e,t){try{let n=await Ym(e),r=[...t||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=qS(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await $(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),kS(e,o),xS(e,o))}}catch{}}async function zS(e,t){try{let n=await Ym(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=GS(o);n.keys.has(s)||(n.keys.add(s),await $(e,{type:"job.started",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,detail:o.detail||null,ts:o.ts??null,boxRole:o.boxRole}}))}}catch{}}var zm,Eu,YS=H(()=>{ge();xo();Sm();Dm();Io();Lm();Yn();yl();Hm();Au();zm=new Map,Eu=new Map});function GB(e){let t=[],n=null;for(let r of String(e||"").split(`
|
|
197
|
-
`)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function KB(e,t){let n=`${e.id}:${t.name}`;if(!Jm.has(n)){let r=await W(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);Jm.set(n,o)}return Jm.get(n)}async function JS(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await io(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await KB(e,t),o=GB(await At(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await $(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:yn(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await $(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var Jm,XS=H(()=>{ge();lo();tn();Fn();Jm=new Map});import _u from"node:fs";import Zm from"node:path";import VB from"node:os";async function JB({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(YB,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${t}`},body:JSON.stringify({teamId:0,startDate:String(e),endDate:String(Date.now()),page:o,pageSize:ZS})});if(!s.ok)throw new Error(`cursor usage feed: HTTP ${s.status}`);let a=await s.json(),i=a?.usageEventsDisplay||a?.usageEvents||[];if(r.push(...i),i.length<ZS)break}return r}function XB(e){if(!e)return null;let t=Number(e.timestamp)||null,n=e.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=e.conversationId||null;return{id:[o||"?",t??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:t,model:e.model||e.modelIntent||null,kind:e.kindLabel||e.kind||null,isHeadless:e.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:e.chargedCents??null}}function eT(){try{return JSON.parse(_u.readFileSync(Iu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function QB(e){try{_u.mkdirSync(Zm.dirname(Iu()),{recursive:!0});let t=Iu()+".tmp";_u.writeFileSync(t,JSON.stringify(e)),_u.renameSync(t,Iu())}catch{}}async function tj({fetchImpl:e,now:t=Date.now()}={}){if(Lr.rows&&t-Lr.at<ZB)return Lr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=eT(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await JB({sinceMs:o,cookie:n,fetchImpl:e});Lr={at:t,rows:s.map(XB).filter(Boolean),error:null}}catch(s){Lr={at:t,rows:null,error:String(s?.message||s)}}return Lr.rows}async function nj(e,t){let n=`${e.id}:${t.name}`;if(!Xm.has(n)){let r=await W(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);Xm.set(n,o)}return Xm.get(n)}async function tT(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!QS())return;let r=await tj({fetchImpl:n});if(!r||!r.length)return;let o=await H0(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await nj(e,t),a=eT(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=yn(u,f)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await $(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}QB({sinceMs:c,seen:[...i].slice(-ej)})}catch{}}var zB,QS,YB,ZS,ZB,Lr,Iu,ej,Qm,Xm,eh=H(()=>{ge();Op();Fn();zB=process.env.BOSTRAT_STATE_DIR||Zm.join(process.env.HOME||VB.tmpdir(),".bostrat"),QS=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,YB="https://cursor.com/api/dashboard/get-filtered-usage-events",ZS=100;ZB=5*6e4,Lr={at:0,rows:null,error:null},Iu=()=>Zm.join(zB,"cursor-usage.json");ej=5e3;Qm=()=>({enabled:QS(),lastPollAt:Lr.at||null,error:Lr.error}),Xm=new Map});import Bi from"node:fs/promises";import Et from"node:path";import rj from"node:os";import oj from"node:net";import{randomUUID as sj}from"node:crypto";import{execFile as aj}from"node:child_process";import{promisify as ij}from"node:util";function mj(e){for(let t of ih(e))if(!iT.test(t))return t;return null}function cT(e){let t=ih(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function hj(e,t){let n=cT(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Et.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Et.resolve(e,n[r+1])}return e}function gj(e){let t=!1,n=!1;for(let r of ih(e)){if(!t){if(iT.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&th(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,th(r))return`serves the filesystem root ("${r}")`;continue}if(th(r))return`serves the filesystem root ("${r}")`;if(wj(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function bj(e,t){if(Et.resolve(e)===Et.resolve(t))return!0;let[n,r]=await Promise.all([$u(e),$u(t)]);return n===r}async function kj(e){let n=(await Bi.readdir(e,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await lT(Et.join(e,o.name,oh))?`./${o.name}`:null))).filter(Boolean)}async function xj(e,t){let[n,r]=await Promise.all([$u(e),$u(t)]),o=Et.relative(n,r);if(o&&(o.startsWith("..")||Et.isAbsolute(o)))throw Pi(`serve directory escapes the Track workspace: ${t}`)}async function vj(e,t){let n=gj(t);if(n)throw Pi(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await yj(e))throw Pi(`serve directory does not exist: ${e}`);let r=mj(t);if(!r)return;if(!r.includes("/")&&!await kb(r,{loginShell:!0,failOpen:!0}))throw Pi(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(dj.test(t)||fj.has(r)||!uj.has(r)||!cT(t).includes("run")||pj.test(t))return;let o=hj(e,t);if(await lT(Et.join(o,oh)))return;let s=await kj(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Pi(`no ${oh} in ${o}${a}`)}async function Zn(){return vn||(nh||=(async()=>{try{vn=JSON.parse(await Bi.readFile(aT,"utf8"))}catch{vn={views:[],adoptWatermarks:{}}}finally{nh=null}return vn.views||=[],vn.adoptWatermarks||={},vn})(),nh)}async function Tn(){await Tt(aT,vn)}function Xn(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function lh(e){return Di.get(e)||null}function dT(e,{name:t,box:n}={}){let r=Di.get(e);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:e,name:t||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return Di.set(e,o),o}function sh(e,t){let n=Di.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function Ru(e,{error:t=null}={}){let n=Di.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function fT(e){let t=[];for(let n of e?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||t.push({box:n.box,from:n.startedAt,to:n.endedAt});return t}function ah(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function Sj(e,t){let n=ah(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!oT.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!oT.has(s))return s}}function ji(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=oj.connect({port:e,host:"127.0.0.1"}),o=s=>{r.destroy(),n(s)};r.setTimeout(t,()=>o(!1)),r.once("connect",()=>o(!0)),r.once("error",()=>o(!1))})}async function uh(e){if(process.platform!=="darwin"){await Sn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Sn("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${e}`]))}catch{return}for(let n of t.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function pT(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function Tj(e,t){let n=new Set(e.views.map(o=>o.port)),r=pT();if(t){let o=Number(t);if(!Number.isInteger(o)||o<1024||o>65535)throw new Error("invalid port");if(r.has(o))throw new Error(`port ${o} is the node's own API port`);if(n.has(o))throw new Error(`port ${o} is already owned by a view`);return o}for(let o=nT;o<=rT;o++)if(!(n.has(o)||r.has(o))&&!await ji(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${nT}-${rT}`)}async function Aj(e){try{let{stdout:t}=await Sn(J,Z("list-sessions","-F","#{session_name}"));return t.split(`
|
|
197
|
+
`)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function KB(e,t){let n=`${e.id}:${t.name}`;if(!Jm.has(n)){let r=await W(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);Jm.set(n,o)}return Jm.get(n)}async function JS(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await io(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await KB(e,t),o=GB(await At(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await $(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:yn(c,i,a.ts),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await $(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var Jm,XS=H(()=>{ge();lo();tn();Fn();Jm=new Map});import _u from"node:fs";import Zm from"node:path";import VB from"node:os";async function JB({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(YB,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${t}`},body:JSON.stringify({teamId:0,startDate:String(e),endDate:String(Date.now()),page:o,pageSize:ZS})});if(!s.ok)throw new Error(`cursor usage feed: HTTP ${s.status}`);let a=await s.json(),i=a?.usageEventsDisplay||a?.usageEvents||[];if(r.push(...i),i.length<ZS)break}return r}function XB(e){if(!e)return null;let t=Number(e.timestamp)||null,n=e.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=e.conversationId||null;return{id:[o||"?",t??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:t,model:e.model||e.modelIntent||null,kind:e.kindLabel||e.kind||null,isHeadless:e.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:e.chargedCents??null}}function eT(){try{return JSON.parse(_u.readFileSync(Iu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function QB(e){try{_u.mkdirSync(Zm.dirname(Iu()),{recursive:!0});let t=Iu()+".tmp";_u.writeFileSync(t,JSON.stringify(e)),_u.renameSync(t,Iu())}catch{}}async function tj({fetchImpl:e,now:t=Date.now()}={}){if(Lr.rows&&t-Lr.at<ZB)return Lr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=eT(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await JB({sinceMs:o,cookie:n,fetchImpl:e});Lr={at:t,rows:s.map(XB).filter(Boolean),error:null}}catch(s){Lr={at:t,rows:null,error:String(s?.message||s)}}return Lr.rows}async function nj(e,t){let n=`${e.id}:${t.name}`;if(!Xm.has(n)){let r=await W(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);Xm.set(n,o)}return Xm.get(n)}async function tT(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!QS())return;let r=await tj({fetchImpl:n});if(!r||!r.length)return;let o=await H0(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await nj(e,t),a=eT(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=yn(u,f,l.ts??void 0)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await $(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}QB({sinceMs:c,seen:[...i].slice(-ej)})}catch{}}var zB,QS,YB,ZS,ZB,Lr,Iu,ej,Qm,Xm,eh=H(()=>{ge();Op();Fn();zB=process.env.BOSTRAT_STATE_DIR||Zm.join(process.env.HOME||VB.tmpdir(),".bostrat"),QS=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,YB="https://cursor.com/api/dashboard/get-filtered-usage-events",ZS=100;ZB=5*6e4,Lr={at:0,rows:null,error:null},Iu=()=>Zm.join(zB,"cursor-usage.json");ej=5e3;Qm=()=>({enabled:QS(),lastPollAt:Lr.at||null,error:Lr.error}),Xm=new Map});import Bi from"node:fs/promises";import Et from"node:path";import rj from"node:os";import oj from"node:net";import{randomUUID as sj}from"node:crypto";import{execFile as aj}from"node:child_process";import{promisify as ij}from"node:util";function mj(e){for(let t of ih(e))if(!iT.test(t))return t;return null}function cT(e){let t=ih(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function hj(e,t){let n=cT(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Et.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Et.resolve(e,n[r+1])}return e}function gj(e){let t=!1,n=!1;for(let r of ih(e)){if(!t){if(iT.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&th(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,th(r))return`serves the filesystem root ("${r}")`;continue}if(th(r))return`serves the filesystem root ("${r}")`;if(wj(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function bj(e,t){if(Et.resolve(e)===Et.resolve(t))return!0;let[n,r]=await Promise.all([$u(e),$u(t)]);return n===r}async function kj(e){let n=(await Bi.readdir(e,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await lT(Et.join(e,o.name,oh))?`./${o.name}`:null))).filter(Boolean)}async function xj(e,t){let[n,r]=await Promise.all([$u(e),$u(t)]),o=Et.relative(n,r);if(o&&(o.startsWith("..")||Et.isAbsolute(o)))throw Pi(`serve directory escapes the Track workspace: ${t}`)}async function vj(e,t){let n=gj(t);if(n)throw Pi(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await yj(e))throw Pi(`serve directory does not exist: ${e}`);let r=mj(t);if(!r)return;if(!r.includes("/")&&!await kb(r,{loginShell:!0,failOpen:!0}))throw Pi(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(dj.test(t)||fj.has(r)||!uj.has(r)||!cT(t).includes("run")||pj.test(t))return;let o=hj(e,t);if(await lT(Et.join(o,oh)))return;let s=await kj(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Pi(`no ${oh} in ${o}${a}`)}async function Zn(){return vn||(nh||=(async()=>{try{vn=JSON.parse(await Bi.readFile(aT,"utf8"))}catch{vn={views:[],adoptWatermarks:{}}}finally{nh=null}return vn.views||=[],vn.adoptWatermarks||={},vn})(),nh)}async function Tn(){await Tt(aT,vn)}function Xn(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function lh(e){return Di.get(e)||null}function dT(e,{name:t,box:n}={}){let r=Di.get(e);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:e,name:t||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return Di.set(e,o),o}function sh(e,t){let n=Di.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function Ru(e,{error:t=null}={}){let n=Di.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function fT(e){let t=[];for(let n of e?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||t.push({box:n.box,from:n.startedAt,to:n.endedAt});return t}function ah(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function Sj(e,t){let n=ah(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!oT.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!oT.has(s))return s}}function ji(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=oj.connect({port:e,host:"127.0.0.1"}),o=s=>{r.destroy(),n(s)};r.setTimeout(t,()=>o(!1)),r.once("connect",()=>o(!0)),r.once("error",()=>o(!1))})}async function uh(e){if(process.platform!=="darwin"){await Sn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Sn("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${e}`]))}catch{return}for(let n of t.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function pT(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function Tj(e,t){let n=new Set(e.views.map(o=>o.port)),r=pT();if(t){let o=Number(t);if(!Number.isInteger(o)||o<1024||o>65535)throw new Error("invalid port");if(r.has(o))throw new Error(`port ${o} is the node's own API port`);if(n.has(o))throw new Error(`port ${o} is already owned by a view`);return o}for(let o=nT;o<=rT;o++)if(!(n.has(o)||r.has(o))&&!await ji(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${nT}-${rT}`)}async function Aj(e){try{let{stdout:t}=await Sn(J,Z("list-sessions","-F","#{session_name}"));return t.split(`
|
|
198
198
|
`).some(n=>n.trim()===zs(e))}catch{return!1}}async function Li(e){try{await Sn(J,Z("kill-session","-t",zs(e)))}catch{}}async function dh(e){if(!await Ka())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=zs(e.slug),n=e.serveCwd??e.cwd,r=Et.dirname(process.execPath);await Sn(J,Z("new-session","-d","-s",t,"-c",n)),await Sn(J,Z("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Sn(J,Z("send-keys","-t",t,"Enter")),await Sn(J,Z("send-keys","-t",t,"-l",e.cmd)),await Sn(J,Z("send-keys","-t",t,"Enter"))}async function sT(e,t=12){try{let{stdout:n}=await Sn(J,Z("capture-pane","-t",zs(e),"-p"));return String(n||"").trimEnd().split(`
|
|
199
199
|
`).filter(Boolean).slice(-t).join(`
|
|
200
200
|
`)}catch{return""}}async function _j(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await Aj(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await sT(e.slug)||"server exited before listening"),Jn.delete(e.id),await Xn(e,e.state,e.error?{error:e.error}:{}),!0}if(await ji(e.port))return Jn.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Xn(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>Ej?(e.state="error",e.error=await sT(e.slug)||"never started listening",await Xn(e,"error",{error:e.error}),!0):!1;let o=(Jn.get(e.id)||0)+1;return Jn.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function Ou(){if(!rh){rh=!0;try{let e=await Zn(),t=!1;for(let n of e.views)await _j(n)&&(t=!0);t&&await Tn()}finally{rh=!1}}}async function Cu({trackId:e}={}){await Ou();let t=await Zn();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function mT(e){let n=(await Zn()).views.find(r=>r.id===e);return n?{...n}:null}function fh(e){return vn&&vn.views.find(t=>t.slug===e)||null}async function ph({trackId:e,name:t,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(i!=="detected"&&(typeof n!="string"||!n.trim()))throw new Error("cmd (string) required");if(!r)throw new Error("cwd required");let l=o!=null,u=Et.resolve(r,o??"."),f=i==="detected"?null:async()=>{await xj(r,u),await vj(u,n)},d=await Zn();if(i!=="detected"){let w=ah(t),g=String(n).trim(),b=d.views.find(v=>v.trackId===e&&(v.slug===w||ah(v.name)===w||v.cmd===g&&Et.resolve(v.serveCwd??v.cwd)===u));if(b)return Ij(d,b,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:f})}if(f&&await f(),d.views.filter(w=>w.state==="live"||w.state==="starting").length>=Fr)throw new Error(`view cap reached (${Fr} live) \u2014 stop one first`);let h={id:sj().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:Sj(d,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await Tj(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await dh(h),d.views.push(h),await Tn(),await Xn(h,"created",{origin:i}),sh(e,h.id),i==="detected"&&await ji(h.port)&&(h.state="live",h.lastHealthyAt=Date.now(),await Tn(),await Xn(h,"live")),{...h}}async function Ij(e,t,{cmd:n,box:r,branch:o,serveCwd:s,validate:a}){r&&(t.box=r),o&&(t.branch=o);let i=t.cmd!==n,c=s!==void 0&&!await bj(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await ji(t.port))return await Tn(),sh(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(f=>f.id!==t.id&&(f.state==="live"||f.state==="starting")).length>=Fr)throw new Error(`view cap reached (${Fr} live) \u2014 stop one first`);return t.origin==="detected"?(await uh(t.port),t.origin="agent"):await Li(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),Jn.delete(t.id),await dh(t),await Tn(),await Xn(t,"created",{restarted:!0,reused:!0}),sh(t.trackId,t.id),{...t,reused:!0}}async function hT(e){let n=(await Zn()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await uh(n.port):await Li(n.slug),n.state!=="stopped"&&(n.state="stopped",Jn.delete(n.id),await Tn(),await Xn(n,"stopped")),{...n}}async function wT(e){let t=await Zn(),n=t.views.find(o=>o.id===e);if(!n)throw new Error("view not found");if(!n.cmd)throw new Error("a detected view has no known command \u2014 recreate it as a managed view");if(t.views.filter(o=>o.id!==e&&(o.state==="live"||o.state==="starting")).length>=Fr)throw new Error(`view cap reached (${Fr} live) \u2014 stop one first`);return await Li(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Jn.delete(n.id),await dh(n),await Tn(),await Xn(n,"created",{restarted:!0}),{...n}}async function gT(e){let t=await Zn(),n=t.views.findIndex(o=>o.id===e);if(n===-1)throw new Error("view not found");let r=t.views[n];return r.origin==="detected"?await uh(r.port):await Li(r.slug),t.views.splice(n,1),Jn.delete(r.id),await Tn(),await Xn(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function yT(e){let t=await Zn(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Li(r.slug),Jn.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Tn()),n.length}async function bT(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await Zn(),r=n.adoptWatermarks[e.id]??null,o=t.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=t.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[e.id]!==s&&(n.adoptWatermarks[e.id]=s,await Tn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll($j)){let u=Number(l[1]||80);u>=1024&&u<=65535&&a.add(u)}if(!a.size)return[];let i=[];for(let c of a)if(!pT().has(c)&&!n.views.some(l=>l.port===c)&&await ji(c))try{i.push(await ph({trackId:e.id,name:`${e.name} preview`,cmd:null,cwd:e.cwd,port:c,origin:"detected",branch:e.workspace?.branch??null}))}catch{}return i}var Sn,cj,aT,nT,rT,Fr,lj,zs,oT,Pi,uj,oh,dj,fj,pj,ih,iT,th,wj,yj,lT,$u,vn,nh,Di,ch,uT,Jn,Ej,rh,$j,Mu=H(()=>{ut();ge();fr();Sn=ij(aj),cj=process.env.BOSTRAT_STATE_DIR||Et.join(process.env.HOME||rj.tmpdir(),".bostrat"),aT=Et.join(cj,"views.json"),[nT,rT]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Fr=Number(process.env.BOSTRAT_VIEW_MAX)||3,lj="bostrat-view-",zs=e=>`${lj}${e}`,oT=new Set(["bostrat","www","api","views","app"]),Pi=e=>Object.assign(new Error(e),{status:400}),uj=new Set(["npm","pnpm","yarn","bun"]),oh="package.json",dj=/[|;&`]|\$\(/,fj=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),pj=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,ih=e=>String(e).trim().split(/\s+/).filter(Boolean),iT=/^[A-Za-z_][A-Za-z0-9_]*=/;th=e=>e==="/",wj=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");yj=e=>Bi.stat(e).then(t=>t.isDirectory(),()=>!1),lT=e=>Bi.stat(e).then(t=>t.isFile(),()=>!1),$u=e=>Bi.realpath(e).catch(()=>Et.resolve(e));vn=null,nh=null;Di=new Map,ch=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,uT=12e3;Jn=new Map,Ej=12e4;rh=!1;$j=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function Nu(e,t=Date.now()){let n=null;for(let r of e||[]){let o=r.payload?.ts??r.ts;r.type==="pr.offer.answered"?n=r.payload?.action==="pr"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"offer"}:null:r.type==="pr.exists.answered"?n=r.payload?.choice==="push"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"exists"}:null:r.type==="pr.state.changed"&&(r.payload?.change==="opened"||r.payload?.change==="pushed")&&n!=null&&o>=n.ts&&(n=null)}return n!=null&&t-n.ts>Oj?null:n}function Cj(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function Pu(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await W(e)}catch{return}let o=Nu(r);if(o==null)return;let s=(e.boxes||[]).find(f=>f.name===e.leadBox);if(await _o(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(mh.get(e.id)||0)<Rj)return;mh.set(e.id,a);let i;try{i=await kn(e.cwd,{caller:"reconcile"})}catch{return}let c=await Ws(e).catch(()=>[n]),l=(i||[]).find(f=>c.includes(f.headRefName));if(!l)return;let u=await Ee(e.cwd).catch(()=>null);if(u){let{link:f,created:d}=await Rt({repo:u,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!d&&!(f?.trackId===e.id&&await Hn(u,l.number))){if(!Cj(f,o))return;let p=await W(e).catch(()=>null);if(p&&Nu(p)==null)return;await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:l.number,url:l.url,title:l.title,branch:n,repo:u}});return}}await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:l.number,url:l.url,title:l.title,branch:n,...u?{repo:u}:{}}}).catch(()=>{}),mh.delete(e.id)}var Rj,mh,Oj,Du=H(()=>{ge();Eo();ur();Wn();_i();Io();Rj=6e3,mh=new Map,Oj=30*6e4});import hh from"node:os";import{execFile as Mj}from"node:child_process";import{promisify as Nj}from"node:util";async function Bu(){if(process.platform!=="darwin")return hh.freemem();try{let{stdout:e}=await Pj("vm_stat",[],{timeout:3e3}),t=Number(/page size of (\d+) bytes/.exec(e)?.[1])||4096,n=o=>Number(new RegExp(`Pages ${o}:\\s+(\\d+)\\.`).exec(e)?.[1])||0,r=(n("free")+n("inactive")+n("speculative"))*t;return r>0?r:hh.freemem()}catch{return hh.freemem()}}var Pj,wh=H(()=>{Pj=Nj(Mj)});import Ye from"node:fs/promises";import Je from"node:path";import ST from"node:os";import{randomUUID as Dj}from"node:crypto";import{execFile as Bj}from"node:child_process";import{promisify as jj}from"node:util";import{chromium as Lj}from"playwright-core";async function _n(){return Oo||(gh||=(async()=>{try{Oo=JSON.parse(await Ye.readFile(AT,"utf8"))}catch{Oo={mocks:[]}}finally{gh=null}return Oo.mocks||=[],Oo})(),gh)}async function qt(){await Tt(AT,Oo)}function $T(e,t){En(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&En(e,t.v,"png")}function bt(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,mockId:e.id,name:e.name,...e.group?{group:e.group}:{},...e.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function Gt(e,t){let n=Ui(e.cwd);return{html:Je.join(n,`${e.id}.v${t}.html`),png:Je.join(n,`${e.id}.v${t}.png`)}}function Fi(e,t,n){if(!t)return null;let r=n==="html"?t.htmlRel:n==="png"?t.pngRel??t.posterRel??null:n==="video"?t.videoRel??null:null;return r?Je.join(e.cwd,r):null}function sn(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function kh(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function ju(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(Kj)}function Vj(e){return!Buffer.isBuffer(e)||e.length<32?null:e.subarray(4,8).toString("latin1")==="ftyp"?{ext:"mp4",mime:"video/mp4"}:e.readUInt32BE(0)===440786851?{ext:"webm",mime:"video/webm"}:null}async function zj(e){let t=Buffer.alloc(24),n=await Ye.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function Yj({imgW:e,imgH:t,bbox:n,pad:r,align:o=1}){if(!n||!(e>0)||!(t>0))return null;let s=n.right-n.left+1,a=n.bottom-n.top+1;if(s<=0||a<=0||s>=e*.9&&a>=t*.9)return null;let i=s+2*r,c=a+2*r;return i+=(o-i%o)%o,c+=(o-c%o)%o,{sx:n.left,sy:n.top,sw:s,sh:a,outW:i,outH:c,dx:Math.floor((i-s)/2),dy:Math.floor((c-a)/2)}}async function Jj(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((h,w)=>{r.onload=h,r.onerror=()=>w(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,f=s,d=-1,p=-1;for(let h=0;h<s;h++)for(let w=h*o*4,g=0;g<o;g++,w+=4)Math.abs(c[w]-l[0])+Math.abs(c[w+1]-l[1])+Math.abs(c[w+2]-l[2])>24&&(g<u&&(u=g),g>d&&(d=g),h<f&&(f=h),p=h);return d<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:f,right:d,bottom:p}}},t.toString("base64"))}async function Xj(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((f,d)=>{c.onload=f,c.onerror=()=>d(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function Zj({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await Lj.launch({executablePath:ET,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Ot("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Ys})).newPage();a.setDefaultTimeout(Js),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Js}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Js});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await Jj(a,i),u=l&&Yj({...l,pad:Hj*Ys,align:Ys});u&&(i=await Xj(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<_T)throw new Ot(`capture produced a ${i.length}-byte image`);let c=kh(i);if(!c)throw new Ot("output is not a PNG");return await Ye.writeFile(t,i),{width:Math.round(c.width/Ys),height:Math.round(c.height/Ys),dpr:Ys,renderMs:Date.now()-r}}catch(s){throw s instanceof Ot?s:new Ot(/timeout/i.test(s?.message||"")?`render timed out after ${Js}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function vT({htmlPath:e,outPath:t,width:n}){let r=await Ye.mkdtemp(Je.join(ST.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await bh(kT,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Js,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ot(`firefox not found (${kT})`,""):new Ot(c?.killed?`render timed out after ${Js}ms`:"firefox exited non-zero",s)}let a=await Ye.stat(t).catch(()=>null);if(!a||a.size<_T)throw new Ot(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=kh(await zj(t));if(!i)throw new Ot("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Ye.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function Qj(e){if(Fj==="firefox")return vT(e);try{return await Zj(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await vT(e)}catch(n){throw/not found/.test(n?.message||"")?new Ot(`no browser installed \u2014 chromium missing at ${ET} and no firefox on PATH; install chromium (Debian: apt install chromium fonts-dejavu-core fonts-liberation) or point BOSTRAT_CHROMIUM_BIN at a Chrome/Chromium binary`,t?.message||""):n}}}function RT(e){return yh=yh.then(e,e),yh}async function OT(e,t){let n=await _n(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await qt(),await bt(r,"rendering",{version:t});try{let o=await Bu();if(o<Wj)throw new Ot(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Gt(r,t),a=await eL({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ye.rm(s.png,{force:!0}).catch(()=>{});return}xh(r,{v:t,source:"html",htmlRel:Je.relative(r.cwd,s.html),pngRel:Je.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await qt(),await bt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),An(r),En(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await qt(),await bt(r,"error",{version:t,error:r.error}),An(r)}}}function xh(e,t){e.versions=(e.versions||[]).filter(r=>r.v!==t.v).concat(t),e.versions.sort((r,o)=>r.v-o.v);let n=e.versions[e.versions.length-1];e.readyVersion=n.v,e.height=n.height,e.dpr=n.dpr,e.renderMs=n.renderMs??null,n.v===e.version&&(e.state="ready",e.error=null)}function tL({trackId:e,name:t,cwd:n,width:r}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(!n)throw new Error("cwd required");let o=r==null?Uj:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Hi({trackId:e,group:t}={}){let n=await _n(),r=e?n.mocks.filter(o=>o.trackId===e):n.mocks;return t&&(r=r.filter(o=>o.group===t)),r.map(o=>({...o}))}async function Qn(e){let n=(await _n()).mocks.find(r=>r.id===e);return n?{...n}:null}function CT({html:e,image:t,video:n}){if([typeof e=="string"&&e.trim(),!!t,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(t&&!ju(t))throw new Error("image must be a PNG");if(n){let o=Vj(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>xT)throw new Error(`video must be ${xT/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function MT({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=tL({trackId:e,name:t,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=CT({html:n,image:r,video:o}),h=await _n(),w={id:Dj().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:f,height:null,dpr:null,state:"queued",source:d?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Ye.mkdir(Ui(s),{recursive:!0}),h.mocks.push(w),d?(await Ye.writeFile(Gt(w,1).html,n),await qt(),await bt(w,"created"),An(w),En(w,1,"html"),RT(()=>OT(w.id,1))):o?(await PT(w,1,o,p),await qt(),await bt(w,"created"),await bt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),An(w),$T(w,w.versions[0])):(await DT(w,1,r),await qt(),await bt(w,"created"),await bt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),An(w),En(w,1,"png")),{...w}}async function NT(e,{html:t,image:n,video:r,width:o}={}){let a=(await _n()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=CT({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Ye.mkdir(Ui(a.cwd),{recursive:!0}),i?(a.state="queued",await Ye.writeFile(Gt(a,l).html,t),await qt(),await bt(a,"updated",{version:l}),An(a),En(a,l,"html"),RT(()=>OT(a.id,l))):r?(await PT(a,l,r,c),await qt(),await bt(a,"updated",{version:l}),await bt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:sn(a)?.durationS??null}),An(a),$T(a,a.versions.find(u=>u.v===l))):(await DT(a,l,n),await qt(),await bt(a,"updated",{version:l}),await bt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),An(a),En(a,l,"png")),{...a}}async function nL(e){try{let{stdout:t}=await bh(qj,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:IT,killSignal:"SIGKILL",maxBuffer:4194304}),n=JSON.parse(t),r=(n.streams||[]).find(s=>s.codec_type==="video"),o=Number(n.format?.duration)||Number(r?.duration)||0;return{durationS:o>0?Math.round(o*10)/10:null,width:Number(r?.width)||null,height:Number(r?.height)||null}}catch{return null}}async function rL(e,t){try{await bh(Gj,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:IT,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ye.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function PT(e,t,n,r){let o=Ui(e.cwd),s=Je.join(o,`${e.id}.v${t}.${r.ext}`),a=Je.join(o,`${e.id}.v${t}.poster.png`);await Ye.writeFile(s,n);let i=await nL(s),c=await rL(s,a);xh(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:Je.relative(e.cwd,s),posterRel:c?Je.relative(e.cwd,a):null,mimeType:r.mime,bytes:n.length,durationS:i?.durationS??null,width:i?.width??null,height:i?.height??null,dpr:1,renderMs:null,createdAt:Date.now()}),i?.width&&(e.width=i.width)}async function DT(e,t,n){let r=kh(n);if(!r)throw new Error("image must be a PNG");let o=Gt(e,t);await Ye.writeFile(o.png,n),xh(e,{v:t,source:"image",htmlRel:null,pngRel:Je.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function BT(e){let t=await _n(),n=t.mocks.find(o=>o.id===e);if(!n)throw new Error("mock not found");if(n.readyVersion==null)throw new Error(`mock is ${n.state} \u2014 nothing to pick yet`);let r=n.group?t.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==e&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await bt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function jT(e){let t=await _n(),n=t.mocks.findIndex(o=>o.id===e);if(n===-1)throw new Error("mock not found");let r=t.mocks[n];t.mocks.splice(n,1);for(let o=1;o<=r.version;o++){let s=Gt(r,o);await Ye.rm(s.html,{force:!0}).catch(()=>{}),await Ye.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ye.rm(Je.join(r.cwd,s),{force:!0}).catch(()=>{});return await qt(),await bt(r,"deleted"),Xt("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function LT(e){let n=(await _n()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=Je.join(TT,"mock-archive",e.id),o=Ui(e.cwd),s=Je.join(r,".bostrat","mocks");await Ye.mkdir(s,{recursive:!0});let a=await Ye.readdir(o).catch(()=>[]);for(let i of a)await Ye.copyFile(Je.join(o,i),Je.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Ye.stat(Je.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=e.name||e.id,i.updatedAt=Date.now(),An(i)}return await qt(),n.length}async function FT(e){let t=await _n(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await qt();for(let r of n)Xt("mocks",r.id).catch(()=>{})}return n.length}async function UT(){if(!je())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await rt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await _n();for(let r of n.mocks){await An(r);for(let o of r.versions||[])o.htmlRel&&await En(r,o.v,"html"),(o.pngRel||o.posterRel)&&await En(r,o.v,"png"),o.videoRel&&await En(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var bh,TT,AT,Fj,ET,kT,Uj,Ys,Hj,_T,Js,Wj,xT,qj,Gj,IT,Ot,Oo,gh,An,En,Ui,Kj,eL,yh,Xs=H(()=>{ge();fr();wh();mr();bh=jj(Bj),TT=process.env.BOSTRAT_STATE_DIR||Je.join(process.env.HOME||ST.tmpdir(),".bostrat"),AT=Je.join(TT,"mocks.json"),Fj=process.env.BOSTRAT_MOCK_ENGINE||"chromium",ET=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",kT=process.env.BOSTRAT_FIREFOX_BIN||"firefox",Uj=1300,Ys=2,Hj=32,_T=1500,Js=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,Wj=700*1024*1024,xT=100*1024*1024,qj=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",Gj=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",IT=2e4,Ot=class extends Error{constructor(t,n=""){super(n?`${t}
|
package/package.json
CHANGED