bostrat-node 1.9.12 → 1.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/bostrat-view +2 -2
- package/dist/cli.js +73 -73
- package/dist/index.js +191 -190
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
var
|
|
2
|
-
`).includes(a));if(!s.length)return;await Lt.mkdir(
|
|
1
|
+
var lC=Object.defineProperty;var W=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Tf=(e,t)=>{for(var n in t)lC(e,n,{get:t[n],enumerable:!0})};import{createHash as uC,randomBytes as dC,timingSafeEqual as pC}from"node:crypto";function ik(){return dC(32).toString("hex")}function Oo(e){let t=typeof e=="string"?e.trim():"";return t?uC("sha256").update(t).digest("hex"):null}function ck(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:pC(Buffer.from(e),Buffer.from(t))}function ui(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Ef.set(e,(Ef.get(e)||0)+1),_f.has(e)&&n-_f.get(e)<fC)return!1;_f.set(e,n);let o=Object.entries(t).filter(([,s])=>s!=null&&s!=="").map(([s,a])=>`${s}=${a}`).join(" ");return r(`[hook-audit] ${e} n=${Ef.get(e)}${o?` ${o}`:""}`),!0}async function lk(e,{byToken:t,legacy:n,env:r=process.env}={}){let o=typeof e=="string"?e.trim():"";if(!o)return r.BOSTRAT_HOOK_LEGACY_DENY==="1"?{mode:"legacy-denied",target:null}:{mode:"legacy",target:await n()};let s=await t(o);return s?.track?{mode:"token",target:s}:{mode:"refused",target:null}}var er,tr,Ef,_f,fC,Ms=W(()=>{er="BOSTRAT_HOOK_TOKEN",tr="x-bostrat-hook";Ef=new Map,_f=new Map,fC=6e4});import Lt from"node:fs/promises";import uk from"node:os";import Ot from"node:path";import{execFile as mC}from"node:child_process";import{promisify as hC}from"node:util";function Ll(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function wC(){return process.env.CLAUDE_CONFIG_DIR?Ot.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):Ot.join(uk.homedir(),".claude.json")}function gC(){return process.env.CLAUDE_CONFIG_DIR?Ot.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):Ot.join(uk.homedir(),".claude","settings.json")}async function Cr(e){if(!e||typeof e!="string")return;let t=Ot.resolve(e),n=wC(),r=gC(),o={};try{o=JSON.parse(await Lt.readFile(n,"utf8"))}catch{}o.hasCompletedOnboarding=!0,o.theme||(o.theme="dark"),o.projects=o.projects||{},o.projects[t]=o.projects[t]||{};let s=o.projects[t];Array.isArray(s.allowedTools)||(s.allowedTools=[]),s.hasTrustDialogAccepted=!0,s.hasCompletedProjectOnboarding=!0;let a=process.env.ANTHROPIC_API_KEY;if(a){let c=a.slice(-20);o.customApiKeyResponses=o.customApiKeyResponses||{},o.customApiKeyResponses.approved=o.customApiKeyResponses.approved||[],o.customApiKeyResponses.rejected=o.customApiKeyResponses.rejected||[],o.customApiKeyResponses.approved.includes(c)||o.customApiKeyResponses.approved.push(c)}await Lt.mkdir(Ot.dirname(n),{recursive:!0}),await Lt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Lt.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,i.remoteControlAtStartup=!1,i.tui===void 0&&(i.tui="default"),process.env.BOSTRAT_HOOKS!=="off"){let l=`curl -sS -m 3 -X POST ${process.env.BOSTRAT_HOOK_URL||`http://127.0.0.1:${process.env.PORT||3362}/api/hook`} -H 'content-type: application/json' -H "${tr}: $${er}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let d of["SessionStart","UserPromptSubmit","Stop"])i.hooks[d]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await Lt.mkdir(Ot.dirname(r),{recursive:!0}),await Lt.writeFile(r,JSON.stringify(i,null,2)),await yC(t)}async function yC(e){try{let t=Ot.resolve(e),n=Ot.join(t,".bostrat","memory","claude"),r=Ot.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await Lt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(Ot.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Lt.mkdir(n,{recursive:!0}),await Lt.mkdir(Ot.dirname(r),{recursive:!0}),await Lt.writeFile(r,JSON.stringify(o,null,2)),await bC(t,["/.claude/settings.local.json"])}catch{}}async function bC(e,t){try{let{stdout:n}=await hC(mC)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=Ot.resolve(e,n.trim()),o=await Lt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
|
|
2
|
+
`).includes(a));if(!s.length)return;await Lt.mkdir(Ot.dirname(r),{recursive:!0}),await Lt.appendFile(r,(o&&!o.endsWith(`
|
|
3
3
|
`)?`
|
|
4
4
|
`:"")+s.join(`
|
|
5
5
|
`)+`
|
|
6
|
-
`)}catch{}}var
|
|
6
|
+
`)}catch{}}var di=W(()=>{Ms()});import If from"node:fs/promises";import kC from"node:os";import Fl from"node:path";function xC(){let e=process.env.CODEX_HOME||Fl.join(kC.homedir(),".codex");return Fl.join(e,"config.toml")}function dk(e){return`[projects."${e}"]`}function vC(e,t){let n=dk(t),r=e.indexOf(n);if(r===-1)return!1;let o=e.slice(r+n.length),s=o.search(/^\s*\[/m),a=s===-1?o:o.slice(0,s);return/trust_level\s*=\s*"trusted"/.test(a)}async function Cs(e){if(!e||typeof e!="string")return;let t=Fl.resolve(e),n=xC(),r="";try{r=await If.readFile(n,"utf8")}catch{}if(vC(r,t))return;let o=dk(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),d=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
|
|
7
7
|
trust_level = "trusted"
|
|
8
8
|
`;r=r.slice(0,a)+d+r.slice(l)}else{let s=`
|
|
9
9
|
${o}
|
|
10
10
|
trust_level = "trusted"
|
|
11
11
|
`;r=r.trimEnd()+s+(r.length&&!r.endsWith(`
|
|
12
12
|
`)?`
|
|
13
|
-
`:"")}try{await
|
|
14
|
-
`,"utf8")}var Ll=W(()=>{});import Ef from"node:fs/promises";import Mr from"node:path";import{execFile as lC}from"node:child_process";import{promisify as uC}from"node:util";async function wC(e){try{return(await Ef.stat(Mr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function gC(e){let t=i=>Ef.readFile(Mr.join(e,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await t("refs/remotes/origin/HEAD"))?.match(/^ref:\s*refs\/remotes\/origin\/(.+)/);if(r)return r[1].trim();let o;for(let i of["main","master"])if(await t(`refs/heads/${i}`)||(o??=await t("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await t("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function er(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await wC(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Mr.basename(o),branch:await gC(o)});return}if(s>=hC)return;let i;try{i=await Ef.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||mC.has(c.name)||await t(Mr.join(o,c.name),s+1)}for(let o of fC)await t(Mr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await $e(o.path),a=s?.toLowerCase();if(a){if(n.has(a))continue;n.add(a),o.slug=s}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function yC(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function $e(e){if(!e)return null;if(Tf.has(e))return Tf.get(e);let t=null;try{let{stdout:n}=await dC("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=yC(n)}catch{t=null}return Tf.set(e,t),t}async function Ns(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await er())if((await $e(n.path))?.toLowerCase()===t)return n.path;return null}var dC,sk,pC,fC,hC,mC,Tf,Cr=W(()=>{dC=uC(lC),sk=process.env.HOME||"/home/globo",pC=Mr.join(process.env.BOSTRAT_STATE_DIR||Mr.join(sk,".bostrat"),"repos"),fC=[...(process.env.BOSTRAT_REPOS_ROOT||Mr.join(sk,"Documents")).split(","),pC].map(e=>e.trim()).filter(Boolean),hC=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,mC=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Tf=new Map});function Ps(e=Date.now()){if(Mo)return{tripped:!1,holdMs:1/0};if(Oo>e)return{tripped:!1,holdMs:Oo-e};if((!pi||e-pi>=Fl.windowMs)&&(pi=e,di=0),di++,di<Fl.trip)return{tripped:!1,holdMs:0};Ul++;let t=Math.min(Fl.minMs*2**(Ul-1),Fl.maxMs);return Oo=e+t,di=0,pi=0,{tripped:!0,holdMs:t}}function ak(){di=0,pi=0,Ul=0,Oo=0}function fi(e=Date.now()){return Mo?1/0:Oo>e?Oo-e:0}function Ds(e=Date.now()){return fi(e)>0}function _f(e={}){Mo={at:Date.now(),...e},Oo=1/0}function Hl(){return Mo}function ik(e=Date.now()){return{held:Ds(e),holdMs:Mo?null:fi(e),holds:Ul,removed:Mo?{...Mo}:null}}var bC,Fl,di,pi,Ul,Oo,Mo,If=W(()=>{bC={trip:3,windowMs:3e5,minMs:3e5,maxMs:216e5},Fl={...bC},di=0,pi=0,Ul=0,Oo=0,Mo=null});import kC from"node:fs";import ck from"node:fs/promises";import hi from"node:path";import xC from"node:os";import{fileURLToPath as vC}from"node:url";import{execFile as SC}from"node:child_process";import{promisify as AC}from"node:util";function Ce(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function Wl(e=process.env){return!!(Ce(e)&&e.BOSTRAT_PLANE_TOKEN)}function fk(e){return e?.status===404&&/not granted/i.test(String(e?.message||""))}async function Bs(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!uk.test(n))throw Co("repo must be owner/name",400);let r=$f.get(n);if(r&&r.expiresAt-Date.now()>_C)return r;if(!Wl(t))throw Co("node is not plane-linked \u2014 GitHub auth unavailable",503);if(Ds()){if(r&&r.expiresAt>Date.now())return r;throw Co(Hl()?"this node was removed from the plane \u2014 GitHub auth unavailable":"plane refused this node's token \u2014 GitHub auth unavailable until it is re-minted",503)}let o;try{o=await dk(`${Ce(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:pk(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Co(`plane unreachable \u2014 GitHub auth unavailable (${i?.message||i})`,503)}let s=await o.json().catch(()=>({}));if(!o.ok){if((o.status===401||o.status===403||o.status===410)&&Ps(),o.status>=500&&r&&r.expiresAt>Date.now())return r;throw Co(s?.error||`plane replied ${o.status}`,o.status)}let a={token:s.token,expiresAt:Number(s.expiresAt)||Date.now()+55*6e4,username:s.username??null,installationId:s.installationId??null};return $f.set(n,a),a}async function mi({env:e=process.env,force:t=!1}={}){if(!Wl(e))return{configured:!1,repos:[],username:null};if(!t&&Nr&&Date.now()-Nr.at<IC)return Nr.data;if(Ds())return Nr?.data??{configured:!0,repos:[],username:null,error:"plane refused this node's token"};try{let n=await dk(`${Ce(e)}/v1/github/repos`,{headers:pk(e)});if((n.status===401||n.status===403||n.status===410)&&Ps(),!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return Nr={at:Date.now(),data:r},r}catch(n){return Nr?Nr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function hk(){$f.clear(),Nr=null}async function En({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await $e(e):null);if(!r)return{};let{token:o}=await Bs(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Rf({env:e=process.env}={}){return(await mi({env:e})).username??null}function MC(e){let[t,n]=String(e).split("/");return hi.join(EC,t,n)}async function Of(e,{env:t=process.env}={}){let n=(...r)=>lk("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${RC()}" ${OC(t)}`),await n("config","credential.useHttpPath","true")}async function ql(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!uk.test(String(e||"")))throw Co(`bad repo slug "${e}"`,400);let r=MC(e);if(kC.existsSync(hi.join(r,".git")))return r;let{token:o}=await Bs(e,{env:t});await ck.mkdir(hi.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await lk("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:$C,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await ck.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Co(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Of(r,{env:t}),r}var lk,TC,EC,uk,_C,IC,$C,dk,$f,Nr,pk,Co,RC,OC,yt=W(()=>{Cr();If();lk=AC(SC),TC=process.env.BOSTRAT_STATE_DIR||hi.join(process.env.HOME||xC.tmpdir(),".bostrat"),EC=hi.join(TC,"repos"),uk=/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?\/[A-Za-z0-9._-]{1,100}$/,_C=5*6e4,IC=6e4,$C=10*6e4,dk=fetch,$f=new Map,Nr=null;pk=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Co=(e,t)=>Object.assign(new Error(e),{status:t});RC=()=>vC(new URL("../bin/bostrat-git-credential",import.meta.url)),OC=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function wk(e=process.env){return!!(Ce(e)&&e.BOSTRAT_PLANE_TOKEN)}async function yk(e,t,n,r=mk){let o=Ce(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await NC(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function bk(e,{env:t=process.env,force:n=!1,timeoutMs:r=mk}={}){if(!wk(t))return{facts:[],source:"unconfigured"};let o=Mf.get(e);if(!n&&o&&Date.now()-o.at<CC)return{facts:o.facts,source:"cache"};try{let s=await yk(`/v1/memory/${encodeURIComponent(e)}`,{headers:gk(t)},t,r);if(!s.ok)throw new Error(`plane ${s.status}`);let a=await s.json(),i=Array.isArray(a?.facts)?a.facts:[];return Mf.set(e,{at:Date.now(),facts:i}),{facts:i,source:"plane"}}catch(s){return o?{facts:o.facts,source:"stale",error:s?.message}:{facts:[],source:"unreachable",error:s?.message}}}async function Kl(e,t,{env:n=process.env}={}){if(!wk(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await yk(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...gk(n),"content-type":"application/json"},body:JSON.stringify({facts:t})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return Mf.delete(e),{pushed:s.filter(a=>a.outcome==="accepted").length,rejected:s.filter(a=>a.outcome==="rejected"),source:"plane"}}catch(r){return{pushed:0,source:"unreachable",error:r?.message}}}var CC,mk,Mf,NC,gk,kk=W(()=>{yt();CC=6e4,mk=5e3,Mf=new Map,NC=(...e)=>fetch(...e);gk=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Cf from"node:fs/promises";import js from"node:path";import PC from"node:os";import{EventEmitter as DC}from"node:events";import{randomUUID as BC}from"node:crypto";function Ls(e){return e?.cwd?js.join(e.cwd,".bostrat","events"):js.join(Nf,"events")}async function UC(e,t){if(!Gl.has(t)){let o=(await q(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Gl.set(t,o)}let n=Gl.get(t)+1;return Gl.set(t,n),n}function Pf(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function C(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!jC.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!LC.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!FC.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?js.join(Nf,"events"):Ls(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(d=>d.name===t.boxId);o=Pf(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await UC(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||BC(),trackId:n,boxId:t.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:t.ts??Date.now(),type:t.type,actor:t.actor??"system",provider:t.provider??null,source:t.source??"orchestrator",payload:t.payload??{},...t.causationId?{causationId:t.causationId}:{},...t.correlationId?{correlationId:t.correlationId}:{}},c=JSON.stringify(i),l=i;return vk(c)&&(c=Sk(c),l=JSON.parse(c)),await Cf.mkdir(r,{recursive:!0}),await Cf.appendFile(xk(r,n),c+`
|
|
15
|
-
`),
|
|
16
|
-
`))if(a.trim())try{s.push(JSON.parse(
|
|
13
|
+
`:"")}try{await If.mkdir(Fl.dirname(n),{recursive:!0}),await If.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var Ul=W(()=>{});import pk from"node:fs/promises";import SC from"node:os";import pi from"node:path";function AC(e){let n=pi.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||pi.join(SC.homedir(),".cursor");return pi.join(r,"projects",n)}async function Ns(e){if(!e||typeof e!="string")return;let t=pi.resolve(e),n=AC(t),r=pi.join(n,".workspace-trusted");await pk.mkdir(n,{recursive:!0}),await pk.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
|
|
14
|
+
`,"utf8")}var Hl=W(()=>{});import Rf from"node:fs/promises";import Nr from"node:path";import{execFile as TC}from"node:child_process";import{promisify as EC}from"node:util";async function MC(e){try{return(await Rf.stat(Nr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function CC(e){let t=i=>Rf.readFile(Nr.join(e,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await t("refs/remotes/origin/HEAD"))?.match(/^ref:\s*refs\/remotes\/origin\/(.+)/);if(r)return r[1].trim();let o;for(let i of["main","master"])if(await t(`refs/heads/${i}`)||(o??=await t("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await t("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function nr(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await MC(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Nr.basename(o),branch:await CC(o)});return}if(s>=RC)return;let i;try{i=await Rf.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||OC.has(c.name)||await t(Nr.join(o,c.name),s+1)}for(let o of $C)await t(Nr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await Re(o.path),a=s?.toLowerCase();if(a){if(n.has(a))continue;n.add(a),o.slug=s}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function NC(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function Re(e){if(!e)return null;if($f.has(e))return $f.get(e);let t=null;try{let{stdout:n}=await _C("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=NC(n)}catch{t=null}return $f.set(e,t),t}async function Ps(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await nr())if((await Re(n.path))?.toLowerCase()===t)return n.path;return null}var _C,fk,IC,$C,RC,OC,$f,Pr=W(()=>{_C=EC(TC),fk=process.env.HOME||"/home/globo",IC=Nr.join(process.env.BOSTRAT_STATE_DIR||Nr.join(fk,".bostrat"),"repos"),$C=[...(process.env.BOSTRAT_REPOS_ROOT||Nr.join(fk,"Documents")).split(","),IC].map(e=>e.trim()).filter(Boolean),RC=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,OC=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);$f=new Map});function Ds(e=Date.now()){if(Co)return{tripped:!1,holdMs:1/0};if(Mo>e)return{tripped:!1,holdMs:Mo-e};if((!mi||e-mi>=Wl.windowMs)&&(mi=e,fi=0),fi++,fi<Wl.trip)return{tripped:!1,holdMs:0};ql++;let t=Math.min(Wl.minMs*2**(ql-1),Wl.maxMs);return Mo=e+t,fi=0,mi=0,{tripped:!0,holdMs:t}}function mk(){fi=0,mi=0,ql=0,Mo=0}function hi(e=Date.now()){return Co?1/0:Mo>e?Mo-e:0}function Bs(e=Date.now()){return hi(e)>0}function Of(e={}){Co={at:Date.now(),...e},Mo=1/0}function Kl(){return Co}function hk(e=Date.now()){return{held:Bs(e),holdMs:Co?null:hi(e),holds:ql,removed:Co?{...Co}:null}}var PC,Wl,fi,mi,ql,Mo,Co,Mf=W(()=>{PC={trip:3,windowMs:3e5,minMs:3e5,maxMs:216e5},Wl={...PC},fi=0,mi=0,ql=0,Mo=0,Co=null});import DC from"node:fs";import wk from"node:fs/promises";import wi from"node:path";import BC from"node:os";import{fileURLToPath as jC}from"node:url";import{execFile as LC}from"node:child_process";import{promisify as FC}from"node:util";function Ne(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function Gl(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}function xk(e){return e?.status===404&&/not granted/i.test(String(e?.message||""))}async function js(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!yk.test(n))throw No("repo must be owner/name",400);let r=Cf.get(n);if(r&&r.expiresAt-Date.now()>WC)return r;if(!Gl(t))throw No("node is not plane-linked \u2014 GitHub auth unavailable",503);if(Bs()){if(r&&r.expiresAt>Date.now())return r;throw No(Kl()?"this node was removed from the plane \u2014 GitHub auth unavailable":"plane refused this node's token \u2014 GitHub auth unavailable until it is re-minted",503)}let o;try{o=await bk(`${Ne(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:kk(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw No(`plane unreachable \u2014 GitHub auth unavailable (${i?.message||i})`,503)}let s=await o.json().catch(()=>({}));if(!o.ok){if((o.status===401||o.status===403||o.status===410)&&Ds(),o.status>=500&&r&&r.expiresAt>Date.now())return r;throw No(s?.error||`plane replied ${o.status}`,o.status)}let a={token:s.token,expiresAt:Number(s.expiresAt)||Date.now()+55*6e4,username:s.username??null,installationId:s.installationId??null};return Cf.set(n,a),a}async function gi({env:e=process.env,force:t=!1}={}){if(!Gl(e))return{configured:!1,repos:[],username:null};if(!t&&Dr&&Date.now()-Dr.at<qC)return Dr.data;if(Bs())return Dr?.data??{configured:!0,repos:[],username:null,error:"plane refused this node's token"};try{let n=await bk(`${Ne(e)}/v1/github/repos`,{headers:kk(e)});if((n.status===401||n.status===403||n.status===410)&&Ds(),!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return Dr={at:Date.now(),data:r},r}catch(n){return Dr?Dr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function vk(){Cf.clear(),Dr=null}async function En({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await Re(e):null);if(!r)return{};let{token:o}=await js(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Nf({env:e=process.env}={}){return(await gi({env:e})).username??null}function zC(e){let[t,n]=String(e).split("/");return wi.join(HC,t,n)}async function Pf(e,{env:t=process.env}={}){let n=(...r)=>gk("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${GC()}" ${VC(t)}`),await n("config","credential.useHttpPath","true")}async function Vl(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!yk.test(String(e||"")))throw No(`bad repo slug "${e}"`,400);let r=zC(e);if(DC.existsSync(wi.join(r,".git")))return r;let{token:o}=await js(e,{env:t});await wk.mkdir(wi.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await gk("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:KC,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await wk.rm(r,{recursive:!0,force:!0}).catch(()=>{}),No(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Pf(r,{env:t}),r}var gk,UC,HC,yk,WC,qC,KC,bk,Cf,Dr,kk,No,GC,VC,gt=W(()=>{Pr();Mf();gk=FC(LC),UC=process.env.BOSTRAT_STATE_DIR||wi.join(process.env.HOME||BC.tmpdir(),".bostrat"),HC=wi.join(UC,"repos"),yk=/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?\/[A-Za-z0-9._-]{1,100}$/,WC=5*6e4,qC=6e4,KC=10*6e4,bk=fetch,Cf=new Map,Dr=null;kk=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),No=(e,t)=>Object.assign(new Error(e),{status:t});GC=()=>jC(new URL("../bin/bostrat-git-credential",import.meta.url)),VC=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function Ak(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ek(e,t,n,r=Sk){let o=Ne(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await YC(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function _k(e,{env:t=process.env,force:n=!1,timeoutMs:r=Sk}={}){if(!Ak(t))return{facts:[],source:"unconfigured"};let o=Df.get(e);if(!n&&o&&Date.now()-o.at<JC)return{facts:o.facts,source:"cache"};try{let s=await Ek(`/v1/memory/${encodeURIComponent(e)}`,{headers:Tk(t)},t,r);if(!s.ok)throw new Error(`plane ${s.status}`);let a=await s.json(),i=Array.isArray(a?.facts)?a.facts:[];return Df.set(e,{at:Date.now(),facts:i}),{facts:i,source:"plane"}}catch(s){return o?{facts:o.facts,source:"stale",error:s?.message}:{facts:[],source:"unreachable",error:s?.message}}}async function zl(e,t,{env:n=process.env}={}){if(!Ak(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await Ek(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...Tk(n),"content-type":"application/json"},body:JSON.stringify({facts:t})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return Df.delete(e),{pushed:s.filter(a=>a.outcome==="accepted").length,rejected:s.filter(a=>a.outcome==="rejected"),source:"plane"}}catch(r){return{pushed:0,source:"unreachable",error:r?.message}}}var JC,Sk,Df,YC,Tk,Ik=W(()=>{gt();JC=6e4,Sk=5e3,Df=new Map,YC=(...e)=>fetch(...e);Tk=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Bf from"node:fs/promises";import Ls from"node:path";import XC from"node:os";import{EventEmitter as ZC}from"node:events";import{randomUUID as QC}from"node:crypto";function Fs(e){return e?.cwd?Ls.join(e.cwd,".bostrat","events"):Ls.join(jf,"events")}async function rN(e,t){if(!Jl.has(t)){let o=(await q(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Jl.set(t,o)}let n=Jl.get(t)+1;return Jl.set(t,n),n}function Lf(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function C(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!eN.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!tN.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!nN.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?Ls.join(jf,"events"):Fs(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(d=>d.name===t.boxId);o=Lf(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await rN(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||QC(),trackId:n,boxId:t.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:t.ts??Date.now(),type:t.type,actor:t.actor??"system",provider:t.provider??null,source:t.source??"orchestrator",payload:t.payload??{},...t.causationId?{causationId:t.causationId}:{},...t.correlationId?{correlationId:t.correlationId}:{}},c=JSON.stringify(i),l=i;return Rk(c)&&(c=Ok(c),l=JSON.parse(c)),await Bf.mkdir(r,{recursive:!0}),await Bf.appendFile($k(r,n),c+`
|
|
15
|
+
`),Je.emit("event",l),Je.emit(`track:${n}`,l),l}async function q(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?Ls.join(jf,"events"):Fs(e));let o;try{o=await Bf.readFile($k(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
|
|
16
|
+
`))if(a.trim())try{s.push(JSON.parse(Rk(a)?Ok(a):a))}catch{}return s}function Mk(e,t){let n=`track:${e}`;return Je.on(n,t),()=>Je.off(n,t)}var eN,tN,nN,Je,jf,$k,Jl,oN,Rk,Ok,me=W(()=>{eN=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","delivery.queued","delivery.settled","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.dismissed","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","rework.cause.retracted","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","job.stalled","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","loop.update.offered","loop.update.answered","loop.updated","loop.delete.offered","loop.delete.answered","loop.deleted","loop.paused","followup.armed","followup.armed.cancelled","followup.offered","followup.answered","followup.create.offered","followup.create.answered","followup.created","planning.change.offered","planning.change.answered","planning.changed","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.phase.changed","track.operation.changed","track.obligations.changed","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),tN=new Set(["user","agent","orchestrator","system","peer"]),nN=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),Je=new ZC;Je.setMaxListeners(0);jf=process.env.BOSTRAT_STATE_DIR||Ls.join(process.env.HOME||XC.tmpdir(),".bostrat");$k=(e,t)=>Ls.join(e,`${t}.ndjson`),Jl=new Map;oN=/(?<!\\)((?:\\\\)*)\\u0000/g,Rk=e=>e.includes("\\u0000"),Ok=e=>e.replace(oN,"$1\\ufffd")});import le from"node:fs/promises";import sN from"node:os";import Se from"node:path";import{execFile as aN}from"node:child_process";import{promisify as iN}from"node:util";function Xl(){return Se.join(Zl,"memory","repos")}function Po(e){return e===rr?Se.join(Zl,"memory",rr):Se.join(Xl(),e)}async function bi(e){try{return JSON.parse(await le.readFile(Se.join(e,Lk),"utf8"))}catch{return{}}}async function Uf(e,t){let n=await bi(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await le.mkdir(e,{recursive:!0}),await le.writeFile(Se.join(e,Lk),JSON.stringify(n))}function Nk(e){let t=String(e||"").trim();if(!t)return null;let r=(t.replace(/\/+$/,"").split(/[/:]/).pop()||"").replace(/\.git$/i,"").toLowerCase();return/^[a-z0-9][a-z0-9._-]*$/.test(r)?r:null}async function Pk(e){try{let{stdout:t}=await cN("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Hf(e){if(!e)return[];let t=Nk(await Pk(e));if(t)return[t];let n=[],r=[];try{r=await le.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Nk(await Pk(Se.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Ql(e){let t=/^---\n([\s\S]*?)\n---\n?/.exec(e);return t?{fm:t[1],body:e.slice(t[0].length)}:{fm:null,body:e}}function Br(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function _n(e,t=null){let n=t??await le.readFile(e,"utf8").catch(()=>""),{fm:r}=Ql(n),o=Br(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await le.stat(e)).mtimeMs}catch{return 0}}function Fk(e,t){let n=Br(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===rr){let o=Br(e,"trust");if(!o||/^operator/i.test(o))return rr}return t}function Wf(e,t,n,r=new Map){let o=(e||"").split(`
|
|
17
17
|
`),s=new Map;for(let c of(t||"").split(`
|
|
18
|
-
`)){let l=
|
|
18
|
+
`)){let l=Hs(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=Hs(c);return l?(a.add(l),n.has(l)&&s.has(l)?s.get(l):c):c});for(let[c,l]of s)a.has(c)||!n.has(c)||(a.add(c),i.push(l));for(let c of n){if(a.has(c))continue;let l=r.get(c);l&&i.push(l)}return i.join(`
|
|
19
19
|
`).replace(/\n{3,}/g,`
|
|
20
20
|
|
|
21
|
-
`)}function
|
|
21
|
+
`)}function Uk(e,t){let n=Br(t,"name")||e.replace(/\.md$/,""),r=Br(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function ki(e){let t=[];try{t=await le.readdir(e,{withFileTypes:!0})}catch{return[]}return t.filter(n=>n.isFile()&&n.name.endsWith(".md")&&n.name!=="MEMORY.md").map(n=>n.name)}async function Hk(e,t){let n=Se.join(e,".bostrat","memory"),r=await ki(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Dk.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=Se.join(n,d);if(o)try{if((await le.stat(p)).mtimeMs<o-uN)continue}catch{continue}let f;try{f=await le.readFile(p,"utf8")}catch{continue}let{fm:w}=Ql(f),m=Fk(w,t);if(!m)continue;let g=Po(m),y=Se.join(g,d),x=await _n(p,f);if(l.has(g)||l.set(g,await bi(g)),(l.get(g)[d]||0)>=x)continue;let b=await _n(y).catch(()=>0);if(await le.access(y).then(()=>!0).catch(()=>!1)&&b>=x)continue;await le.mkdir(g,{recursive:!0}),await le.writeFile(y,f),c++;let $=a.get(g);$||a.set(g,$={won:new Set,generated:new Map}),$.won.add(d),$.generated.set(d,Uk(d,w)),i.has(m)||i.set(m,new Set),i.get(m).add(d)}let u=await le.readFile(Se.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=Se.join(d,"MEMORY.md"),w=await le.readFile(f,"utf8").catch(()=>"");await le.writeFile(f,Wf(w,u,p.won,p.generated))}return Dk.set(e,s),{harvested:c,changedByKey:i}}async function Wk(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await le.access(Se.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Hf(r),a=await Hk(r,s||null);t+=a.harvested;for(let[i,c]of a.changedByKey){n.has(i)||n.set(i,new Set);for(let l of c)n.get(i).add(l)}}return{harvested:t,changedByKey:n}}async function dN(){let e=Se.join(Zl,"workspaces"),t=[];try{t=await le.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return Wk(t.filter(n=>n.isDirectory()).map(n=>Se.join(e,n.name)))}async function mN(e,t){let n=Po(e),r=await bi(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!pN.test(l)||l==="MEMORY.md")continue;let u=Se.join(n,l),d=await le.access(u).then(()=>!0).catch(()=>!1),p=d?await _n(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await le.rm(u,{force:!0}),await Uf(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await le.mkdir(n,{recursive:!0}),await le.writeFile(u,String(c.content??"")),o.add(l),typeof c.indexLine=="string"&&c.indexLine.trim()&&s.set(l,c.indexLine),i++)}if(o.size||a.length){let c=Se.join(n,"MEMORY.md"),l=await le.readFile(c,"utf8").catch(()=>""),u=Wf(l,[...s.values()].join(`
|
|
22
22
|
`),o);if(a.length){let d=new Set(a);u=u.split(`
|
|
23
|
-
`).filter(p=>!d.has(
|
|
24
|
-
`)}await
|
|
25
|
-
`);t.length>
|
|
26
|
-
`);for(;Buffer.byteLength(n,"utf8")>
|
|
27
|
-
`);return n}async function
|
|
23
|
+
`).filter(p=>!d.has(Hs(p))).join(`
|
|
24
|
+
`)}await le.mkdir(n,{recursive:!0}),await le.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function eu(e,t=null){let n=Po(e),r=t?.length?t:await ki(n);if(!r.length)return{pushed:0,source:"empty"};let o=fN(await le.readFile(Se.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=Se.join(n,a),c;try{c=await le.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await _n(i,c),indexLine:o.get(a)??null})}return zl(e,s)}async function hN(e,{timeoutMs:t}={}){let{facts:n,source:r}=await _k(e,t?{timeoutMs:t}:{});n.length?await mN(e,n):r==="plane"&&await eu(e)}function wN(e){let t=e.split(`
|
|
25
|
+
`);t.length>Ck&&(t=t.slice(0,Ck));let n=t.join(`
|
|
26
|
+
`);for(;Buffer.byteLength(n,"utf8")>lN&&t.length;)t.pop(),n=t.join(`
|
|
27
|
+
`);return n}async function yN(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=Se.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=Po(u),p=await bi(d);for(let[g,y]of Object.entries(p)){let x=Se.join(n,g);await le.access(x).then(()=>!0).catch(()=>!1)&&await _n(x)<=y&&(await le.rm(x,{force:!0}),o++)}let f=await ki(d);if(!f.length)continue;await le.mkdir(n,{recursive:!0});for(let g of f){let y=Se.join(d,g),x=Se.join(n,g),b=await _n(y),I=await _n(x).catch(()=>0);await le.access(x).then(()=>!0).catch(()=>!1)&&I>=b||(await le.copyFile(y,x),r++)}let w=await le.readFile(Se.join(d,"MEMORY.md"),"utf8").catch(()=>""),m=u===rr?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${m}
|
|
28
28
|
|
|
29
29
|
${w.trim()}`:w.trim())}if(!s.length)return o?{materialized:!1,reason:"empty-store",cleaned:o}:{materialized:!1,reason:"empty-store"};let i="_Shared Track memory (point-in-time facts). Verify file/line citations against the current code before acting on them; correct a wrong fact in place (bump `modified`, use `supersedes`) rather than working around it._\n\n"+s.join(`
|
|
30
30
|
|
|
31
31
|
`)+`
|
|
32
|
-
`,c=
|
|
33
|
-
`).filter(f=>!s.has(
|
|
34
|
-
`);await
|
|
35
|
-
`).filter(l=>
|
|
36
|
-
`)).catch(()=>{});let c=await
|
|
37
|
-
`)){let r=
|
|
32
|
+
`,c=wN(i);await le.mkdir(n,{recursive:!0}),await le.writeFile(Se.join(n,"MEMORY.md"),c);let l=Se.join(n,"claude");return await le.mkdir(l,{recursive:!0}),await le.writeFile(Se.join(l,"MEMORY.md"),gN,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function qk(e){try{let t=await Hf(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,rr];return await Promise.all(n.map(r=>hN(r,{timeoutMs:bN}))),await yN(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Kk(){return{...st,pending:Us.size,queued:Ff.size}}function Gk(e){if(Yl.has(e))return Yl.get(e);Ff.add(e);let t=Bk.then(async()=>{Ff.delete(e),Yl.delete(e);let n=await qf(e);return st.runs++,st.lastRunAt=Date.now(),n.error?(st.errors++,st.lastError=n.error):st.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Yl.set(e,t),Bk=t.then(()=>{}),t}function tu(e,{delayMs:t=kN}={}){if(!e||typeof e!="string")return;st.scheduled++;let n=Us.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{Us.delete(e),Gk(e)},t);r.unref?.(),Us.set(e,r)}async function nu(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await le.access(Se.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=Us.get(e);r&&(clearTimeout(r),Us.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Gk(e),s])}finally{clearTimeout(o)}}async function Vk(e){return yi||(yi=(async()=>{try{jk||(jk=!0,await vN());let{harvested:t,changedByKey:n}=await Wk(e);for(let[r,o]of n)await eu(r,[...o]);return st.reconciles++,st.lastReconcileAt=Date.now(),st.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return st.errors++,st.lastError=t?.message||String(t),{harvested:0,error:st.lastError}}finally{yi=null}})(),yi)}function xN(){return Se.join(Zl,"memory",".full-sweep-done")}async function zk(){let e=xN();try{let t=JSON.parse(await le.readFile(e,"utf8"));return st.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...st.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await dN();for(let[o,s]of n)await eu(o,[...s]);let r={at:Date.now(),harvested:t};return await le.mkdir(Se.dirname(e),{recursive:!0}),await le.writeFile(e,JSON.stringify(r)),st.backfill=r,{ran:!0,...r}}catch(t){return st.errors++,st.lastError=t?.message||String(t),{ran:!1,error:st.lastError}}}async function vN(){let e=0,t=[];try{t=await le.readdir(Xl(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=Se.join(Xl(),n.name),o=Po(rr),s=new Set,a=new Map;for(let f of await ki(r)){let w=Se.join(r,f),m;try{m=await le.readFile(w,"utf8")}catch{continue}let{fm:g}=Ql(m);if(Fk(g,n.name)!==rr)continue;let y=Se.join(o,f),x=await _n(y).catch(()=>0),b=await _n(w,m);await le.mkdir(o,{recursive:!0}),b>x&&await le.writeFile(y,m),await le.rm(w,{force:!0}),s.add(f),a.set(f,Uk(f,g)),e++}if(!s.size)continue;let i=Date.now();await Uf(r,[...s].map(f=>[f,i])),await zl(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=Se.join(r,"MEMORY.md"),l=await le.readFile(c,"utf8").catch(()=>""),u=l.split(`
|
|
33
|
+
`).filter(f=>!s.has(Hs(f))).join(`
|
|
34
|
+
`);await le.writeFile(c,u).catch(()=>{});let d=Se.join(o,"MEMORY.md"),p=await le.readFile(d,"utf8").catch(()=>"");await le.writeFile(d,Wf(p,l,s,a))}return{moved:e}}async function Jk(){let e=[],t=[rr];try{for(let n of await le.readdir(Xl(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=Po(n),o=await ki(r),s=await bi(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await le.readFile(Se.join(r,i),"utf8").catch(()=>""),{fm:l}=Ql(c);a.push({file:i,name:Br(l,"name")||i.replace(/\.md$/,""),description:Br(l,"description")||"",scope:Br(l,"scope")||null,modified:await _n(Se.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function Yk(e,t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(t)||t==="MEMORY.md")throw new Error("bad fact filename");let n=Po(e),r=Se.join(n,t);if(!await le.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await le.rm(r,{force:!0}),await Uf(n,[[t,s]]);let a=Se.join(n,"MEMORY.md"),i=await le.readFile(a,"utf8").catch(()=>"");await le.writeFile(a,i.split(`
|
|
35
|
+
`).filter(l=>Hs(l)!==t).join(`
|
|
36
|
+
`)).catch(()=>{});let c=await zl(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function qf(e){try{let t=await Hf(e),{harvested:n,changedByKey:r}=await Hk(e,t[0]||null);for(let[o,s]of r)await eu(o,[...s]);return n>0&&await AN(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function AN(e,t){let n=/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1];if(!n)return;let r={},o=0;for(let[s,a]of t){let i=[...a].sort();o+=i.length,r[s]={count:i.length,files:i.slice(0,SN)}}await C({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var cN,Zl,Ck,lN,rr,Lk,Hs,Dk,uN,pN,fN,gN,bN,kN,Us,Ff,Bk,st,Yl,jk,yi,SN,xi=W(()=>{Ik();me();cN=iN(aN),Zl=process.env.BOSTRAT_STATE_DIR||Se.join(process.env.HOME||sN.tmpdir(),".bostrat"),Ck=200,lN=25*1024;rr="operator";Lk=".tombstones.json";Hs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;Dk=new Map,uN=2e3;pN=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,fN=e=>{let t=new Map;for(let n of(e||"").split(`
|
|
37
|
+
`)){let r=Hs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};gN=`# Track memory
|
|
38
38
|
|
|
39
39
|
Shared Track memory (all providers) lives one level up: read \`../MEMORY.md\` for the
|
|
40
40
|
index and the fact files beside it. Facts you save here stay Claude-local but ride the
|
|
41
41
|
same sync; prefer adding durable cross-provider facts to \`../\` following its format.
|
|
42
|
-
`;
|
|
43
|
-
`,n!=null?{mode:n}:void 0),await
|
|
44
|
-
`,"utf8");let n=(await
|
|
45
|
-
`).filter(Boolean);n.length>
|
|
42
|
+
`;bN=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;kN=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,Us=new Map,Ff=new Set,Bk=Promise.resolve(),st={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Yl=new Map;jk=!1,yi=null;SN=20});import ru from"node:fs/promises";import TN from"node:path";async function Mt(e,t,{mode:n}={}){await ru.mkdir(TN.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++EN}.tmp`;try{await ru.writeFile(r,JSON.stringify(t,null,2)+`
|
|
43
|
+
`,n!=null?{mode:n}:void 0),await ru.rename(r,e)}catch(o){throw await ru.unlink(r).catch(()=>{}),o}}var EN,jr=W(()=>{EN=0});import t0 from"node:fs/promises";import n0 from"node:os";import r0 from"node:path";function qe(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ai(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),_N);try{return await MN(`${Ne(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function i0(){return su||(Kf||=t0.readFile(o0(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>su={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>Kf=null),Kf)}async function au(){await Mt(o0(),su).catch(()=>{})}function Qk(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function Vf(e){let t=await i0(),n=Qk(e);if(e.op==="delete")t.ops=t.ops.filter(r=>!(r.family===e.family&&r.id===e.id)),t.ops.push(e);else{t.ops=t.ops.filter(o=>!(o.op==="delete"&&o.family===e.family&&o.id===e.id));let r=t.ops.findIndex(o=>Qk(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Xk&&(t.ops=t.ops.slice(-Xk)),await au()}function e0(){ou||(ou=setTimeout(()=>{ou=null,Ws().catch(()=>{})},CN),ou.unref?.())}function Gf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function PN(e,t=process.env){if(e.op==="record"){let n=await Ai(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Si(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:s0()}]})},t);if(!n.ok)throw Gf(n.status);let o=(await n.json().catch(()=>null))?.results?.[0];return o?.outcome==="rejected"?{delivered:!1,rejected:o.reason}:{delivered:!0}}if(e.op==="blob"){let n=await t0.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Ai(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Si(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw Gf(r.status);return r.status===400?{delivered:!1,rejected:(await r.json().catch(()=>null))?.error||"rejected"}:{delivered:!0}}if(e.op==="delete"){let n=await Ai(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Si(t)},t);if(!n.ok)throw Gf(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Ws({env:e=process.env,log:t=console,now:n=Date.now()}={}){return qe(e)?vi||(vi=(async()=>{let r=await i0();DN(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await PN(a,e)}catch(c){if(!c?.refused)return e0(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<$N)return e0(),await au(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};t.error?.(`[content-plane] ALARM parking ${a.op} ${a.family}/${a.id} after ${a.refusals} refusals (${c.message}) \u2014 draining the ${r.ops.length-1} ops behind it`),r.ops.shift(),r.parked.push({...a,parkedAt:n,error:c.message}),r.parked.length>Zk&&(r.parked=r.parked.slice(-Zk)),s++,await au();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await au()}return{flushed:o,parked:s,pending:0}})().finally(()=>{vi=null}),vi):{flushed:0,source:"unconfigured"}}function DN(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=NN);if(n.length){e.parked=e.parked.filter(r=>!n.includes(r));for(let r of n)e.ops.push({...r,refusals:0,parkedAt:void 0,error:void 0})}}async function Tt(e,t,{trackId:n=null,env:r=process.env}={}){return qe(r)?(await Vf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),Ws({env:r})):{queued:!1,source:"unconfigured"}}async function Lr(e,t,n,r,o,{env:s=process.env}={}){return qe(s)?(await Vf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),Ws({env:s})):{queued:!1,source:"unconfigured"}}async function an(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return qe(r)?(await Vf({op:"delete",family:e,id:t,deletedAt:n}),Ws({env:r})):{queued:!1,source:"unconfigured"}}async function lt(e,{env:t=process.env}={}){if(!qe(t))return{records:[],source:"unconfigured"};try{let n=await Ai(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Si(t)},t);if(!n.ok)throw new Error(`plane ${n.status}`);let r=await n.json();return{records:Array.isArray(r?.records)?r.records:[],source:"plane"}}catch(n){return{records:[],source:"unreachable",error:n?.message}}}async function Ti(e,t,n,r,{env:o=process.env}={}){if(!qe(o))return null;try{let s=await Ai(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Si(o)},o);if(!s.ok)return null;let a=Buffer.from(await s.arrayBuffer());return r==="md"||r==="html"?a.toString("utf8"):a}catch{return null}}var _N,IN,Xk,$N,Zk,RN,ON,o0,s0,a0,MN,CN,NN,Si,su,Kf,ou,vi,Fr=W(()=>{gt();jr();_N=1e4,IN=3e4,Xk=2e3,$N=5,Zk=100,RN=60*6e4,ON=()=>process.env.BOSTRAT_STATE_DIR||r0.join(process.env.HOME||n0.tmpdir(),".bostrat"),o0=()=>r0.join(ON(),"content-outbox.json"),s0=()=>process.env.BOSTRAT_NODE_ID||n0.hostname(),a0=()=>s0(),MN=(...e)=>fetch(...e),CN=IN,NN=RN;Si=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});su=null,Kf=null,ou=null,vi=null});import zf from"node:fs/promises";import c0 from"node:path";async function l0(e,t,{box:n=null,agent:r=null}={}){if(!e||!qe())return{pushed:!1};try{let o=Date.now();return await Tt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Lr("checkpoints",e,o,"md",t),Ei=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function UN(){if(Ei&&Date.now()-Ei.at<FN)return{records:Ei.records,source:"plane"};let e=await lt("checkpoints");return e.source==="plane"&&(Ei={at:Date.now(),records:e.records}),e}async function iu(e){try{let t=LN(e);if(!t||!qe())return{restored:!1};let n=c0.join(e,BN,jN);if(await zf.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await UN();if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===t);if(!s?.data?.v)return{restored:!1};let a=await Ti("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await zf.mkdir(c0.dirname(n),{recursive:!0}),await zf.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var BN,jN,LN,FN,Ei,cu=W(()=>{Fr();BN=".bostrat/handoff",jN="latest.md",LN=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;FN=6e4,Ei=null});import _i from"node:fs/promises";import HN from"node:os";import d0 from"node:path";function Do(e){let t=String(e??"");for(let n of WN)t=t.replace(n,"\u2039redacted\u203A");return t}function lu(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function qN(e){try{await _i.mkdir(Jf,{recursive:!0}),await _i.appendFile(qs,`${JSON.stringify(e)}
|
|
44
|
+
`,"utf8");let n=(await _i.readFile(qs,"utf8")).split(`
|
|
45
|
+
`).filter(Boolean);n.length>u0&&await _i.writeFile(qs,`${n.slice(-u0).join(`
|
|
46
46
|
`)}
|
|
47
|
-
`,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${
|
|
48
|
-
`).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=
|
|
49
|
-
`,r=
|
|
47
|
+
`,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${qs}: ${t?.message||t}`)}}async function pe(e={}){let t={at:new Date().toISOString(),ts:Date.now(),...e},n=[t.flow||"handoff",t.phase||t.step||"?",t.trackId?`track=${t.trackId}`:"",t.sessionName?`box=${t.sessionName}`:"",t.error?`ERR=${t.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),t.sessionName&&lu())try{t.paneTail=Do((await De(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(lu()||t.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch|submit-|gate-accept|blocked|timeout|dialog)/.test(String(t.phase||t.step||"")))&&await qN(t)}async function p0({limit:e=80}={}){try{return(await _i.readFile(qs,"utf8")).split(`
|
|
48
|
+
`).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=Do(o.paneTail)),o}catch{return{raw:Do(r)}}})}catch{return[]}}var WN,Jf,qs,u0,f0,In=W(()=>{ft();WN=[/[A-Za-z0-9_-]{20,}#[A-Za-z0-9_-]{20,}/g,/\bsk-[A-Za-z0-9_-]{16,}/g,/\bghs_[A-Za-z0-9]{16,}|\bghp_[A-Za-z0-9]{16,}|\bgithub_pat_[A-Za-z0-9_]{20,}/g,/\bFlyV1 [A-Za-z0-9+/=_-]{16,}/g,/\bey[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g];Jf=process.env.BOSTRAT_DEBUG_DIR||d0.join(HN.homedir(),".bostrat","debug"),qs=d0.join(Jf,"handoff.jsonl"),u0=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;f0={DEBUG_DIR:Jf,LOG_FILE:qs}});import uu from"node:fs/promises";import Yf from"node:path";import KN from"node:os";async function h0(e=m0){await uu.mkdir(e,{recursive:!0});for(let t of VN){let n=t==="prepare-commit-msg"?zN:t==="post-commit"?JN:`${Xf}exit 0
|
|
49
|
+
`,r=Yf.join(e,t),o=null;try{o=await uu.readFile(r,"utf8")}catch{}o!==n&&await uu.writeFile(r,n,{mode:493}),await uu.chmod(r,493).catch(()=>{})}return e}function w0({nodeUrl:e,dir:t=m0,env:n=process.env}={}){return String(n.BOSTRAT_GIT_HOOKS||"").toLowerCase()==="off"?[]:["-e","GIT_CONFIG_COUNT=1","-e","GIT_CONFIG_KEY_0=core.hooksPath","-e",`GIT_CONFIG_VALUE_0=${t}`,"-e",`${Ii}=${e}`]}function g0(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var Ii,GN,m0,VN,Xf,zN,JN,Zf=W(()=>{Ms();Ii="BOSTRAT_NODE_URL",GN=process.env.BOSTRAT_STATE_DIR||Yf.join(process.env.HOME||KN.tmpdir(),".bostrat"),m0=Yf.join(GN,"git-hooks"),VN=["applypatch-msg","pre-applypatch","post-applypatch","pre-commit","pre-merge-commit","prepare-commit-msg","commit-msg","post-commit","pre-rebase","post-checkout","post-merge","pre-push","post-rewrite","pre-auto-gc"],Xf=`#!/bin/sh
|
|
50
50
|
# bostrat git hook shim (agent/src/git-hooks.js) \u2014 chains to the repo's own hook,
|
|
51
51
|
# then stamps/reports for rework attribution when running inside a bostrat box.
|
|
52
52
|
hook=$(basename "$0")
|
|
@@ -61,75 +61,75 @@ esac
|
|
|
61
61
|
if [ -x "$orig/$hook" ] && [ "$orig/$hook" != "$0" ]; then
|
|
62
62
|
"$orig/$hook" "$@" || exit $?
|
|
63
63
|
fi
|
|
64
|
-
`,
|
|
64
|
+
`,zN=`${Xf}
|
|
65
65
|
# \u2500\u2500 bostrat: append provenance trailers (Layer 0). Skipped for merge commits
|
|
66
66
|
# (nobody "wrote" a merge) and outside a box (no token / no node url).
|
|
67
|
-
[ -z "$${
|
|
68
|
-
[ -z "$${
|
|
67
|
+
[ -z "$${er}" ] && exit 0
|
|
68
|
+
[ -z "$${Ii}" ] && exit 0
|
|
69
69
|
[ "$2" = "merge" ] && exit 0
|
|
70
|
-
trailers=$(curl -sS -m 3 -H "${
|
|
70
|
+
trailers=$(curl -sS -m 3 -H "${tr}: $${er}" "$${Ii}/api/git/trailers" 2>/dev/null) || exit 0
|
|
71
71
|
[ -z "$trailers" ] && exit 0
|
|
72
72
|
printf '%s\\n' "$trailers" | while IFS= read -r line; do
|
|
73
73
|
[ -n "$line" ] && git interpret-trailers --in-place --if-exists addIfDifferent --trailer "$line" "$1" >/dev/null 2>&1 || true
|
|
74
74
|
done
|
|
75
75
|
exit 0
|
|
76
|
-
`,
|
|
76
|
+
`,JN=`${Xf}
|
|
77
77
|
# \u2500\u2500 bostrat: report the commit (code.committed + rework analysis, node-side).
|
|
78
|
-
[ -z "$${
|
|
79
|
-
[ -z "$${
|
|
78
|
+
[ -z "$${er}" ] && exit 0
|
|
79
|
+
[ -z "$${Ii}" ] && exit 0
|
|
80
80
|
sha=$(git rev-parse HEAD 2>/dev/null) || exit 0
|
|
81
81
|
cwd=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
82
|
-
printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${
|
|
83
|
-
-H 'content-type: application/json' -H "${
|
|
82
|
+
printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${Ii}/api/git/committed" \\
|
|
83
|
+
-H 'content-type: application/json' -H "${tr}: $${er}" --data-binary @- >/dev/null 2>&1 || true
|
|
84
84
|
exit 0
|
|
85
|
-
`});import{execFile as
|
|
86
|
-
`).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),
|
|
87
|
-
`).map(n=>n.trim()).includes(e)}catch{return!1}}function
|
|
88
|
-
`).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function
|
|
89
|
-
`).filter(Boolean).length}catch{return 0}}async function
|
|
90
|
-
`);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
|
|
91
|
-
`){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function
|
|
92
|
-
`,n);i!==-1&&(t=t.slice(0,i))}let r
|
|
93
|
-
`).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function
|
|
94
|
-
`)){let a=s.trim();if(!a||a[0]!=="{")continue;let i;try{i=JSON.parse(a)}catch{continue}let c=i.message;if(!c)continue;let l=[];if(
|
|
95
|
-
`);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function
|
|
96
|
-
`)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if((w.type==="turn_context"&&w.payload?.model||w.type==="session_meta"&&w.payload?.model)&&(i=w.payload.model),w.type==="event_msg"){let
|
|
97
|
-
`;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function
|
|
98
|
-
`)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let d=[];if(u.type==="function_call"&&
|
|
99
|
-
`).trim():"";
|
|
100
|
-
`).trim():""}function
|
|
101
|
-
`)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let
|
|
102
|
-
|
|
103
|
-
`):""}var
|
|
104
|
-
`);if(!
|
|
105
|
-
`);for(let r=n.length-1;r>=0;r--)if(
|
|
106
|
-
`);return t}function
|
|
107
|
-
`),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(
|
|
108
|
-
`).pop()||"";return
|
|
109
|
-
`),o=r.findIndex(i=>
|
|
110
|
-
`).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function
|
|
111
|
-
`),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function
|
|
112
|
-
`),n=-1;for(let c=t.length-1;c>=0;c--)if(t[c].trim()){n=c;break}if(n<0)return!1;let r=t[n];if(
|
|
113
|
-
`).filter(c=>/^\s*›/.test(c)),i=a.some(c=>/^\s*›\s+(?:Ask Codex to do anything|Implement \{feature\})\s*$/.test(c));return a.length>0&&!i&&/esc to interrupt|\bWorking \(/.test(s)}function
|
|
114
|
-
`),r=-1;for(let o=n.length-1;o>=0;o--)if(
|
|
115
|
-
`)}function
|
|
116
|
-
`))
|
|
117
|
-
`).slice(-
|
|
118
|
-
`);return
|
|
85
|
+
`});import{execFile as b0}from"node:child_process";import{promisify as YN}from"node:util";import pu from"node:fs";import{randomUUID as k0}from"node:crypto";function Bo(e){return new Promise(t=>setTimeout(t,e))}function du(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 x0(e){return`/tmp/tmux-${e}/default`}function XN({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=x0(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function Ri(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${$i}=1`]}function eP(){return QN.flatMap(e=>["-e",`${e}=`])}function Oi(e,t,n){let r=jo(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&&Be(n)&&(s+=` --name ${n}`),s}function jo(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Ur(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function nP(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:jo(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function v0(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await S0(e,{loginShell:t});return r===fu?!0:r===Ks?!1:n}async function S0(e,{loginShell:t=!1,timeoutMs:n=Qf}={}){if(!e)return Ks;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Me(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),fu}catch(s){return s?.killed||s?.signal?Gs:s?.code===1||s?.code===127?Ks:Gs}}async function mu(e,{retries:t=rP,sleep:n=oP,probe:r=S0}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Qf});for(let a=0;s===Gs&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:Qf*2});return s}function oe(...e){return["-S",Ft,...e]}async function Hr(){if(!pu.existsSync(Ft))return!1;try{return await Me(ne,oe("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Mi(){if(await Hr())return!0;try{pu.mkdirSync(Ft.replace(/\/[^/]+$/,""),{recursive:!0}),await Me(ne,oe("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Hr()}function Be(e){return typeof e=="string"&&sP.test(e)}async function cn(){if(!pu.existsSync(Ft))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 Me(ne,oe("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
|
|
86
|
+
`).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),m=Number(i),g=Number(w);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(m)?n-m*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:d||null,agent:p||(l==="1"?"claude":null),alternateOn:f==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!tP.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function be(e){return(await cn()).find(n=>n.name===e)||null}function cP(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=iP&&aP.test(t)}function hu(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function A0(e){try{let{stdout:t}=await Me(ne,oe("list-sessions","-F","#{session_name}"));return t.split(`
|
|
87
|
+
`).map(n=>n.trim()).includes(e)}catch{return!1}}function dP(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 pP(e,t){let n=Date.now()+Ci(),r=dP(t),o=!1,s=0,a=0;for(;;){if(await Bo(lP),s+=1,!await A0(e))return;let i=await De(e,{lines:15}),c=!o&&uP.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await or(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await pe({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Ur(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Me(ne,oe("send-keys","-t",e,"C-u")),await Me(ne,oe("send-keys","-t",e,"-l",t)),await Me(ne,oe("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await pe({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Ur(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function $n(e,t=ZN,n={}){if(!cP(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=hu(r);if(!Be(o))throw new Error("resulting tmux session name is invalid");if(!await Mi())throw new Error(`host tmux server not running on ${Ft} and auto-start failed \u2014 start one: ${ne} -S ${Ft} new-session -d -s keeper "sleep 2147483647"`);if(await A0(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||em,a=n.agent||Ur(s),i=!!n.resumeSessionId,c=n.resumeSessionId||k0(),l=i?s:Oi(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&jo(s),p=n.firstRun===!0;p||(d&&await Cr(t),a==="codex"&&await Cs(t),a==="cursor"&&await Ns(t),await qk(t),n.freshWorkspace!==!0&&await iu(t));let f=d&&!p?Ll():null,w=ik(),m=["-e",`${er}=${w}`];m.push(...w0({nodeUrl:g0()})),m.push(...eP()),f&&m.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&m.push(...Ri());try{await Me(ne,oe("new-session","-d","-s",o,"-c",t,...m))}catch(g){throw du(f?du(g,f):g,w)}return await Lo(o),await Me(ne,oe("set-option","-t",o,"@bostrat-session","1")),await Me(ne,oe("set-option","-t",o,"@bostrat-title",r)),await Me(ne,oe("set-option","-t",o,"@bostrat-sid",c)),await Me(ne,oe("set-option","-t",o,"@bostrat-agent",a)),await Me(ne,oe("send-keys","-t",o,l,"Enter")),nP(l)&&pP(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function Ct(e){if(!Be(e))throw new Error("invalid session name");await Me(ne,oe("kill-session","-t",e))}async function T0(e,t){if(Be(e))try{let n=t?oe("set-option","-t",e,"@bostrat-sid",t):oe("set-option","-u","-t",e,"@bostrat-sid");await Me(ne,n)}catch{}}async function De(e,{lines:t=40}={}){if(!Be(e))return"";try{let n=oe("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Me(ne,n);return String(r||"")}catch{return""}}async function E0(e){if(!Be(e))return[];try{let{stdout:t}=await Me(ne,oe("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
|
|
88
|
+
`).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function _0(e){if(!Be(e))return 0;try{let{stdout:t}=await Me(ne,oe("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
|
|
89
|
+
`).filter(Boolean).length}catch{return 0}}async function Lo(e,{cols:t=hP,rows:n=wP}={}){if(!Be(e))return!0;if(await _0(e))return!1;try{let r=await I0(e);if(r.cols===t&&r.rows===n)return!0;await Me(ne,oe("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Me(ne,oe("set-window-option","-t",e,"window-size","latest")),await Bo(80)}catch{}return!0}async function gP(e){if(!Be(e))return 0;try{let{stdout:t}=await Me(ne,oe("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function or(e){let t=await gP(e);if(!t)return!1;try{return await Me("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function I0(e){if(!Be(e))return{cols:0,rows:0};try{let{stdout:t}=await Me(ne,oe("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 wu(e,{cols:t=fP,rows:n=mP}={}){if(Be(e)&&!await _0(e))try{let r=await I0(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Me(ne,oe("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Me(ne,oe("set-window-option","-t",e,"window-size","latest")),await Bo(80))}catch{}}async function ln(e){return await wu(e),De(e,{lines:Xe})}async function Ge(e,t,{settleMs:n=40,kind:r}={}){if(!Be(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>$0.has(s));for(let s=0;s<o.length;s++)await Me(ne,oe("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Bo(n);return pe({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function rm(e,t,{settleMs:n=40,kind:r}={}){if(!Be(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[]).filter(s=>s&&(typeof s.key=="string"&&$0.has(s.key)||typeof s.text=="string"&&s.text.length>0));for(let s=0;s<o.length;s++){let a=o[s];a.text!=null?await Me(ne,oe("send-keys","-t",e,"-l",a.text)):await Me(ne,oe("send-keys","-t",e,a.key)),n>0&&s<o.length-1&&await Bo(n)}return pe({flow:"tmux",phase:"send-sequence",sessionName:e,kind:r||"sequence",steps:o.map(s=>s.text!=null?`\u2039text:${s.text.length}\u203A`:s.key).join(" ")}).catch(()=>{}),o.length}async function Vs(e,t,{kind:n}={}){if(!Be(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await Me(ne,oe("send-keys","-t",e,"-N",String(r),"BSpace")),pe({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function yu(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!Be(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await Me(ne,oe("send-keys","-t",e,"-l",s)),n>0&&await Bo(n);pe({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function yP(e,t){return new Promise((n,r)=>{let o=b0(ne,oe(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function bP(e,t){let n=`bostrat-${k0().slice(0,8)}`;await yP(["load-buffer","-b",n,"-"],t),await Me(ne,oe("paste-buffer","-p","-d","-b",n,"-t",e))}async function at(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!Be(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await bP(e,t):await Me(ne,oe("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Bo(a),await Me(ne,oe("send-keys","-t",e,"Enter"))}pe({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 Me,ne,y0,Ft,ZN,em,$i,QN,tm,tP,fu,Ks,Gs,Qf,rP,oP,nm,sP,aP,iP,Ci,lP,uP,fP,mP,Xe,hP,wP,$0,gu,ft=W(()=>{di();Ul();Hl();xi();cu();In();Ms();Zf();Me=YN(b0);ne=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";y0=typeof process.getuid=="function"?process.getuid():0,Ft=XN({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return pu.existsSync(x0(y0))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:y0}),ZN=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",em=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",$i="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";QN=Object.freeze(["BOSTRAT_PLANE_URL","BOSTRAT_PLANE_TOKEN"]);tm="bostrat-usage-probe",tP=new Set([tm]);fu="present",Ks="absent",Gs="unknown",Qf=5e3,rP=[250,1e3,3e3],oP=e=>new Promise(t=>setTimeout(t,e));nm={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"};sP=/^[A-Za-z0-9_.-]{1,64}$/;aP=/^[A-Za-z0-9 ._↻-]+$/,iP=64;Ci=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,lP=1e3,uP=/not found|Unknown command/i;fP=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,mP=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Xe=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,hP=Number(process.env.BOSTRAT_BOX_COLS)||120,wP=Number(process.env.BOSTRAT_BOX_ROWS)||40;$0=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);gu=1600});import Ni from"node:fs";import TP from"node:fs/promises";import zs from"node:path";import EP from"node:os";function am(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function im(e){let t=zs.join(sm,am(e)),n;try{n=Ni.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=zs.join(t,o);try{let{mtimeMs:a}=Ni.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function un(e,t){if(!t)return null;let n=zs.join(sm,am(e),`${t}.jsonl`);return Ni.existsSync(n)?n:null}function D0(e){if(!e)return[];let t=zs.join(sm,am(e)),n;try{n=Ni.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=Ni.statSync(zs.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Nt(e,t=131072){let n=await TP.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 IP(e){let t=e.split(`
|
|
90
|
+
`);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 Pi(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=un(e,t),o=!0,!r)return null}else if(n){if(r=im(e),o=!1,!r)return null}else return null;let s;try{s=IP(await Nt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(P0,s.model),i=P0[s.model]||_P;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 P0,_P,sm,dn=W(()=>{P0={"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},_P=2e5,sm=process.env.BOSTRAT_CLAUDE_PROJECTS||zs.join(EP.homedir(),".claude","projects")});function $P(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===`
|
|
91
|
+
`){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function Di(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 Bi(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 je(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(L0(o)){t.has(o)&&r++;continue}n.push(o)}return n}function F0(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 MP(e){let t=F0(e),n=yt(je(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Ve(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Ve(n)}`:e.includes("-i")&&n?`Edit ${Ve(n)}`:null}function cm(e){if(e.includes("--files")){let s=yt(je(e,B0)[0]);return s&&s!=="."?`List files in ${Js(s)}`:"List files"}let t=je(e,B0),n=t[0];if(!n)return null;let r=yt(t.slice(1).find(s=>s!==".")),o=Ys(n,40);return r?`Search for \u201C${o}\u201D in ${Js(r)}`:`Search for \u201C${o}\u201D`}function lm(e){let t=je(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 um(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=je(e)[0];return n?`Run ${Ve(n)}`:null}function CP(e){let t=je(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 j0(e){return e.find(t=>/^https?:\/\//.test(t))||null}function DP(e){let t=Bi(Di(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Ve(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return dm(t[2]);let n=Ve(t[0]);if(PP.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=NP[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function dm(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
|
|
92
|
+
`,n);i!==-1&&(t=t.slice(0,i))}let r=$P(t);for(let i=0;i<r.length-1;i++){let c=Bi(Di(r[i])),l=Bi(Di(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Ve(c[0]))&&Ve(l[0])==="sed"){let u=F0(l),d=je(c)[0];if(u&&d)return Ys(u.from===u.to?`Read line ${u.from} of ${Ve(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Ve(d)}`,88)}}let o=[];for(let i of r){let c=DP(i);c&&o.push({d:c,head:Ve(Bi(Di(i))[0]||""),sub:je(Bi(Di(i)))[0]})}if(!o.length)return null;let s=o.find(i=>i.head==="git"&&i.sub==="commit"),a=o.find(i=>i.head==="git"&&i.sub==="push");return s&&a?"Commit and push changes":Ys(s?s.d:o[0].d,88)}var Ys,yt,Ve,Js,L0,B0,RP,OP,NP,PP,U0=W(()=>{Ys=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,yt=e=>e&&!/[$`]/.test(e)?e:null,Ve=e=>e.replace(/\/+$/,"").split("/").pop()||e,Js=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},L0=e=>e.startsWith("-"),B0=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);RP={status:()=>"Check git status",diff:()=>"Review changes",log:()=>"Review commit history",show:()=>"Inspect a commit",add:()=>"Stage files",commit:()=>"Commit changes",push:()=>"Push to remote",pull:()=>"Pull from remote",fetch:()=>"Fetch from remote",merge:()=>"Merge branches",rebase:()=>"Rebase branch",stash:()=>"Stash changes",clone:e=>e[1]?`Clone ${Ve(e[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(e,t)=>t.includes("--show-current")?"Check current branch":"List branches",remote:()=>"Check git remotes","rev-parse":()=>"Resolve a git ref",worktree:()=>"Manage git worktrees","merge-base":()=>"Find the merge base","ls-files":()=>"List tracked files"},OP={pr:e=>({create:"Create a pull request",list:"List pull requests",view:"View a pull request",merge:"Merge a pull request",checks:"Check PR status"})[e[1]]||"Run a gh pr command",auth:()=>"Authenticate GitHub CLI",api:()=>"Call the GitHub API",repo:()=>"Inspect the GitHub repo",issue:()=>"Work with GitHub issues"};NP={git:e=>{let t=je(e,new Set(["-C","-c"])),n=RP[t[0]];return n?n(t,e):null},gh:e=>{let t=je(e),n=OP[t[0]];return n?n(t):null},sed:MP,rg:cm,grep:cm,egrep:cm,nl:e=>{let t=yt(je(e)[0]);return t?`Read ${Ve(t)}`:null},cat:e=>{let t=yt(je(e)[0]);return t?`Read ${Ve(t)}`:null},head:e=>{let t=yt(je(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Ve(t)}`:null},tail:e=>{let t=yt(je(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Ve(t)}`:null},wc:e=>{let t=yt(je(e)[0]);return t?`Count lines in ${Ve(t)}`:"Count input lines"},ls:e=>{let t=yt(je(e)[0]);return t&&t!=="."?`List files in ${Js(t)}`:"List files"},find:e=>yt(e[1])&&!L0(e[1])&&e[1]!=="."?`Find files in ${Js(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=yt(je(e)[0]);return t?`Create directory ${Js(t)}`:null},touch:e=>{let t=yt(je(e)[0]);return t?`Create ${Ve(t)}`:null},rm:e=>{let t=yt(je(e)[0]);return t?`Delete ${Js(t)}`:null},mv:e=>{let t=yt(je(e)[0]);return t?`Move ${Ve(t)}`:null},cp:e=>{let t=yt(je(e)[0]);return t?`Copy ${Ve(t)}`:null},chmod:e=>{let t=yt(je(e)[1]);return t?`Change permissions on ${Ve(t)}`:null},diff:e=>{let t=je(e);return t.length>=2?`Compare ${Ve(t[0])} and ${Ve(t[1])}`:null},curl:e=>{let t=j0(e);return t?`Fetch ${Ys(t,56)}`:"Fetch a URL"},wget:e=>{let t=j0(e);return t?`Fetch ${Ys(t,56)}`:"Fetch a URL"},npm:lm,pnpm:lm,yarn:lm,npx:e=>{let t=je(e)[0];return t?`Run ${t}`:null},node:e=>um(e,"Node"),python:e=>um(e,"Python"),python3:e=>um(e,"Python"),make:e=>{let t=je(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:CP,journalctl:e=>{let t=e.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=t!==-1?e[t+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:e=>{let t=je(e,new Set(["-S","-L","-t","-f"]))[0];return{ls:"List tmux sessions","list-sessions":"List tmux sessions","kill-session":"Kill a tmux session","send-keys":"Send keys to a tmux session","capture-pane":"Capture a tmux pane","new-session":"Start a tmux session"}[t]||null},ps:()=>"List processes",which:e=>{let t=je(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=je(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},PP=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function Xs(e){let t=e.split(`
|
|
93
|
+
`).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Wr(e,t=""){let n=t.trim();return n||dm(e)||Xs(e)}function pm(e,t){if(e){if(Array.isArray(e)){for(let n of e)pm(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&fm.has(e.name)){let n=String(e.input?.command||"").trim();n&&t.push({id:e.id||null,tool:e.name,command:n,description:String(e.input?.description||"").trim()})}for(let n of Object.values(e))pm(n,t)}}}async function H0(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await Nt(e,t)}catch{return[]}let o=[];for(let s of r.split(`
|
|
94
|
+
`)){let a=s.trim();if(!a||a[0]!=="{")continue;let i;try{i=JSON.parse(a)}catch{continue}let c=i.message;if(!c)continue;let l=[];if(pm(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Wr(d.command,d.description),ts:u})}return o.slice(-n)}function W0(e,t){let n=a=>a?.box??null,r=new Map;for(let a of t||[]){if(a.role!=="assistant"||!(a.text||"").trim())continue;let i=n(a);r.has(i)||r.set(i,[]),r.get(i).push(a)}let o=new Map;for(let a of e||[]){let i=n(a);o.has(i)||o.set(i,[]),o.get(i).push(a)}let s=[];for(let[a,i]of o)s.push(...BP(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function BP(e,t){let n=[...t].sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((w,m)=>m>=s&&(w.ts||0)>(l.ts||0)),d=u===-1?r.length:u,p=r.slice(s,d);if(s=d,!p.length)continue;let f=p.map(w=>({...w,n:i(w)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:f,ts:Math.max(...f.map(w=>w.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var fm,Zs=W(()=>{dn();U0();fm=new Set(["Bash"])});import q0 from"node:fs";import hm from"node:fs/promises";import mm from"node:path";import jP from"node:os";async function K0(e){try{return await hm.realpath(e)}catch{return e}}function FP(e=LP){let t=[],n=r=>{let o;try{o=q0.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=mm.join(r,s.name);if(s.isDirectory())n(a);else if(s.isFile()&&s.name.startsWith("rollout-")&&s.name.endsWith(".jsonl")){let i=/-([0-9a-f-]{36})\.jsonl$/i.exec(s.name);try{t.push({id:i?i[1]:null,file:a,mtimeMs:q0.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function UP(e,t=1048576){let n;try{n=await hm.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
|
|
95
|
+
`);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function HP(e){let t=await UP(e);if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}return n?.type==="session_meta"&&n?.payload?.cwd||null}async function Fo(e,t){if(!e&&!t)return null;let n=FP();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await K0(e);for(let o of n){let s=await HP(o.file);if(s&&(s===e||await K0(s)===r))return o}return null}async function G0(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Fo(e,t);if(!o)return[];let s;try{s=await Nt(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let p of s.split(`
|
|
96
|
+
`)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if((w.type==="turn_context"&&w.payload?.model||w.type==="session_meta"&&w.payload?.model)&&(i=w.payload.model),w.type==="event_msg"){let x=w.payload?.type;x==="task_started"?(l=!0,u=!1,d=w.payload?.turn_id||null):x==="task_complete"&&l&&(l=!1,!u&&w.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Uo,sourceId:w.payload?.turn_id||d||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i}));continue}if(w.type!=="response_item")continue;let m=w.payload;if(!m)continue;if((m.type==="function_call"||m.type==="custom_tool_call")&&m.name){u=!0,wm.has(m.name)||c.push(m.name);continue}if(m.type!=="message"||m.role!=="assistant")continue;u=!0;let g=qP(m.content),y=c.length?c.slice():null;c=[],!(!g&&!y)&&a.push({role:"assistant",text:g,tools:y||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i})}if(i)for(let p of a)p.model||(p.model=i);return a.slice(-n)}function KP(e){if(typeof e?.cmd=="string"&&e.cmd.trim())return e.cmd.trim();let t=e?.command;return typeof t=="string"&&t.trim()?t.trim():Array.isArray(t)&&t.length?t.length===3&&/^(ba)?sh$/.test(t[0])&&t[1]==="-lc"?String(t[2]).trim():t.map(String).join(" ").trim():null}function GP(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
|
|
97
|
+
`;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function VP(e){let t=String(e||""),n=[],r=/exec_command\s*\(/g;for(let s;s=r.exec(t);)n.push(s.index+s[0].length);let o=[];return n.forEach((s,a)=>{let i=t.slice(s,a+1<n.length?n[a+1]:t.length),c=/(?:^|[{,\s])["'`]?cmd["'`]?\s*:\s*/.exec(i);if(!c)return;let l=GP(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function V0(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Fo(e,t);if(!o)return[];let s;try{s=await Nt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
|
|
98
|
+
`)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let d=[];if(u.type==="function_call"&&ji.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=KP(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=VP(u.input));if(!d.length)continue;let p=u.call_id||u.id||null;d.forEach((f,w)=>{a.push({id:p?w?`${p}:${w}`:p:null,tool:u.name,command:f,description:"",summary:Wr(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function z0(e,t){let n=await Fo(e,t);if(!n)return null;try{return Math.round((await hm.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var LP,WP,qP,ji,wm,Uo,Ho=W(()=>{dn();Zs();LP=process.env.BOSTRAT_CODEX_SESSIONS||mm.join(process.env.CODEX_HOME||mm.join(jP.homedir(),".codex"),"sessions");WP=new Set(["output_text","text"]),qP=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&WP.has(t.type)).map(t=>t.text).join(`
|
|
99
|
+
`).trim():"";ji=new Set(["exec_command","shell","exec"]),wm=new Set(["wait","write_stdin"]),Uo="Codex ended the turn without a response \u2014 it hit an error the CLI shows only in the terminal (e.g. quota or billing). Check the Terminal tab."});function Li({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&J0.has(r))return J0.get(r);let o=Number(t)||0;if(o===401)return"auth";if(o===403)return"entitlement";if(o===429)return"rate_limit";if(o===529)return"overloaded";if(o>=500)return"server";let s=String(n||"").toLowerCase();return/overloaded/.test(s)?"overloaded":/rate limit|too many requests|quota|usage limit/.test(s)?"rate_limit":/billing|subscription|not allowed|disabled .* access|upgrade your plan|no credits/.test(s)?"entitlement":/log ?in|authenticat|expired|invalid.*key|unauthorized/.test(s)?"auth":/server|internal error|5\d\d/.test(s)?"server":"other"}function Y0(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||Li({error:t.code,status:t.status,text:e.text}),code:t.code||null,status:t.status||null,requestId:t.requestId||null}}if(e.failed){let t=String(e.text||"");return{cls:t===Uo?"other":Li({text:t}),code:null,status:null,requestId:null}}return null}function X0(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:Li({text:n}),code:null,status:zP(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function zP(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var b3,J0,ku=W(()=>{Ho();b3=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),J0=new Map([["oauth_org_not_allowed","entitlement"],["permission_error","entitlement"],["billing_error","entitlement"],["authentication_error","auth"],["oauth_token_expired","auth"],["invalid_api_key","auth"],["rate_limit_error","rate_limit"],["overloaded_error","overloaded"],["server_error","server"],["api_error","server"],["internal_server_error","server"]])});function JP(e,t){return!e||!t?null:un(e,t)}function YP(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
|
|
100
|
+
`).trim():""}function XP(e){if(!Array.isArray(e))return null;let t=e.filter(n=>n&&n.type==="tool_use").map(n=>n.name).filter(Boolean);return t.length?t:null}function ZP(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function gm(e){let t=[],n=e?.message?.content;if(!Array.isArray(n))return t;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)t.push({mediaType:r.source.media_type||"image/png",data:r.source.data,toolUseId:null});else if(r.type==="tool_result"&&Array.isArray(r.content))for(let o of r.content)o?.type==="image"&&o.source?.type==="base64"&&o.source.data&&t.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return t}function Z0(e,t){if(!e.uuid)return null;let n=gm(e).map((r,o)=>({uuid:e.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&t.get(r.toolUseId)||null}));return n.length?n:null}async function ym(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await Nt(e,t)}catch{return[]}let o=[],s=new Map,a=new Map;for(let i of r.split(`
|
|
101
|
+
`)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let x=y?.type==="tool_use"?y.input?.file_path||y.input?.path:null;typeof x=="string"&&QP.test(x)&&s.set(y.id,x.split("/").pop()),y?.type==="tool_use"&&y.name==="Skill"&&y.id&&a.set(y.id,String(y.input?.skill||"").trim().replace(/^\//,"")||null)}if(ZP(u.content)){let y=Z0(l,s);y&&o.push({role:"assistant",text:"",images:y,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=YP(u.content),f=d==="assistant"?XP(u.content):null,w=d==="user"?Z0(l,s):null;if(!p&&!f&&!w)continue;let m=d==="user"&&l.isMeta&&typeof l.sourceToolUseID=="string"&&l.sourceToolUseID?{toolUseId:l.sourceToolUseID,skill:a.get(l.sourceToolUseID)??null}:null,g=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:Li({error:l.error,status:l.apiErrorStatus,text:p})}:null;o.push({role:d,text:p,tools:f||void 0,images:w||void 0,injected:m||void 0,ts:l.timestamp?Date.parse(l.timestamp):null,model:u.model||null,apiError:g||void 0})}return o.slice(-n)}async function Q0(e,t,{turns:n=16}={}){let r=JP(e,t);if(!r)return"";let o=await ym(r,{limit:n});return o.length?o.map(s=>{let a=s.role==="user"?"User":"Lead agent",i=s.tools?`_(also ran: ${s.tools.join(", ")})_`:"",c=s.images?.length?"(viewed an image)":"(took an action)";return`**${a}:** ${eD(s.text||c,700)} ${i}`.trim()}).join(`
|
|
102
|
+
|
|
103
|
+
`):""}var QP,eD,xu=W(()=>{ku();dn();QP=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;eD=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import tD from"node:fs/promises";import{execFile as nD}from"node:child_process";import{promisify as rD}from"node:util";function rx(e){km=typeof e=="function"?e:null}function xm(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function ox({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||ex.has(r)||(ex.add(r),tx=tx.then(()=>sD({sessionName:e,from:t,to:r})).catch(()=>{}))}async function sD({sessionName:e,from:t,to:n}){await pe({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await bm("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await tD.realpath(r),s=xm(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await bm("npm",["install","-g","@openai/codex"],{env:a,timeout:oD});let i=(await bm(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await pe({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await nx({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await pe({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await nx({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function nx(e){if(km)try{await km(e)}catch{}}var bm,oD,ex,tx,km,vu=W(()=>{In();bm=rD(nD),oD=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,ex=new Set,tx=Promise.resolve(),km=null});function iD(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
|
|
104
|
+
`);if(!sx.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(aD);if(u)o.unshift({n:Number(u[1]),label:u[2]}),s=!0;else{if(s&&r[l].trim()==="")continue;if(s){var a=r[l].trim();break}}}if(o.length<2)return null;let i=o.sort((l,u)=>l.n-u.n);if(i.some((l,u)=>l.n!==u+1))return null;let c=typeof a=="string"&&sx.test(a)?a:"The agent is asking for approval";return{provider:t,box:n,promptId:`${t}:${c}:${i.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Approval",multiSelect:!1,options:i.map(l=>({label:l.label,description:""}))}]}}function qr(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
|
|
105
|
+
`);for(let r=n.length-1;r>=0;r--)if(cx.test(n[r]))return n.slice(r).join(`
|
|
106
|
+
`);return t}function cD(e){let t=String(e).trim();if(!t)return!1;let n=(t.match(/[A-Za-z]/g)||[]).length;return n>=3&&n/t.length>=.5}function lD(e){return/device code/i.test(e)?"works from the device you're reading this on":/sign in with chatgpt/i.test(e)?"opens a browser link on the node itself \u2014 can't finish from another device":""}function uD(e,t=""){let n=qr(e);if(Fi.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
|
|
107
|
+
`),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(ax);if(!u)continue;s<0&&(s=l);let d="";for(let p=l+1;p<Math.min(l+3,r.length);p++){let f=r[p].trim();if(f){if(ax.test(r[p])||/^Press enter/.test(f))break;d=f;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:d})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!cx.test(r[l])&&cD(u)&&i.push(u)}let c=i.join(" ").slice(0,400)||"Codex isn't signed in on this box \u2014 choose a sign-in method";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:Math.max(0,a.findIndex(l=>l.cursor)),answerMode:"keys",promptId:`codex:signin:${a.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Sign in",multiSelect:!1,options:a.map(l=>{let u=lD(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function fD(e,t=""){let n=qr(e);if(Fi.test(n)||!dD.test(n))return null;let r=n.trimEnd().split(`
|
|
108
|
+
`).pop()||"";return pD.test(r)?{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"codex:signin-complete",questions:[{question:"Codex successfully signed in and is waiting to open the session.",header:"Signed in",multiSelect:!1,options:[{label:"Continue",description:""}]}]}:null}function hD(e,t=""){let n=qr(e);if(Fi.test(n)||!ix.test(n))return null;let r=n.split(`
|
|
109
|
+
`),o=r.findIndex(i=>ix.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(mD);if(c){s=c[1];break}}if(!s)return null;let a=(n.match(/https:\/\/\S+/)||[])[0]||"https://auth.openai.com/codex/device";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:`codex:device-code:${s}`,questions:[{question:`Codex is waiting for you to finish signing in: open ${a} and enter code ${s} (expires in 15 minutes). The code goes straight to OpenAI \u2014 bostrat never sees your login. This card clears once OpenAI confirms.`,header:"Sign in",multiSelect:!1,options:[{label:"Cancel sign-in",description:"Go back to the sign-in options"}]}]}}function wD(e,t=""){let n=qr(e);return Fi.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-browser",questions:[{question:"Codex started its browser sign-in, which opens on the box itself and can't complete from another device. Go back and choose \u201CSign in with Device Code\u201D instead.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function gD(e,t=""){let n=qr(e);return Fi.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-apikey",questions:[{question:"Codex is asking for an OpenAI API key. For safety a key can only be typed in the Terminal tab, never through chat. To use your ChatGPT subscription instead, go back and pick a sign-in option.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function yD(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||vm.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
110
|
+
`).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function kD(e,t=""){let n=String(e);if(!bD.test(n)||vm.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
111
|
+
`),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function xD(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||vm.test(n)?null:{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:"cursor:signin-qr",questions:[{question:"Cursor is showing a QR sign-in code in the Terminal tab \u2014 scan it from another device to log in. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function lx(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=fD(t,n)||hD(t,n)||wD(t,n)||gD(t,n)||uD(t,n);if(r)return r}if(e==="cursor"){let r=kD(t,n)||xD(t,n)||yD(t,n);if(r)return r}return iD(t,{provider:e,box:n})}function ux(e,t){let n=Array.isArray(t?.[0])?t[0]:[],o=(Number.isInteger(n[0])&&n[0]>=0?n[0]:0)+1;return String(o)}var aD,sx,Fi,cx,ax,dD,pD,ix,mD,vm,bD,Su=W(()=>{aD=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,sx=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Fi=/(^|\n)\s*›/,cx=/^\s*Welcome to Codex\b|^\s*(?:│\s*)?>_ OpenAI Codex\b/;ax=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;dD=/Successfully logged in\./,pD=/^\s*Press Enter to continue\.\s*$/;ix=/Enter this one-time code/,mD=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;vm=/Run Everything|Add a follow-up|Plan, search, build anything/;bD=/click this link to log in|Signing in with the browser/});function TD(e){let t=String(e||"").replace(/\r/g,"").split(`
|
|
112
|
+
`),n=-1;for(let c=t.length-1;c>=0;c--)if(t[c].trim()){n=c;break}if(n<0)return!1;let r=t[n];if(SD.test(r)||AD.test(r)){for(let c=n-1;c>=0&&n-c<=64;c--)if(/^\s*›/.test(t[c]))return!0}let s=String(e||""),a=s.split(`
|
|
113
|
+
`).filter(c=>/^\s*›/.test(c)),i=a.some(c=>/^\s*›\s+(?:Ask Codex to do anything|Implement \{feature\})\s*$/.test(c));return a.length>0&&!i&&/esc to interrupt|\bWorking \(/.test(s)}function RD(e){let t=String(e||"");if(!Ze.codex.block.test(t))return null;let n=qr(t);if(!Ze.codex.block.test(n))return null;let r=n.match($D);return{from:r?.[1]||null,to:r?.[2]||null}}function Rn(e){return new Promise(t=>setTimeout(t,e))}function Sm(e,t){let n=Date.now(),r=OD();for(let[s,a]of Tu)n-a>=r&&Tu.delete(s);let o=`${e}::${t}`;return Tu.has(o)?!1:(Tu.set(o,n),!0)}function mx(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
|
|
114
|
+
`),r=-1;for(let o=n.length-1;o>=0;o--)if(fx.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
|
|
115
|
+
`)}function CD(e){let t=0;for(let n of String(e).split(`
|
|
116
|
+
`))fx.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Am(e,t){let n=Ze[e];if(!n?.busy)return{state:"idle",reason:null};if(Em(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(mx(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=CD(t);return e==="claude"&&r>0&&r<MD?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Tm(e,t){return Am(e,t).state}function hx(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
|
|
117
|
+
`).slice(-PD).join(`
|
|
118
|
+
`);return ND.test(n)}function ea(e,t){return Tm(e,t)==="busy"}function Ui(e,t){return Tm(e,t)!=="idle"}function Wo(e,t){let n=Ze[e];return n?.up?n.up.test(t):!0}function DD(e,t){let n=Ze[e];return n?Em(e,t)?!1:n.up.test(t)&&Tm(e,t)==="idle":!0}function Em(e,t){let n=Ze[e];if(!n)return!1;let r=e==="codex"?qr(t):t;return n.auth?.test(r)&&!n.up.test(r)?!0:n.block?.test(r)?e==="codex"?!0:!n.up.test(r):!1}function _m(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
|
|
119
119
|
`);for(let o=r.length-1;o>=0;o--)if(r[o].includes(n))return r.slice(o+1).join(`
|
|
120
|
-
`);return e}function
|
|
121
|
-
`)?!0:Buffer.byteLength(e,"utf8")>=
|
|
122
|
-
`).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(
|
|
123
|
-
`).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(
|
|
124
|
-
`))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return
|
|
125
|
-
${o}`.trim()||t.slice(0,2e3)}function
|
|
126
|
-
`):""}async function
|
|
120
|
+
`);return e}function wx(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function dx(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 px(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await Lo(e).catch(()=>{});;){let l=_m(await De(e),o);if(DD(t,l))return await s?.(),await Rn(Qs),"up";if(Ze[t]?.up&&!Ze[t].up.test(l))if(await or(e)){if(c??=Date.now(),Date.now()-c>=Ci()){let u=dx(t);throw pe({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"&&ID.test(l)&&!Ze.claude.up.test(l))return pe({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&_D.test(l)&&!Ze.codex.up.test(l)&&i<3){if(!Sm(e,"codex-trust")){await Rn(Au);continue}i+=1,await pe({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await at(e,"",{enter:!0,kind:"codex-trust-accept"}),await Rn(Qs);continue}if(t==="cursor"&&ED.test(l)&&!Ze.cursor.up.test(l)&&i<3){if(!Sm(e,"cursor-trust")){await Rn(Au);continue}i+=1,await pe({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await at(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await Rn(Qs);continue}if(t==="codex"&&i<3){let u=RD(l);if(u){if(!Sm(e,`codex-update:${u.from}->${u.to}`)){await Rn(Au);continue}i+=1,await pe({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await at(e,"3",{enter:!1,kind:"codex-update-skip"}),ox({sessionName:e,from:u.from,to:u.to}),await Rn(Qs);continue}}if(Date.now()>a){if(Em(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'),pe({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await or(e)){let u=dx(t);throw pe({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}return console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),pe({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(mx(Ze[t],l))}).catch(()=>{}),await Rn(Qs),"timeout"}await Rn(Au)}}function Hi({agent:e,agentCmd:t}={}){let n=t?Ur(t):Ur(e||"");return{label:n,realClaude:t?jo(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 gx({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=Hi({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function qo({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o,onBlocked:s}={}){let{realCodex:a,realCursor:i}=Hi({agent:n,agentCmd:r});return!t||!a&&!i?null:sr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},c=>{try{BD(c,{onBlocked:s,agent:n,sessionName:t})}catch{}})}function BD(e,{onBlocked:t=null,agent:n=null,sessionName:r=null}={}){if(typeof t!="function"||!e||e.code==="cli-not-running")return!1;let o=String(typeof e=="string"?e:e.message??"").trim();return o?(t({message:o,agent:n??null,sessionName:r??null}),!0):!1}async function sr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=vD(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=Hi({agent:r,agentCmd:o});if(u&&e&&await Cr(e),d&&e&&await Cs(e),p&&e&&await Ns(e),(u||d||p)&&n)return await px(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});let f=Ze[r]?r:Ze[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await px(n,f,s,{launchEcho:i}):(await Rn(Qs),"settle")}var vD,Au,Qs,SD,AD,Ze,ED,_D,ID,$D,OD,Tu,MD,fx,ND,PD,ta=W(()=>{ft();di();Ul();Hl();vu();Su();In();vD=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Au=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Qs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,SD=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,AD=/^\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:TD},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/}},ED=/Trust this workspace|\[a\]\s*Trust/,_D=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,ID=/Resume from summary/i,$D=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;OD=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Tu=new Map;MD=68,fx=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;ND=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,PD=15});function UD(e){return typeof e!="string"||!e?!1:e.includes(`
|
|
121
|
+
`)?!0:Buffer.byteLength(e,"utf8")>=FD}function On(e,t){return e==="codex"?{enter:!0,submitDelayMs:jD,...UD(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:LD}:{enter:!0}}var jD,LD,FD,Wi=W(()=>{jD=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),LD=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),FD=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function qi(e,t){if(e==="codex")return GD(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
|
|
122
|
+
`).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(yx.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(yx.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(HD);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 GD(e){let t=String(e).replace(/\r/g,"").split(`
|
|
123
|
+
`).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(WD.test(t[o])||qD.test(t[o]))&&!Im.test(t[o])?n=o:Im.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(Im);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(KD.test(s))return null;r.unshift(s)}return null}function $m(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Ue(n.replace(VD,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Ue(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Ue(e){return String(e||"").replace(/\s+/g," ").trim()}function bx(e,t,{slackMs:n=2e4}={}){let r=Ue(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&&Ue(a.text).includes(r));return s>=0&&s<o.length-1}function kx(e,t,n,{busy:r=!1}={}){let o=qi(e,n);return o&&Eu(t,o)||o&&e==="codex"&&$m(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Eu(e,t){let n=Ue(e),r=Ue(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var yx,HD,Im,WD,qD,KD,VD,Ki=W(()=>{yx=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,HD=/^❯[ ]?(.*)$/,Im=/^\s*›[ ]?(.*)$/,WD=/\S+ · \S/,qD=/^\s*(?:\? for shortcuts|tab to queue message)\b/,KD=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;VD=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function Vi({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say",stats:a=null},i={}){let c=(i.now||Date.now)(),l=(F,B,T={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:F,retries:T.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!T.sawUp,reason:T.reason??null}),B);if(!zD.has(t))return l("skipped",!0);let u=i.waitForUp??gx({agent:t,agentCmd:n}),d=i.capture||(F=>De(F,{lines:Xe})),p=i.pressEnter||(F=>Ge(F,["Enter"],{kind:"submit-retry"})),f=i.sleep||ZD,w=i.now||Date.now,m=i.log||(F=>pe(F).catch(()=>{})),g=i.maxMs??XD(),y=w()+g,x={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},b=0,I=0,$=0,P=!1;for(await f(Gi[0]);;){let F=await d(e).catch(()=>""),B=Wo(t,F),T=ea(t,F),_=kx(t,r,F,{busy:T});if(_==="submitted")return l("submitted",!0,{retries:b,sawUp:!0});if(u&&(!B||_==="stuck"&&T)){if(w()>=y)return _==="stuck"?(m({...x,phase:"submit-failed",reason:"stuck-at-deadline",retries:b}),l("failed",!1,{retries:b,sawUp:P,reason:"stuck-at-deadline"})):(m({...x,phase:"submit-unverified",reason:P?"cli-down":"cli-never-up",retries:b,waitedMs:g}),l("unverified",!0,{retries:b,sawUp:P,reason:P?"cli-down":"cli-never-up"}));await f(JD);continue}if(P=!0,_==="stuck"){if(b>=YD)return m({...x,phase:"submit-failed",retries:b}),l("failed",!1,{retries:b,sawUp:!0,reason:"stuck"});b+=1,I=0,$=0,await p(e),m({...x,phase:"submit-retry",attempt:b}),await f(Gi[0]);continue}if(I+=1,I>=Gi.length||w()>=y)return l("assumed",!0,{retries:b,sawUp:!0});$+=1,await f(Gi[Math.min($,Gi.length-1)])}}var zD,Gi,JD,YD,XD,ZD,Rm=W(()=>{ft();ta();Ki();In();zD=new Set(["claude","codex"]),Gi=[250,450,700],JD=500,YD=2,XD=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},ZD=e=>new Promise(t=>setTimeout(t,e))});function xx(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function ar(e){let t=xx(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of QD){let o=0;for(let s of eB[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function vx(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))tB.has(r)&&(t+=o||0),nB.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function zi(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 Sx(e){let t=xx(e).trim();return t?oB.test(t)?!0:t.split(/\s+/).length<=rB:!1}var QD,eB,tB,nB,rB,oB,_u=W(()=>{QD=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],eB={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/]};tB=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),nB=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);rB=12,oB=/^\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 _x(e){let t=zi(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||sB.has(r)||n.push(r);return n}function aB(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(Ex(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(Ex(n,"assistant",o))}}return t}function Ex(e,t,n){let r=ar(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 Ji(e){let t=aB(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=_x(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,d]of l){let p=n.get(u);p||n.set(u,p=new Map),p.set(i,d)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function Iu(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(_x(t))];if(!i.length)return[];let c=new Map;for(let u of i){let d=e.postings.get(u);if(!d)continue;let p=d.size,f=Math.log(1+(e.N-p+.5)/(p+.5));for(let[w,m]of d){let g=e.lengths[w],y=m+Ax*(1-Tx+Tx*(g/(e.avgdl||1))),x=f*(m*(Ax+1)/y);c.set(w,(c.get(w)||0)+x)}}let l=[];for(let[u,d]of c){let p=e.chunks[u];o&&p.role!==o||s&&!p.tags.includes(s)||a&&p.boxId!==a||l.push({chunk:p,score:d})}return l.sort((u,d)=>d.score-u.score||d.chunk.seq-u.chunk.seq),l.slice(0,r)}var Ax,Tx,sB,Om=W(()=>{_u();Ax=1.5,Tx=.75,sB=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 $u from"node:fs/promises";import Ix from"node:path";async function iB(e){let t=Ix.join(e,".bostrat","events"),n;try{n=await $u.readdir(t)}catch{return Ji([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await $u.readFile(Ix.join(t,o),"utf8");for(let a of s.split(`
|
|
124
|
+
`))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return Ji(r)}function cB(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}
|
|
125
|
+
${o}`.trim()||t.slice(0,2e3)}function lB(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Iu(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(),d=u.length>800?u.slice(0,800)+"\u2026":u,p=`- **${l}:** ${d}`;if(i+p.length>r||(a.push(p),i+=p.length,a.length>=n))break}return a.length?["",`## ${$x}, 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(`
|
|
126
|
+
`):""}async function Rx(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await $u.readFile(t,"utf8");if(a.includes($x))return{appended:!1,reason:"already-enriched"};let i=await iB(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=lB(i,cB(a),{k:r,maxChars:o,exclude:s});return c?(await $u.appendFile(t,`
|
|
127
127
|
`+c),{appended:!0,chars:c.length,chunks:c.split(`
|
|
128
|
-
- `).length-1,indexed:i.N}):{appended:!1,reason:"no-hits",indexed:i.N}}catch(a){return{appended:!1,reason:"error",error:a?.message||String(a)}}}var
|
|
129
|
-
`).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function
|
|
128
|
+
- `).length-1,indexed:i.N}):{appended:!1,reason:"no-hits",indexed:i.N}}catch(a){return{appended:!1,reason:"error",error:a?.message||String(a)}}}var $x,Ox=W(()=>{Om();$x="Relevant prior discussion (verbatim, retrieved"});function hB(e){return uB.test(String(e||"").trimStart())}function Nx(e){let t=String(e||"");if(!hB(t.trimStart()))return null;let n=t.replace(dB,"").trim(),r=wB(n),o=[];for(let u of fB){let d=u.from.map(p=>na(r.get(p))).find(p=>p&&!Mx(p));d&&o.push({h:u.h,text:Yi(d,pB)})}let s=na(r.get("Current Work"))||na(r.get("Primary Request and Intent"))||yB(n),a=Ou(s),i=Yi(Ru(Nm(a[0]||"")),mB)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Yi(Ru(Nm(l)),Cm));for(let u of["Pending Tasks","Optional Next Step"]){let d=Ou(na(r.get(u)))[0]||"";if(!(!d||Mx(d))){c.push(Yi(`Left to do: ${Ru(Nm(d))}`,Cm));break}}if(!c.length){let u=Ou(na(r.get("Problem Solving"))||"")[0];u&&c.push(Yi(Ru(u),Cm))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function wB(e){let t=new Map,n=[];Mm.lastIndex=0;for(let r=Mm.exec(e);r;r=Mm.exec(e))n.push({name:gB(r[1]),start:r.index,end:r.index+r[0].length});for(let r=0;r<n.length;r++){let o=n[r+1]?.start??e.length;t.has(n[r].name)||t.set(n[r].name,e.slice(n[r].end,o).trim())}return t}function gB(e){return Cx.find(n=>n.toLowerCase()===e.toLowerCase())||e}function na(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
|
|
129
|
+
`).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function yB(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return na(t.split(/\n{2,}/).slice(0,2).join(" "))}function Ou(e){let t=String(e||"").trim();if(!t)return[];let r=t.replace(/\b([A-Za-z0-9_-]+)\.(js|ts|tsx|mjs|json|md|css|jsonl|sh|yml|yaml|py|html)\b/g,"$1<DOT>$2").replace(/\b(e\.g|i\.e|etc|vs|approx|no|fig|Dr|Mr|Ms|St)\./gi,"$1<DOT>").split(/(?<=[.!?])["')\]]?\s+(?=[A-Z"“'(\[]|\d)/).map(s=>s.replace(/<DOT>/g,".").trim()).filter(Boolean),o=[];for(let s of r){let a=o[o.length-1];a&&(a.match(/["“”]/g)?.length??0)%2===1?o[o.length-1]=`${a} ${s}`:o.push(s)}return o}function Nm(e){return String(e||"").replace(/^(?:Immediately before (?:this|the) summary(?: request)?[,:]?\s*|At the (?:time|point) of (?:this )?compaction[,:]?\s*|Currently[,:]?\s*|The (?:most recent|immediately preceding|current) work (?:was|is)\s*)/i,"").replace(/^(?:I(?:'m|'d| am| was| had| have)?\s+(?:currently\s+|just\s+)?(?:been\s+)?(?:working on|in the middle of|completing|finishing)\s+|The user(?:'s)?\s+(?:most recent\s+)?(?:request|ask) (?:was|is)\s+(?:to\s+)?)/i,"").replace(/^I(?:'m|'d| am| was| had| have)?\s+(?:just\s+|then\s+)?(?=(?:[a-z]+(?:ed|ing)|ran|wrote|built|made|began|found|left|sent|took|went|did|got|kept|held|brought|caught|chose|came|saw|said|gave|told|set|put|read)\b)/,"").replace(/^["“]|["”]$/g,"").replace(/^(\w)/,t=>t.toUpperCase()).trim()}function Ru(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function Mx(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function Yi(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Ou(n),o="";for(let i of r){let c=o?`${o} ${i}`:i;if(c.length>t)break;o=c}if(o.length>=Math.min(60,t*.4))return o;let s=n.slice(0,t),a=s.lastIndexOf(" ");return`${(a>t*.6?s.slice(0,a):s).replace(/[,;:.\s]+$/,"")}\u2026`}var uB,Cx,Mm,dB,pB,fB,mB,Cm,Px=W(()=>{uB=/^This session is being continued from a previous conversation that ran out of context\./,Cx=["Primary Request and Intent","Key Technical Concepts","Files and Code Sections","Errors and Fixes","Problem Solving","All user messages","Pending Tasks","Current Work","Optional Next Step"],Mm=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${Cx.join("|")})[:*\t ]*$`,"gim"),dB=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,pB=420,fB=[{h:"What we were doing",from:["Primary Request and Intent"]},{h:"Key decisions",from:["Key Technical Concepts"]},{h:"Where it got to",from:["Current Work","Problem Solving"]},{h:"Left to do",from:["Pending Tasks","Optional Next Step"]}],mB=116,Cm=168});function jx(e){return Pm.has(String(e||"").replace(/^\//,"").toLowerCase())}function Xi(e){let t=String(e||"").trim();if(!t)return null;let n=Nx(t);if(n)return n;let r=t.match(bB);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(kB);if(o)return{kind:"skill",name:o[1]};let s=t.match(xB);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(vB);if(a){let c=a[1].toLowerCase();return Pm.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(MB);if(i&&Pm.has(i[1].toLowerCase()))return{kind:"suppress"};if(SB.test(t))return{kind:"suppress"};if(TB.test(t))return{kind:"suppress"};if(AB.test(t))return{kind:"suppress"};if(EB.test(t)){let c=u=>DB(t.match(u)?.[1].trim()||"")||null,l=c(OB);return{kind:"task",summary:c(_B)||"",taskId:c(IB),toolUseId:c($B),status:c(RB)?.toLowerCase()||null,resultHead:l?l.length>Dx?`${l.slice(0,Dx).trimEnd()}\u2026`:l:null}}return null}function Lx(e){let t=Xi(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function Fx(e){let t=String(e||""),n=t.match(CB);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(NB);return r?{kind:"shell-output",stdout:Bx(r[1]),stderr:Bx(r[2])}:null}function DB(e){return e.replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/&/g,"&")}function Ux(e){return e?.kind==="skill"?`Ran the ${e.name} skill`:e?.kind==="command"?`Ran ${e.command}`:e?.kind==="task"?e.summary||"A background task finished":e?.kind==="resume-summary"?e.title?`Context resumed from summary: ${e.title}`:"Context resumed from summary":""}function Hx(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var bB,kB,xB,vB,SB,AB,TB,EB,_B,IB,$B,RB,OB,Dx,Pm,MB,CB,NB,PB,Bx,Mu=W(()=>{Px();bB=/^Base directory for this skill:\s*(\S+)/,kB=/^Run the "([^"]+)" workflow\./,xB=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,vB=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,SB=/^<local-command-(?:stdout|caveat)>/i,AB=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,TB=/^Continue from where you left off\.$/,EB=/^<task-notification>/i,_B=/<summary>([\s\S]*?)<\/summary>/i,IB=/<task-id>([\s\S]*?)<\/task-id>/i,$B=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,RB=/<status>([\s\S]*?)<\/status>/i,OB=/<result>([\s\S]*?)(?:<\/result>|$)/i,Dx=600,Pm=new Set(["model","clear","compact","login","exit","quit"]);MB=/^\/([a-z0-9:_-]+)$/i;CB=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,NB=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,PB=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,Bx=e=>String(e||"").replace(PB,"").replace(/^\n+/,"").replace(/\s+$/,"")});import BB from"node:crypto";function UB(e){let t=Array.isArray(e)?e:Array.isArray(e?.questions)?e.questions:null;if(!t||!t.length)return null;let n=[];for(let r of t.slice(0,qx)){let o=ra(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,jB)){let c=ra(i?.label);if(!c)return null;let l=ra(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<LB)return null;n.push({question:o,header:ra(r?.header).slice(0,FB),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Dm(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;Wx.lastIndex=0;let t=null;for(let o;o=Wx.exec(e);)t=o;if(!t||t.index+t[0].length<e.trimEnd().length)return null;let n;try{n=JSON.parse(t[2])}catch{return null}let r=UB(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Bm(e,t,n){let r=BB.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function jm(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=qx}={}){if(!Array.isArray(e)||!t||!n)return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||Dm(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Bm(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",custom:!0,dismissable:!0,multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function Kx(e,t,n,r){let o=[];(e?.questions||[]).forEach((i,c)=>{let l=(t?.[c]||[]).map(d=>i.options?.[d]?.label).filter(Boolean),u=ra(Array.isArray(r)?r[c]:"");u&&l.push(u),l.length&&o.push({name:i.header||i.question,picks:l.join(", ")})});let s=ra(n),a;return o.length?o.length===1?a=`${o[0].name}: ${o[0].picks}`:a=`Answers:
|
|
130
130
|
${o.map(i=>`- ${i.name}: ${i.picks}`).join(`
|
|
131
131
|
`)}`:a=s,o.length&&s&&(a+=`
|
|
132
|
-
${s}`),a||""}var
|
|
132
|
+
${s}`),a||""}var qx,jB,LB,FB,Wx,ra,Gx,Lm=W(()=>{qx=4,jB=4,LB=2,FB=24,Wx=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,ra=e=>typeof e=="string"?e.trim():"";Gx=`
|
|
133
133
|
When you are BLOCKED on a decision only the operator can make \u2014 an ambiguous
|
|
134
134
|
requirement, an irreversible choice, several valid approaches \u2014 do not bury the
|
|
135
135
|
question in prose. End your message with exactly ONE fenced code block tagged
|
|
@@ -150,82 +150,82 @@ your turn. The operator sees the questions as an interactive card in their chat
|
|
|
150
150
|
They may instead reply in free text \u2014 treat that as the answer. Never use the block for rhetorical questions, progress updates, or
|
|
151
151
|
anything you can decide yourself; keep asking in prose for questions without
|
|
152
152
|
enumerable options.
|
|
153
|
-
`});function E1(e){return{id:e.id,kind:"prompt",groupId:e.groupId,provider:e.provider,box:e.box,agent:e.provider,questionTotal:e.questions.length,answeredVia:"chat",questions:e.questions.map((t,n)=>({index:n,header:t.header||"",question:t.question,multiSelect:!!t.multiSelect,chosen:[]})),ts:e.ts}}function Fx(e,t,n){let r=Dh(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function Mn(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Map,l=new Set,u=new Map,d=new Map,p=(x,m)=>{d.set(x,m),t.push(m)},f=x=>{let m=d.get(x);m&&(m.retired=!0)},w=/^Agent "([\s\S]+)" finished$/,h=new Map;for(let x of e||[]){if(x.type!=="tool.called"||x.source!=="transcript")continue;let m=String(x.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(m))for(let v of m.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let P=v[0].split("/").pop().toLowerCase();h.has(P)||h.set(P,[]),h.get(P).push(x.payload?.ts??x.ts)}}let g=3*6e4,y=20*6e4,k=(x,m)=>!!(x?.name&&h.get(String(x.name).toLowerCase()))?.some(P=>P>=m-g&&P<=m+y);for(let x of e||[])if(x.type==="turn.retracted"){r.add(`${x.boxId}|${x.payload?.saidTs}`);let m=Ue(x.payload?.text);m&&(o.has(x.boxId)||o.set(x.boxId,[]),o.get(x.boxId).push(m))}else if(x.type==="turn.user"&&x.source==="orchestrator"){let m=Ue(x.payload?.text);m&&(s.has(x.boxId)||s.set(x.boxId,new Set),s.get(x.boxId).add(m))}else if(x.type==="job.stalled"&&x.payload?.id)i.set(x.payload.id,{ts:he(x),quietMs:Number(x.payload.quietMs)||null});else if(x.type==="job.started"&&x.payload?.id)a.add(x.payload.id),(x.payload.kind||"agent")==="agent"&&x.payload.name&&l.add(x.payload.name);else if(x.type==="turn.user"&&x.payload?.note?.kind==="task"){let m=x.payload.note,v={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:he(x)};m.toolUseId&&c.set(m.toolUseId,v);let P=String(m.summary||"").match(w);P&&u.set(P[1],v)}let b=new Map,I=new Map,R=null,N=new Map,D=new Map,j=new Map,T=new Map,$=new Map,F=new Map,J=new Map,M=new Map,S=new Map,_=new Map,H=new Map,K=new Map,X=new Map,pe=new Map,Oe=new Map,Me=[],Q=x=>Me.push(x),qe=x=>{if(!Me.length)return;let m=he(x);for(let v of Me){if(v.status!=="open"||v.box&&v.box!==x.boxId||(v.ts??0)>m)continue;let P=t.indexOf(v);P>=0&&t.splice(P,1),v.ts=m,t.push(v)}},Ae=new Map,Z=new Map,me=new Map,Te=new Map,z=new Map,ge=new Map,Ge=new Map,O=new Map,Y=()=>{for(let x of O.values())x.questions.length&&t.push(x);O.clear()},Le=null,Qe=new Map,oe=6e4,ye=new Map,Fe=(x,m)=>{let v=o.get(x);if(!v?.length)return!1;let P=Ue(m),ce=s.get(x);return v.some(be=>{if(!P.startsWith(be))return!1;let Ne=Ue(P.slice(be.length));return!!Ne&&!!ce?.has(Ne)})};for(let x of e||[]){let m=x.payload||{};switch(x.type){case"turn.user":{if(x.source==="hook"||(Me.length=0,!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length))break;{let v=Mx(m.text);if(v){if(v.kind==="shell-input"){let P={id:x.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:he(x),box:x.boxId,agent:x.provider};t.push(P),Qe.set(x.boxId,P)}else{let P=Qe.get(x.boxId);P?(P.stdout=v.stdout||null,P.stderr=v.stderr||null,P.done=!0,Qe.delete(x.boxId)):t.push({id:x.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:he(x),box:x.boxId,agent:x.provider})}break}}{let v=m.note||Ji(m.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let P=String(v.summary||"").match(w);if(!v.toolUseId&&P&&l.has(P[1]))break}if(v.kind==="command"&&Rx(v.command))break;if(v.kind==="resume-summary"){t.push({id:x.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:he(x),box:x.boxId,agent:x.provider});break}v.kind!=="suppress"&&t.push({id:x.id,kind:"event",type:Nx(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:he(x),box:x.boxId,agent:x.provider});break}}if(r.has(`${x.boxId}|${he(x)}`)||x.source==="transcript"&&Fe(x.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){t.push({id:x.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:he(x),box:x.boxId,agent:x.provider});break}if(m.kind==="mock-picked"||m.kind==="ci-fix"||m.kind==="reconcile"||m.kind==="pr-go"||m.kind==="push-go"||m.kind==="spin-up-view"||m.kind==="prompt-answer"||m.kind==="followup-go"){m.kind==="prompt-answer"&&(Le=null);break}for(let v of N.values())v.status="stale";N.clear();for(let v of j.values())v.status="stale";j.clear();for(let v of X.values())v.status="stale";X.clear(),Le&&Le.box===x.boxId&&(t.push(E1(Le)),Le=null),t.push({id:x.id,kind:"message",role:"user",text:m.text,ts:he(x),box:x.boxId,agent:x.provider,boxRole:m.boxRole,...x.actor==="orchestrator"?{orchestration:m.kind||!0}:{},...m.sourceId?{sourceId:m.sourceId}:{},...m.attachments?.length?{attachments:m.attachments}:{},...m.images?.length?{images:m.images}:{}});break}case"peer.message":{let v=m.from||{};t.push({id:x.id,kind:"event",type:"peer-message",text:m.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:he(x),box:x.boxId,agent:x.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let v=W0(m,{codexFailedText:Fo});if(v){t.push({id:x.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:x.provider,legacy:!0,at:he(x),ts:he(x),box:x.boxId,agent:x.provider});break}Y();let P=(m.images||[]).filter(rt=>!k(rt,he(x)));if(!String(m.text||"").trim()&&!P.length)break;if(x.provider==="cursor"){let rt=`${x.boxId}|${m.text}`;if(n.has(rt))break;n.add(rt)}(!Le||Le.box===x.boxId)&&(Le=null);let ce=x.provider==="codex"?(m.tools||[]).filter(rt=>!ph.has(rt)&&!Di.has(rt)):m.tools||[],be=m.text,Ne=null,gt=Mh(String(m.text||""));gt&&(be=gt.text,Ne={questions:gt.questions}),t.push({id:x.id,kind:"message",role:"assistant",text:be,ts:he(x),box:x.boxId,agent:x.provider,boxRole:m.boxRole,...Ne?{ask:Ne}:{},...ce.length?{tools:ce}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...P.length?{images:P}:{}}),qe(x),Ne&&(Le={id:x.id,groupId:Ch(x.provider,m.sourceId||x.id,Ne.questions),provider:x.provider,box:x.boxId,questions:Ne.questions,ts:he(x)});break}case"job.started":{if(!m.id)break;let v=he(x),P=c.get(m.id);if(!P&&(m.kind||"agent")==="agent"&&m.name){let lt=u.get(m.name);lt&<.ts>=v&&(P=lt)}let ce=P?null:i.get(m.id)||null,be={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:P?P.status==="killed"?"stopped":P.status&&P.status!=="completed"?"failed":"done":ce?"stalled":"running",startedTs:v,finishedTs:P?.ts??ce?.ts??null,quietMs:ce?.quietMs??null,summary:P?.summary??null,resultHead:P?.resultHead??null},Ne=ye.get(x.boxId),gt=Ne?.jobs[Ne.jobs.length-1]?.startedTs;if(Ne&>!=null&&v-gt<=oe)Ne.jobs.push(be);else{let lt={id:x.id,kind:"job-dock",dockId:m.id,ts:v,box:x.boxId,agent:x.provider,jobs:[be]};ye.set(x.boxId,lt),t.push(lt)}break}case"handoff.done":t.push(mt(x,"lead-handoff"));break;case"subtask.delegated":t.push({...mt(x,"subtask-delegated"),to:x.boxId,toAgent:x.provider});break;case"subtask.merged":t.push(mt(x,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let P of N.values())P.status="stale";N.clear();for(let P of j.values())P.status="stale";j.clear()}let v=mt(x,`pr-${m.change}`);if(v.box=x.boxId??null,Lx.has(m.change)&&m.number!=null){let P=Fx(b,I,m);if(b.size>=2){for(let be of I.values())for(let Ne of be)Ne.grouped=!0;v.groupPrs=[...b.values()];let ce=[v];for(let be of b.keys())I.set(be,ce)}else{let ce=I.get(P)??[];ce.push(v),I.set(P,ce)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let P=Dh(m),ce=R&&!R.complete||b.size>=2;if(b.has(P))b.delete(P),I.delete(P);else if(m.number!=null)for(let be of[...b.keys()])be.endsWith(`#${m.number}`)&&(b.delete(be),I.delete(be));if(ce&&m.number!=null){(!R||R.complete)&&(R={id:x.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:he(x),ts:he(x),box:x.boxId,agent:x.provider},t.push(R)),R.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:he(x)}),R.remaining=[...b.values()],R.complete=b.size===0;break}}t.push(v);break}case"pr.offered":{if(!m.offerId)break;for(let P of N.values())P.status="stale";N.clear();for(let P of j.values())P.status="stale";j.clear();let v={id:x.id,kind:"pr-offer",offerId:m.offerId,excerpt:m.excerpt||null,branch:m.branch||null,base:m.base||null,offered:Array.isArray(m.offered)&&m.offered.length?m.offered:null,toPr:m.toPr&&typeof m.toPr=="object"?{number:m.toPr.number??null}:null,available:Array.isArray(m.available)?m.available:null,defaults:Array.isArray(m.defaults)?m.defaults:null,prState:m.prState||null,openPr:m.openPr&&typeof m.openPr=="object"?m.openPr:null,repos:Array.isArray(m.repos)&&m.repos.length?m.repos:null,status:"open",source:x.source==="cli"||m.via==="cli"?"cli":"transcript",ts:he(x),box:x.boxId,agent:x.provider};N.set(m.offerId,v),D.set(m.offerId,v),t.push(v),v.source==="cli"&&Q(v);break}case"pr.offer.answered":{let v=D.get(m.offerId);v&&(v.status=m.action||"dismiss",v.actions=Array.isArray(m.actions)?m.actions:null,v.notify=m.notify===!0,m.existingPr&&typeof m.existingPr=="object"&&(v.existingPr={number:m.existingPr.number??null}),N.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let P of j.values())P.status="stale";j.clear();let v={id:x.id,kind:"pr-exists-offer",offerId:m.offerId,srcOfferId:m.srcOfferId??null,branch:m.branch||null,base:m.base||null,pr:m.pr&&typeof m.pr=="object"?{number:m.pr.number??null,url:m.pr.url??null,title:m.pr.title??null}:null,actions:Array.isArray(m.actions)&&m.actions.length?m.actions:null,notify:m.notify===!0,status:"open",ts:he(x),box:x.boxId,agent:x.provider};j.set(m.offerId,v),T.set(m.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=T.get(m.offerId);v&&(v.status=m.choice||"dismiss",j.delete(m.offerId));break}case"box.state.changed":{let v=m.change==="model"?"model-change":m.change;if(!v)break;let P=mt(x,v);if(v==="model-change"&&(P.to=m.model),v==="node-update"&&P.latest){let ce=t.findIndex(be=>be.kind==="event"&&be.type==="node-update"&&be.latest===P.latest);if(ce>=0){let be=t[ce];t[ce]={...P,ts:be.ts,at:be.at,firstAt:be.firstAt??be.ts,updatedAt:P.ts};break}}t.push(P);break}case"track.transferred":case"track.recovered":t.push(mt(x,"track-moved"));break;case"view.state.changed":{if(m.change==="deleted"){f(`view:${m.viewId}`);break}if(m.change!=="created"||m.restarted)break;p(`view:${m.viewId}`,{id:x.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:he(x),box:x.boxId,agent:x.provider});break}case"view.spinup.failed":{t.push({id:x.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:he(x),box:x.boxId,agent:x.provider});break}case"mock.state.changed":{if(m.change==="picked"){t.push({id:x.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:he(x),box:x.boxId,agent:x.provider});break}if(m.change==="deleted"){f(`mock:${m.mockId}`);break}if(m.change!=="created")break;p(`mock:${m.mockId}`,{id:x.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:he(x),box:x.boxId,agent:x.provider});break}case"flow.state.changed":{if(m.change==="deleted"){f(`flow:${m.flowId}`);break}if(m.change!=="created")break;p(`flow:${m.flowId}`,{id:x.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:he(x),box:x.boxId,agent:x.provider});break}case"runbook.state.changed":{if(m.change==="deleted"){f(`runbook:${m.runbookId}`);break}if(m.change!=="created")break;p(`runbook:${m.runbookId}`,{id:x.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:he(x),box:x.boxId,agent:x.provider});break}case"ticket.linked":{t.push({id:x.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:he(x),box:x.boxId,agent:x.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let P of J.values())P.box===(m.box||x.boxId)&&(P.status="stale",J.delete(P.offerId));let v={id:x.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:he(x),box:m.box||x.boxId,agent:m.agent||x.provider};J.set(m.offerId,v),M.set(m.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=M.get(m.offerId);v&&(v.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",J.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let P of $.values())P.key===m.key&&(P.status="stale",$.delete(P.offerId));let v={id:x.id,kind:"ticket-offer",offerId:m.offerId,provider:m.provider||"linear",key:m.key,url:m.url??null,phase:m.phase??null,from:m.from??null,to:m.to?.name??null,prNumber:m.prNumber??null,status:"open",ts:he(x),box:x.boxId,agent:x.provider};$.set(m.offerId,v),F.set(m.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=F.get(m.offerId);v&&(v.status=m.action==="moved"?"moved":"dismiss",$.delete(m.offerId));break}case"ticket.state.changed":{for(let v of $.values())v.key===m.key&&v.to===m.to&&(v.status="stale",$.delete(v.offerId));if(m.mode==="offer")break;t.push(mt(x,"ticket-state"));break}case"ticket.commented":{t.push({id:x.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:he(x),box:x.boxId,agent:x.provider});break}case"ticket.flow.changed":t.push(mt(x,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let P of S.values())P.status="stale";S.clear();let v={id:x.id,kind:"ticket-create-offer",proposalId:m.proposalId,provider:m.provider||"linear",epic:m.epic??null,issues:Array.isArray(m.issues)?m.issues:[],team:m.team??null,needsTeam:!!m.needsTeam,linkCurrentTrack:!!m.linkCurrentTrack,status:"open",ts:he(x),box:x.boxId,agent:x.provider};S.set(m.proposalId,v),_.set(m.proposalId,v),t.push(v),Q(v);break}case"ticket.create.answered":{let v=_.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",v.createdCount=m.createdCount??null,v.failedCount=m.failedCount??null,S.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let P of H.values())P.status="stale";H.clear();let v={id:x.id,kind:"loop-create-offer",proposalId:m.proposalId,name:m.name??"",schedule:m.schedule??"",prompt:m.prompt??"",expectation:m.expectation??null,notify:m.notify??"off",assignment:m.assignment??{provider:"claude"},repo:m.repo??null,nodeId:m.nodeId??null,nodeName:m.nodeName??null,status:"open",ts:he(x),box:x.boxId,agent:x.provider};H.set(m.proposalId,v),K.set(m.proposalId,v),t.push(v),Q(v);break}case"loop.create.answered":{let v=K.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",H.delete(m.proposalId));break}case"followup.armed":{if(!m.armId)break;let v=m.replaces?Oe.get(m.replaces):null;v&&v.status==="armed"&&(v.status="replaced");let P={id:x.id,kind:"followup-armed",armId:m.armId,trigger:m.trigger??"now",label:m.label??"",prompt:m.prompt??"",why:m.why??null,status:"armed",ts:he(x),box:x.boxId,agent:x.provider};Oe.set(m.armId,P),P.trigger!=="now"&&t.push(P);break}case"followup.armed.cancelled":{let v=Oe.get(m.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!m.offerId)break;for(let ce of X.values())ce.trigger===m.trigger&&(ce.status="stale",X.delete(ce.offerId));let v=Array.isArray(m.rows)?m.rows:[];for(let ce of v){let be=ce.armId?Oe.get(ce.armId):null;be&&be.status==="armed"&&(be.status="offered")}let P={id:x.id,kind:"followup-offer",offerId:m.offerId,trigger:m.trigger??"now",repo:m.repo??null,context:m.context&&typeof m.context=="object"?m.context:{},rows:v.map(ce=>({followupId:ce.followupId??null,armId:ce.armId??null,label:ce.label??"",prompt:ce.prompt??null,promptPreview:ce.promptPreview??null,promptHash:ce.promptHash??null,origin:ce.origin??"operator",why:ce.why??null})),status:"open",answer:null,ts:he(x),box:x.boxId,agent:x.provider};X.set(m.offerId,P),pe.set(m.offerId,P),t.push(P),P.trigger==="now"&&Q(P);break}case"followup.answered":{let v=pe.get(m.offerId);v&&(v.status=m.action==="sent"?"sent":m.action==="removed"?"removed":"dismiss",v.answer={followupId:m.followupId??null,armId:m.armId??null,label:m.label??null,promoted:m.promoted??null,revived:m.revived===!0},X.delete(m.offerId));break}case"followup.create.offered":{if(!m.proposalId)break;for(let P of Ae.values())P.status="stale";Ae.clear();let v={id:x.id,kind:"followup-create-offer",proposalId:m.proposalId,label:m.label??"",prompt:m.prompt??"",trigger:m.trigger??"pr.merged",repo:m.repo??null,why:m.why??null,status:"open",created:null,ts:he(x),box:x.boxId,agent:x.provider};Ae.set(m.proposalId,v),Z.set(m.proposalId,v),t.push(v),Q(v);break}case"followup.create.answered":{let v=Z.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",Ae.delete(m.proposalId));break}case"followup.created":{let v=m.proposalId?Z.get(m.proposalId):null;v&&(v.created={followupId:m.followupId??null});break}case"loop.created":{let v=m.proposalId?K.get(m.proposalId):null;v&&(v.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(mt(x,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!m.proposalId||!m.loopId)break;for(let ce of me.values())ce.loopId===m.loopId&&(ce.status="stale",ce.staleReason="superseded",me.delete(ce.proposalId));let v=x.type==="loop.update.offered",P={id:x.id,kind:v?"loop-update-offer":"loop-delete-offer",proposalId:m.proposalId,loopId:String(m.loopId),name:m.name??m.base?.name??"",base:m.base??null,...v?{patch:m.patch??{},changed:Array.isArray(m.changed)?m.changed:Object.keys(m.patch||{})}:{reason:m.reason??""},selfEdit:!!m.selfEdit,status:"open",staleReason:null,ts:he(x),box:x.boxId,agent:x.provider};me.set(m.proposalId,P),Te.set(m.proposalId,P),t.push(P),Q(P);break}case"loop.update.answered":{let v=Te.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",me.delete(m.proposalId));break}case"loop.delete.answered":{let v=Te.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",me.delete(m.proposalId));break}case"loop.updated":{let v=m.proposalId?Te.get(m.proposalId):null;v&&(v.applied={changed:Array.isArray(m.changed)?m.changed:[],nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(mt(x,"loop-updated"));break}case"loop.deleted":t.push(mt(x,"loop-deleted"));break;case"loop.paused":t.push(mt(x,"loop-paused"));break;case"planning.change.offered":{if(!m.proposalId||!Array.isArray(m.ops)||!m.ops.length)break;for(let P of z.values())P.status="stale",P.staleReason="superseded",z.delete(P.proposalId);let v={id:x.id,kind:"planning-offer",proposalId:m.proposalId,why:m.why??"",ops:m.ops,base:m.base??{},resolved:m.resolved??{},snapped:!!m.snapped,createsMeRow:!!m.createsMeRow,status:"open",staleReason:null,applied:null,ts:he(x),box:x.boxId,agent:x.provider};z.set(m.proposalId,v),ge.set(m.proposalId,v),t.push(v),Q(v);break}case"planning.change.answered":{let v=ge.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",z.delete(m.proposalId));break}case"planning.changed":{let v=m.proposalId?ge.get(m.proposalId):null;v&&(v.applied={results:Array.isArray(m.results)?m.results:[]}),t.push(mt(x,"planning-changed"));break}case"rework.cause.offered":{if(!m.sha||Ge.has(m.sha))break;let v={id:x.id,kind:"rework-cause-offer",sha:m.sha,subject:m.subject??"",linesReworked:Number(m.linesReworked)||0,origins:Array.isArray(m.origins)?m.origins:[],heuristic:m.heuristic??null,intent:m.intent??null,shas:Array.isArray(m.shas)?m.shas:null,pr:m.pr??null,retracts:0,status:"open",cause:null,ts:he(x),box:x.boxId,agent:x.provider};Ge.set(m.sha,v),t.push(v);break}case"rework.cause.answered":{let v=m.sha?Ge.get(m.sha):null;v&&(v.status="answered",v.cause=m.cause??null);break}case"rework.cause.retracted":{let v=m.sha?Ge.get(m.sha):null;v&&(v.status="open",v.cause=null,v.retracts=(v.retracts??0)+1);break}case"ticket.created":{let v={items:Array.isArray(m.items)?m.items:[],failed:Array.isArray(m.failed)?m.failed:[],team:m.team??null},P=m.proposalId?_.get(m.proposalId):null;if(P){P.created=v;break}t.push({id:x.id,kind:"ticket-created",...v,ts:he(x),box:x.boxId,agent:x.provider});break}case"error":{if(!m.kind)break;t.push(mt(x,m.kind));break}case"provider.error":t.push({...mt(x,"provider-error"),provider:x.provider,box:x.boxId,agent:x.provider});break;case"usage.cap.hit":t.push(mt(x,"usage-cap-hit"));break;case"usage.cap.warning":t.push(mt(x,"usage-cap-warning"));break;case"provider.connected":{t.push({id:x.id,kind:"event",type:"provider-connected",provider:m.provider||x.provider,ts:he(x),at:he(x),box:x.boxId,agent:x.provider});break}case"prompt.answered":{if(Le=null,m.control||!m.question)break;let v=m.groupId||m.promptId;if(!v)break;let P=O.get(v);P||(P={id:x.id,kind:"prompt",groupId:v,provider:x.provider,box:x.boxId,agent:x.provider,questionTotal:m.questionTotal??1,questions:[],ts:he(x)},O.set(v,P));let ce=m.questionIndex??0,be={index:ce,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},Ne=P.questions.findIndex(rt=>rt.index===ce&&Ue(rt.question)===Ue(be.question));Ne>=0?P.questions[Ne]=be:P.questions.push(be),P.questions.sort((rt,lt)=>rt.index-lt.index),P.questionTotal=Math.max(P.questionTotal,m.questionTotal??1),P.questions.length>=P.questionTotal&&(t.push(P),O.delete(v));break}case"prompt.dismissed":{Le=null;let v=m.groupId||m.promptId;if(!v||!m.question)break;let ce=O.get(v)||{id:x.id,kind:"prompt",groupId:v,provider:x.provider,box:x.boxId,agent:x.provider,questionTotal:m.questionTotal??1,questions:[],ts:he(x)},be=m.questionIndex??0;ce.questions.some(Ne=>Ne.index===be&&Ue(Ne.question)===Ue(m.question))||(ce.questions.push({index:be,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:[]}),ce.questions.sort((Ne,gt)=>Ne.index-gt.index)),ce.answeredVia="chat",t.push(ce),O.delete(v);break}default:break}}let jt=d.size?t.filter(x=>!x.retired):t;return I1(jt.sort((x,m)=>(x.ts??0)-(m.ts??0)))}function I1(e){let t=new Map,n=[];for(let r of e){if(r.kind!=="message"||!r.box){n.push(r);continue}let o=r.role==="assistant"&&!String(r.text||"").trim()&&r.images?.length,s=t.get(r.box);if(o&&s&&(r.ts??0)-s.lastTs<=_1){s.item.images.push(...r.images),s.lastTs=r.ts??s.lastTs;continue}if(o){let a={...r,images:[...r.images]};t.set(r.box,{item:a,lastTs:r.ts??0}),n.push(a)}else t.delete(r.box),n.push(r)}return n}function Bh(e,t=null){let n=[];for(let o of e||[]){if(o.type!=="tool.called"||o.source!=="transcript")continue;let s=o.payload||{};String(s.command||"").trim()&&n.push({id:s.id??null,tool:s.tool||null,command:s.command,description:s.description||"",summary:$1(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??Mn(e)).filter(o=>o.kind==="message");return P0(n,r)}function $1(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==Ys(e.command)?t:Ur(e.command,e.description||"")}function mt(e,t){let{ts:n,change:r,kind:o,...s}=e.payload||{};return{id:e.id,kind:"event",type:t,...s,at:he(e),ts:he(e)}}function Ux(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||r.type!=="archived")continue;let o=(r.ts??0)+R1,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&O1.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Hx(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!C1.has(r.type)||!r.box)continue;let o=(r.ts??0)+M1,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||!(a?.kind==="message"&&a.role==="assistant"&&a.box===r.box||a?.kind==="command-batch"&&a.anchorBox===r.box))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Ru(e){return(e||[]).filter(t=>N1.has(t?.kind)&&t.status==="open")}function Wx(e){let t=new Map,n=new Map;for(let r of e||[]){if(r.type!=="pr.state.changed")continue;let o=r.payload||{};if(Lx.has(o.change)&&o.number!=null)Fx(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=Dh(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var he,Lx,Dh,_1,R1,O1,M1,C1,N1,Ou=W(()=>{Xs();Uo();gu();Wi();$u();Ph();he=e=>e.payload?.ts??e.ts;Lx=new Set(["opened","ci-fixed","reconciled","pushed"]),Dh=e=>`${e.repo??""}#${e.number}`;_1=2*6e4;R1=12e4,O1=new Set(["archived","unarchived","opened"]);M1=2500,C1=new Set(["pr-opened","pr-merged","pr-auto-armed"]);N1=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","planning-offer","fullscreen-offer","followup-create-offer"])});function L1(e){let t=null,n=null,r=null;for(let o of e??[]){let s=o?.ts??null;s&&(r=Math.max(r??0,s)),o?.type==="handoff.artifact"&&(t={ts:o.payload?.ts??s,truncated:!!o.payload?.truncated,...o.payload?.reconstructed?{reconstructed:!0}:{}}),o?.type==="code.pushed"&&(n={ts:o.payload?.ts??s,sha:o.payload?.sha??null,ref:o.payload?.ref??null,wip:!!o.payload?.wip})}return{lastArtifact:t,lastPush:n,lastEventAt:r}}function U1(e){for(let t=(e?.length??0)-1;t>=0;t--){let n=e[t];if(n?.type==="handoff.artifact"&&!n.payload?.reconstructed)return n}return null}function H1(e,t){let n=[],r=[],o=new Set,s=new Set;for(let a=(e?.length??0)-1;a>=0;a--){let i=e[a];if(i?.type!=="tool.called")continue;if(t!=null&&(i.ts??0)<=t)break;let c=i.payload||{};c.path&&!o.has(c.path)&&n.length<B1&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<j1&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function Vx(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=L1(e),s=U1(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Mn(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-P1);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(Gx[r]??Gx.failover),l.push(""),o.lastPush?.sha){let p=Kx(n,o.lastPush.ts),f=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${f}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let p=Kx(n,i);l.push(`## Last real checkpoint (written by the previous agent${p?`, ~${p} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=H1(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(p=>`\`${p}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(p=>`\`${p}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let p of c)l.push(`**${p.role==="user"?"operator":"agent"}:** ${F1(p.text,D1)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let d=l.join(`
|
|
154
|
-
`);return d.length<=
|
|
155
|
-
|
|
156
|
-
[\u2026 brief truncated]`}var
|
|
157
|
-
|
|
158
|
-
[\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function Z1(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(Xx.test(s)){if(r.length>=cv)continue;let a=X1(s.replace(Xx,"").replace(/[.;,:]+$/,""),lv,J1);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>Yx&&(o=`${o.slice(0,Yx-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function uv(e,t,{timeoutMs:n=9e4}={}){let r=qr.join(t,V1),o=qr.join(r,z1);await Wr.mkdir(r,{recursive:!0});let s=await Mu(o),a=await ke(e);if(!a)throw new Error(`session "${e}" not found`);return await Cu(e,a,Y1(o)),await gv(o,s,n),Z1(await Wr.readFile(o,"utf8"))}function dv(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===ov||n===iv;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(rv)||n===q1||r.startsWith(sv)||r.startsWith(av)}function pv(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-Q1;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 fv(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 hv(e,{windows:t=[]}={}){if(dv(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 Nu(e){return jh.get(e)||null}async function mv(e){let t=jh.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:qr.join(n.cwd,ev,tv)};return jh.set(e,r),nB(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function nB(e,t){e.step="summarize",await wv(e.name,t),e.step="clear";let n=await ke(e.name);await Cu(e.name,n,"/clear"),await Lh(eB),e.step="resume",await Cu(e.name,n,G1),e.step="done",e.finishedAt=Date.now()}async function wv(e,t,{timeoutMs:n=tB}={}){let r=qr.join(t,ev),o=qr.join(r,tv);await Wr.mkdir(r,{recursive:!0});let s=await Mu(o),a=await ke(e);await de({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Cu(e,a,K1(o)),await gv(o,s,n),await de({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Mu(o)});let i=await vx(t,o,{exclude:u=>dv(u.role,u.text)});await de({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await C({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 Wr.readFile(o,"utf8");await C({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...nv(u),ts:Date.now()}})}catch{}}await Ff(t);let l=await rB(r,o);return c&&await t0(c,l||o,{box:e,agent:a?.agent??null}),o}async function Pu(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 wv(e,n.cwd,t?{timeoutMs:t}:void 0)}async function Du(e,t,{trackName:n="this Track"}={}){let r=await q({id:e,cwd:t}),o=Vx(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=qr.join(t,Zx);return await Wr.mkdir(qr.dirname(s),{recursive:!0}),await Wr.writeFile(s,o,"utf8"),await C({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...nv(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Zx}async function Mu(e){try{return(await Wr.stat(e)).mtimeMs}catch{return 0}}async function gv(e,t,n){let r=Date.now()+n;for(;;){if(await Mu(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await Lh(2e3)}}async function rB(e,t){try{if(!W1.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=qr.join(e,`${n}.md`);return await Wr.copyFile(t,r),r}catch{return null}}function Lh(e){return new Promise(t=>setTimeout(t,e))}function Qx(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 Cu(e,t,n){if(t){let o=Qx(t.agent);await rr({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 ze(e,["Escape"],{kind:"drive-wipe"}),await Lh(150),await Gs(e,hu,{kind:"drive-wipe"}),await it(e,n,{kind:"orchestration-drive",...On(r.agent,n)}),await Ki({sessionName:e,agent:r.agent,agentCmd:Qx(r.agent),text:n,flow:"orchestration-drive"})}var ev,tv,Jx,rv,ov,sv,q1,K1,G1,av,iv,V1,z1,Yx,cv,lv,J1,Y1,Xx,X1,Q1,eB,tB,jh,Zx,Fh=W(()=>{ht();ea();In();Ui();Eh();Sx();bi();fe();su();zx();ev=".bostrat/handoff",tv="latest.md",Jx=32*1024;rv="Checkpoint: write a work-in-progress handoff",ov="HANDOFF WRITTEN",sv="Resume from .bostrat/handoff/latest.md",q1="/clear",K1=e=>`${rv} 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 ${ov} and take no further action.`,G1=`${sv}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,av="Beat: write a",iv="BEAT WRITTEN",V1=".bostrat/arc",z1="beat.txt",Yx=200,cv=4,lv=5,J1=36,Y1=e=>`${av} 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 ${cv} further lines, each starting with "- " and naming ONE piece in at most ${lv} 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 ${iv} and take no further action.`,Xx=/^(?:[-–—*•·]|\d+[.)])\s+/,X1=(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};Q1=6e5;eB=3500,tB=3e5,jh=new Map;Zx=".bostrat/handoff/status-latest.md"});function Gr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Bu.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 kv(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:Gr(o.from,"from",n),toMs:Gr(o.to,"to",n)}))}return t}function Hh(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 sB(e){if(!e)return null;let t=String(e).trim();return Kr[t]?t:yv[t]?yv[t]:Object.keys(Kr).find(r=>t.startsWith(r))||null}function aB(e){if(!e||e===Kr)return oB;let t=bv.get(e);return t||(t=kv(e),bv.set(e,t)),t}function xv(e,t,n={}){let{table:r,speed:o}=n,s=aB(r),a=r&&r!==Kr?s[e]?e:null:sB(e);if(!a)return null;let i=Hh(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 Cn(e,t={},n,r){let o=xv(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 iB(e=Kr){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:Gr(a.from,"from",n),toMs:Gr(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`),Bu.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 lB({now:e=Date.now(),table:t=Kr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...cB,...n},a=[],i=Hh(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(d=>({...d,fromMs:Gr(d.from,"from",c),toMs:Gr(d.to,"to",c),verifiedMs:Bu.test(String(d.verifiedAt??""))?Date.parse(`${d.verifiedAt}T00:00:00.000Z`):NaN}))}catch(d){a.push(String(d.message));continue}for(let d of u){if(!Number.isFinite(d.verifiedMs)){a.push(`${c}: window ${d.from??"\u2026"} \u2192 ${d.to??"now"} has no verifiedAt`);continue}let p=i>=d.fromMs&&i<=d.toMs,f=d.fromMs>i&&d.fromMs-i<=o*Uh;p&&i-d.verifiedMs>r*Uh&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),f&&d.fromMs-d.verifiedMs>s*Uh&&a.push(`${c}: scheduled rate change on ${d.from} was last verified ${d.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function ra({now:e=Date.now(),table:t=Kr,...n}={}){let r=Hh(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Gr(l.from,"from",i),d=Gr(l.to,"to",i);r>=u&&r<=d&&Bu.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=[...iB(t),...lB({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Kr,yv,Bu,oB,bv,vv,cB,Uh,sr=W(()=>{Kr={"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)."}]},yv={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"},Bu=/^\d{4}-\d{2}-\d{2}$/;oB=kv(Kr);bv=new WeakMap;vv=(e,t,n)=>xv(e,t,n)!==null;cB=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Uh=864e5});function uB(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Av(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Xt(e){let t=e.payload?.model||"unknown",n=uB(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=Cn(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&&!vv(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Vr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(p=>p.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=Sv();for(let p of n){let{usd:f,model:w,tokens:h,repriced:g,unpriced:y,asRecorded:k}=Xt(p);i+=k;let b=p.provider||"unknown",I=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(w)),a+=f,Av(d,h),r[w]||={usd:0,tokens:Sv(),events:0},r[w].usd+=f,r[w].events+=1,Av(r[w].tokens,h),o[b]||={usd:0,events:0},o[b].usd+=f,o[b].events+=1,s[I]||={usd:0,events:0,provider:b,models:new Set,label:t[I]||I},s[I].usd+=f,s[I].events+=1,w!=="unknown"&&s[I].models.add(w),p.epoch!=null){let R=(s[I].epochs||={})[p.epoch]||={usd:0,events:0,provider:b,models:new Set};R.usd+=f,R.events+=1,R.provider=b,w!=="unknown"&&R.models.add(w)}}return{totalUsd:oa(a),asRecordedUsd:oa(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:ju(r,p=>({...p,usd:oa(p.usd)})),byProvider:ju(o,p=>({...p,usd:oa(p.usd)})),byBox:ju(s,p=>({usd:oa(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:ju(p.epochs,f=>({usd:oa(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var Sv,oa,ju,zr=W(()=>{sr();Sv=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});oa=e=>Math.round(e*1e4)/1e4,ju=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function dB(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 Tv(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 d=u.payload||{};!d.repo||d.number==null||(d.change==="merged"?o.set(`${d.repo}#${d.number}`,d):d.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(d=>{let[p,f]=d.split("#");return`${p.split("/").pop()}#${f}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Wh(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Wh(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(d=>`${d.fromAgent}\u2192${d.toAgent}`).join(", ");n.push(`${Wh(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Vr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?dB(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Wh,Ev=W(()=>{zr();Wh=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as pB}from"node:child_process";import{promisify as fB}from"node:util";import{randomUUID as hB}from"node:crypto";async function qh(e,t){let n=Date.now()+t;for(;;){if(await nr(e))return!0;if(Date.now()>n)return!1;await Yi(mB)}}async function gB(e,t){let n=_v[t]||_v.default;n.escape&&(await ze(e,["Escape"],{kind:"swap-exit"}),await Yi(150)),n.wipe&&await Gs(e,hu,{kind:"swap-exit"}),await mu(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=On(t).submitDelayMs||0;await Yi(Math.max(r,250)),await ze(e,["Enter"],{kind:"swap-exit"})}async function Iv(e,t){try{let{stdout:n}=await qo(ne,re("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Ov(e){await qo(ne,re("respawn-pane","-k","-t",e))}async function Kh(e,{exitTimeoutMs:t=$v,fromAgent:n=null}={}){if(!De(e))throw new Error("invalid session name");let r=!1;if(await nr(e))return{forced:r};let o=n||(await ke(e))?.agent||"agent";if(await gB(e,o),!await qh(e,t)&&(r=!0,await de({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Ov(e),!await qh(e,Rv)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r}}async function Gh(e,t={}){if(!De(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||Lr(n),a=Number(t.exitTimeoutMs)||$v;await de({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let{forced:i}=await Kh(e,{exitTimeoutMs:a,fromAgent:o}),c=s==="claude"&&Bo(n),l=c?Dl():null,u=await Iv(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await qo(ne,re("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await qo(ne,re("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?cu(g,l):g}if(d&&!i&&(await Ov(e),!await qh(e,Rv)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||hB(),w=p?n:$i(n,f,e),h=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await Or(r.cwd),s==="codex"&&await Ms(r.cwd),s==="cursor"&&await Cs(r.cwd),await jo(e),await qo(ne,re("set-option","-t",e,"@bostrat-sid",f)),await qo(ne,re("set-option","-t",e,"@bostrat-agent",s)),await Yi(wB),c&&Ii().length&&(await Iv(e,_i)||await qo(ne,re("set-environment","-t",e,_i,"1")).catch(()=>{}),await it(e,`export ${_i}=1`,{kind:"swap-env"}),await Yi(150)),await it(e,w,{kind:"swap-launch"}),await de({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:f,forced:i,envRespawned:d}),{name:e,cwd:r.cwd,sessionId:f,agent:s,pinned:h,forced:i,envRespawned:d,launchCmd:w}}var qo,Yi,$v,Rv,mB,wB,_v,Mv=W(()=>{ht();li();jl();Ll();Ui();In();qo=fB(pB),Yi=e=>new Promise(t=>setTimeout(t,e)),$v=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Rv=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,mB=250,wB=400,_v={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"}}});function Vh(e=process.env){return!!(Ce(e)&&e.BOSTRAT_PLANE_TOKEN)}async function zh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!Vh(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),Cv);try{let a=await Nv(`${Ce(r)}/v1/loops/${encodeURIComponent(e)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:t,...n?{note:n}:{}}),signal:o.signal}),i=await a.json().catch(()=>({}));return a.ok?{ok:!0,source:"plane",status:a.status,run:i?.run||null}:{ok:!1,source:"plane",status:a.status,error:i?.error||`plane ${a.status}`}}catch(a){return{ok:!1,source:"unreachable",error:a?.message||String(a)}}finally{clearTimeout(s)}}async function Xi(e,{provider:t=null,cls:n="other",status:r=null,text:o="",note:s=null}={},{env:a=process.env,now:i=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!Vh(a))return{ok:!1,source:"unconfigured"};let c=Lu.get(e.id)||0;if(i()-c<yB)return{ok:!1,source:"debounced"};Lu.set(e.id,i());let l=await Zi({env:a}),u=l.loops.find(f=>f.trackId===e.id);if(!u)return Lu.delete(e.id),{ok:!1,source:l.source==="plane"?"no-loop":l.source};let d=s?String(s).replace(/\s+/g," ").trim():`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`,p=await zh({loopId:u.id,outcome:"errored",note:d.slice(0,500),env:a});return p.ok||Lu.delete(e.id),{...p,loop:{id:u.id,name:u.name}}}async function Zi({env:e=process.env}={}){if(!Vh(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),Cv);try{let r=await Nv(`${Ce(e)}/v1/loops`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},signal:t.signal});if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json();return{loops:Array.isArray(o?.loops)?o.loops:[],source:"plane"}}catch(r){return{loops:[],source:"unreachable",error:r?.message||String(r)}}finally{clearTimeout(n)}}var Cv,Nv,yB,Lu,Fu=W(()=>{yt();Cv=1e4,Nv=(...e)=>fetch(...e);yB=10*6e4,Lu=new Map});import{execFile as bB}from"node:child_process";import Uu from"node:fs/promises";import Jh from"node:path";import{promisify as kB}from"node:util";function _B(e){let n=String(e||"").trim().match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?/);return n?n[0]:null}async function IB(e,{env:t=process.env}={}){let n=String(e||"").trim();if(!n)return null;let r=n.includes("/")?[Jh.resolve(n)]:String(t.PATH||"").split(Jh.delimiter).filter(Boolean).map(o=>Jh.join(o,n));for(let o of r)try{await Uu.access(o,Uu.constants.X_OK);let s=await Uu.realpath(o),a=await Uu.stat(s);if(!a.isFile())continue;return{path:s,mtimeMs:a.mtimeMs}}catch{}return null}async function Ko({agent:e=null,agentCmd:t=null,env:n=process.env}={}){let r=String(t||(e?n[AB[e]]||SB[e]:"")||"").trim();if(!r)return null;let{realClaude:o,realCodex:s,realCursor:a}=Fi({agent:e,agentCmd:r});if(!(o||s||a))return null;let i=await IB(r.split(/\s+/)[0],{env:n});if(!i)return null;let c=`${i.path}@${i.mtimeMs}`;return Yh.has(c)||Yh.set(c,Promise.resolve().then(()=>EB(i.path,{agent:e})).then(l=>_B(l)).catch(()=>null)),Yh.get(c)}var xB,vB,SB,AB,Yh,TB,EB,Pv=W(()=>{ea();xB=kB(bB),vB=8e3,SB={claude:"claude",codex:"codex",cursor:"cursor-agent"},AB={claude:"BOSTRAT_AGENT_CMD",codex:"BOSTRAT_CODEX_CMD",cursor:"BOSTRAT_CURSOR_CMD"},Yh=new Map,TB=async e=>(await xB(e,["--version"],{timeout:vB})).stdout,EB=TB});function CB(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return Dv.test(String(e.content||""))?String(e.content):null;if(e.type==="attachment"){let n=e.attachment;return n?.type==="queued_command"&&n.commandMode==="task-notification"&&typeof n.prompt=="string"?n.prompt:null}let t=e.message?.content;return typeof t=="string"&&Dv.test(t)?t:null}async function Bv(e,t={}){return(await Lv(e,t)).launches}async function jv(e,t={}){let{launches:n,done:r}=await Lv(e,t);return n.filter(o=>!r.has(o.id))}async function Lv(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await Ct(e,t)}catch{return{launches:[],done:new Set}}let o=new Map,s=new Set,a=new Set,i=new Map;for(let l of r.split(`
|
|
159
|
-
`)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=
|
|
160
|
-
`).trim():"",
|
|
161
|
-
`),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 d=r[u].match(
|
|
162
|
-
`),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!
|
|
163
|
-
`),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(
|
|
164
|
-
`),o=-1;for(let u=r.length-1;u>=0;u--)if(
|
|
165
|
-
`),o=
|
|
166
|
-
`),o=
|
|
167
|
-
`),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=
|
|
168
|
-
`)].reverse().find(a=>
|
|
169
|
-
`),o=
|
|
170
|
-
`),o=-1;for(let l=r.length-1;l>=0;l--)if(r[l].trim()!==""){o=l;break}if(o<0)return null;let s=r[o].match(
|
|
171
|
-
`),o=
|
|
172
|
-
`).pop()||"")?!0:
|
|
173
|
-
`).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function Nn(e,t){return!e||!t?null:e.agent==="claude"?
|
|
174
|
-
${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];
|
|
175
|
-
`).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function
|
|
176
|
-
`).map(s=>s.trim()).filter(Boolean)}async function
|
|
177
|
-
`).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var
|
|
178
|
-
`),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function
|
|
179
|
-
`),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function
|
|
180
|
-
`);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function
|
|
181
|
-
`),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function FS(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim();if(e==="codex"){let[r,o]=n.split(/[\s:]+/);if(o&&!jS.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=LS.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!Cj.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function nc(e,t,{timeoutMs:n=Oj}={}){let r=Date.now()+n;for(;;){let o=await Pe(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Qu(Mj)}}async function Dj(e,t){return await it(e,`/model ${t.model}`,On("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function Bj(e,t){await fu(e),await it(e,"/model",{enter:!1}),await Qu(250),await ze(e,["Enter"],{kind:"model-switch"});let n=await nc(e,NS);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await ze(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${t.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=Pj(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await it(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await nc(e,i=>PS(i)||!NS(i)&&o(i)&&{done:o(i)});if(!s)throw await ze(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?jS.get(t.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await ze(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await it(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await nc(e,i=>!PS(i)&&o(i));if(!a)throw new Error("codex never confirmed the model change");return{verified:!0,model:a.model,effort:a.effort}}async function jj(){let e=CS.join(process.env.CURSOR_CONFIG_DIR||CS.join(Rj.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await $j.readFile(e,"utf8"))?.model||null}catch{return null}}async function Lj(e,t){await fu(e),await mu(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await nc(e,DS),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(t.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await nc(e,DS,{timeoutMs:1500});if(s=l?.rows.find(u=>u.active)||null,s&&o(s))break;if(!l||!l.rows.some(o)){s=null;break}await ze(e,["Down"],{kind:"model-switch"}),await Qu(250)}if(!n||!s||!o(s)){await ze(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await ze(e,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${t.filter}"`:"cursor model picker didn't open")}await ze(e,["Enter"],{kind:"model-switch"}),await Qu(800);let a=await jj();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function US(e,t,n){return e==="codex"?Bj(t,n):e==="cursor"?Lj(t,n):Dj(t,n)}var Qu,Oj,Mj,BS,Cj,Nj,jS,LS,HS=W(()=>{ht();Ui();Qu=e=>new Promise(t=>setTimeout(t,e)),Oj=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,Mj=300,BS=[{alias:"default",label:"Default"},{alias:"opus",label:"Opus 5"},{alias:"sonnet",label:"Sonnet 5"},{alias:"haiku",label:"Haiku 4.5"},{alias:"fable",label:"Fable 5.1"},{alias:"opusplan",label:"Opus Plan"}],Cj=new Set([...BS.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5","claude-fable-5-1"]),Nj=[{alias:"gpt-5.6-sol",label:"GPT-5.6 Sol"},{alias:"gpt-5.6-terra",label:"GPT-5.6 Terra"},{alias:"gpt-5.6-luna",label:"GPT-5.6 Luna"},{alias:"gpt-5.5",label:"GPT-5.5"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}],jS=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),LS=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5-high",label:"Opus 5"},{alias:"claude-fable-5-1-high",label:"Fable 5.1"},{alias:"claude-sonnet-5-high",label:"Sonnet 5"},{alias:"cursor-grok-4.6-high",label:"Cursor Grok 4.6"},{alias:"gpt-5.6-sol-high",label:"GPT-5.6 Sol High"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function nd(e){let t=e||{},n=Fj(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function Fj(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:ct(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint,cliVersion:e.cliVersion??null}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:ct(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:ct(e.agent),payload:{...Pn(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:ct(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Pn(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{change:"subtask-resumed",...Pn(e)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"model",model:e.to,from:e.from??null,verified:e.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:"codex",payload:{change:"cli-update",from:e.from??null,to:e.to??null,status:e.status,...e.error?{error:e.error}:{}}};case"node-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",payload:{change:"node-update",...Pn(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Pn(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Pn(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason,cliVersion:e.cliVersion??null}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{...Pn(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Pn(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{kind:"retag-failed",action:e.action??"reshape",reason:e.reason,rolledBack:e.rolledBack!==!1,...e.recovered?{recovered:!0}:{}}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};case"delivery-held":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{kind:"delivery-held",...Pn(e)}};case"startup-gate":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{kind:"startup-gate",...Pn(e)}};default:return null}}function KS(e,t){let n=nd(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;rd(()=>C(r,n))}async function GS(e){if(!(!e?.id||WS.has(e.id))){WS.add(e.id);try{let t=await q(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=nd(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await C(e,o)}}catch{}}}function Pn(e){let{type:t,at:n,...r}=e;return r}function VS(e,t,n){!n?.promptId||td.get(e.id)===n.promptId||(td.set(e.id,n.promptId),rd(()=>C(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:ct(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function zS(e,t,n,r={}){td.delete(e.id),rd(()=>C(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:ct(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function Rm(e,t,n,r={}){td.delete(e.id),rd(()=>C(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:ct(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var ct,ed,rd,qS,WS,td,Om=W(()=>{fe();ct=e=>e||null;ed=Promise.resolve(),rd=e=>(ed=ed.then(e).catch(()=>{}),ed),qS=()=>ed;WS=new Set;td=new Map});function Kj(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function eA(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of Kj(n).reverse()){if(!Uj.test(r))continue;let o=r.endsWith("?")&&r.length<=qj&&Wj.test(r);if(Hj.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function nA(e){let t=String(e||""),n=[];Gj.test(t)&&n.push("commit"),tA.test(t)&&n.push("rebase"),Vj.test(t)&&n.push("push");let r=Jj.test(t);!r&&zj.test(t)&&n.push("pr");let o=null;if(r){let s=t.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||t.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function rA(e){return tA.test(String(e||""))}function fa(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(f=>`${f.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let f=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${f} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${f} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let f=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",w=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${w}${f}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${f}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${w}${f}`:`push this branch${l} to the remote${f}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let d=[];a.has("commit")||d.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&d.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&d.push("don't push"),a.has("pr")||d.push("don't open a pull request");let p=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return d.length&&(p+=` ${d.join(", and ").replace(/^./,f=>f.toUpperCase())}.`),a.has("pr")&&(p+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),p}function oA(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(e)?e:["commit","push","pr"]),a=t?` on this branch (${t})`:"",i=[];s.has("commit")&&i.push(`commit the work${a} with a clear commit message`),s.has("rebase")&&i.push(`rebase ${s.has("commit")?"the branch":`this branch${t?` (${t})`:""}`} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`),i.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),i.push("push the new branch to the remote"),i.push(`open a pull request${n?` against ${n}`:""} from the new branch with a concise title and a description of what changed and why (use \`gh pr create\`)`);let c=[];s.has("commit")||c.push("don't create any new commits \u2014 ship what's already committed"),o&&!s.has("rebase")&&c.push("don't rebase \u2014 leave the branch's history as it is");let l=`Yes \u2014 go ahead, as a NEW pull request: ${i.join(", then ")}.`;return c.length&&(l+=` ${c.join(", and ").replace(/^./,u=>u.toUpperCase())}.`),l+=` Leave the existing open PR${r?` #${r}`:""}${t?` and its remote branch (${t})`:" and its remote branch"} exactly as they are \u2014 don't push ${t||"the old branch"} itself.`,l}function sA(e,t=Date.now()){let n=[],r=null;for(let o of e||[]){let s=o.payload||{},a=s.ts??o.ts;if(o.type==="pr.offer.answered"&&s.action==="pr"){r={box:o.boxId,from:a,lastActivity:a};continue}if(o.type==="pr.exists.answered"&&s.choice==="new"){r={box:o.boxId,from:a,lastActivity:a};continue}!r||a==null||a<r.from||(o.type==="pr.offer.answered"||o.type==="pr.exists.answered"?r=null:o.type==="pr.state.changed"&&s.change==="opened"?(n.push({box:r.box,from:r.from,to:a,settled:!0}),r=null):o.type==="turn.user"&&o.source!=="hook"&&!s.kind&&String(s.text||"").trim()?r=null:o.boxId===r.box&&/^(?:turn|tool)\./.test(o.type)&&(r.lastActivity=Math.max(r.lastActivity,a)))}return r&&t-r.lastActivity<=Yj&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function aA(e,t){let n=new Set;for(let r of t||[]){if(!r.settled)continue;let o=null;for(let s of e||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+Xj||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function iA(e){let t=(Array.isArray(e)?e:[]).filter(r=>JS[r]).map(r=>JS[r]);return`The ship you were given the go-ahead for${t.length?` (${t.join(", then ")})`:""} should now be complete. This is an automated ship notification the operator armed on the offer: carry straight on with this Track's follow-up work (dependent tasks, cleanup, next steps) \u2014 don't wait for review or merge. If a ship step failed or is unfinished, finish the ship first. If nothing needs doing, say so briefly.`}var YS,XS,ZS,QS,Uj,Hj,Wj,qj,to,Gj,tA,Vj,zj,Jj,Yj,Xj,JS,es=W(()=>{YS=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional|amend(?:ed)?|squash|merge|follow[\s-]?up|clean[\s-]?up)\s)commit(?!s\b)(?!\s+(?:history|log|message|hash|sha)s?\b)/.source,XS=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional)\s)push(?!\s+notifications?\b)(?:\s+(?:it|this|that|them|everything|the\s+\w+))?\s*(?:up)?/.source,ZS=/open(?:\s+up)?\s+(?:a|the|that)\s+(?:draft\s+)?(?:pr|pull\s+request)|creat(?:e|ing)\s+(?:a|the)\s+(?:draft\s+)?(?:pr|pull\s+request)|rais(?:e|ing)\s+(?:a|the)\s+(?:pr|pull\s+request)|put\s+up\s+(?:a|the)\s+(?:pr|pull\s+request)|send\s+(?:up\s+)?(?:a|the)\s+(?:pr|pull\s+request)/.source,QS=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|clean|interactive)\s)rebase(?!s\b)(?:\s+(?:it|this|that|them|(?:this|that|the)\s+branch))?(?:\s+(?:on(?:to)?|against|atop|over)\s+\S+)?/.source,Uj=new RegExp(`\\b(?:${YS}|${XS}|${ZS}|${QS})\\b`,"i"),Hj=/\b(?:want\s+me\s+to|would\s+you\s+like(?:\s+me)?(?:\s+to)?|should\s+i|shall\s+i|do\s+you\s+want(?:\s+me)?(?:\s+to)?|happy\s+to|ready\s+for\s+me\s+to|let\s+me\s+know\s+(?:if|when|whether|and)|say\s+the\s+word|give\s+me\s+the\s+(?:word|go[\s-]?ahead)|if\s+you(?:'d|\s+would)?\s+(?:like|want|prefer)|just\s+say\s+(?:so|yes|go))\b/i,Wj=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,qj=90;to=["commit","rebase","push","pr"],Gj=new RegExp(`\\b(?:${YS})\\b`,"i"),tA=new RegExp(`\\b(?:${QS})\\b`,"i"),Vj=new RegExp(`\\b(?:${XS})\\b`,"i"),zj=new RegExp(`\\b(?:${ZS})\\b`,"i"),Jj=/\b(?:to|into|onto|on|updat(?:e|es|ing))\s+(?:the|that|this)\s+(?:open\s+|existing\s+|current\s+|same\s+)?(?:draft\s+)?(?:pr|pull\s+request)\b/i;Yj=3e4;Xj=2500;JS={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import Zj from"node:crypto";import od from"node:fs/promises";import cA from"node:path";import Qj from"node:os";function pA(e){dA=typeof e=="function"?e:async()=>new Set}function eL(e,t,n){if(e.originNode&&e.originNode===t)return!0;let r=e.data?.trackId;return!!r&&n.has(r)}async function He(){return ir||(Mm??=od.readFile(Nm,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(ir=e,!t&&Ke()){let{records:n,source:r}=await dt("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){let o=Zk(),s=await dA().catch(()=>new Set),a=0;for(let i of n){if(i.deletedAt||!i.data?.repo||i.data?.number==null)continue;if(!eL(i,o,s)){a++;continue}let{id:c,updatedAt:l,...u}=i.data;ir[ae(u.repo,u.number)]=u}a&&console.log(`[pr-links] restore: ${Object.keys(ir).length} link(s) re-seeded, ${a} other-node record(s) left on the plane`),Object.keys(ir).length&&await Pm().catch(()=>{})}}return ir}).finally(()=>Mm=null),Mm)}async function Pm(){let e=JSON.stringify({links:ir},null,2),t=`${Nm}.${process.pid}.tmp`;await od.mkdir(lA,{recursive:!0}),await od.writeFile(t,e),await od.rename(t,Nm)}async function Ze(e){Cm=Cm.then(Pm,Pm),await Cm.catch(()=>{});let t=ir?.[e];t&&At("prlinks",{id:uA(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ut({repo:e,number:t,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!e||!Number.isInteger(Number(t))||!n)return{link:null,created:!1};let i=await He(),c=ae(e,t);return i[c]?{link:i[c],created:!1}:(i[c]={repo:e,number:Number(t),trackId:n,url:r,headRef:o,title:s,source:a,announced:tL.has(a),firstSeen:Date.now()},await Ze(ae(e,t)),{link:i[c],created:!0})}async function cr(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||n.announced?null:(n.announced=!0,await Ze(ae(e,t)),n)}async function fA(e,t){if(!e||t==null)return!1;let n=(await He())[ae(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await Ze(ae(e,t)),!0):!1}async function pt(e,t){return!e||t==null?null:(await He())[ae(e,t)]??null}async function no(e,t,n){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,delete r.followupPending,await Ze(ae(e,t)),r):null}async function hA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[ae(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Ze(ae(e,t)),o):null}async function mA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[ae(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Ze(ae(e,t)),o):null}async function sd(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Ze(ae(e,t)),r)}async function ad(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Ze(ae(e,t)),n)}async function id(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Ze(ae(e,t)),r)}async function cd(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Ze(ae(e,t)),n)}async function wA(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(r.baseFoldAt=n,await Ze(ae(e,t)),r):null}async function gA(e,t,{misses:n,until:r}){if(!e||t==null)return null;let o=(await He())[ae(e,t)];return o?(o.brokerRefused={misses:Number(n)||0,until:Number(r)||0},await Ze(ae(e,t)),o):null}async function yA(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return n?.brokerRefused?(delete n.brokerRefused,await Ze(ae(e,t)),n):null}async function bA(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Ze(ae(e,t)),n)}async function kA(e,t,n){if(!e||t==null||!n)return null;let r=(await He())[ae(e,t)];return r?(r.lastHeadSha=n,await Ze(ae(e,t)),r):null}async function xA(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await He())[ae(e,t)];if(!r)return{prev:null,link:null};let o=r.verdict??null;return o&&o.blocked===(n.blocked??null)&&(o.sha??null)===(n.sha??null)||(r.verdict={blocked:n.blocked??null,sha:n.sha??null,at:n.at??Date.now()},await Ze(ae(e,t))),{prev:o,link:r}}async function rc(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Ze(ae(e,t)),r):null}async function ts(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Ze(ae(e,t)),r):null}async function ns(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Ze(ae(e,t)),r):null}async function vA(e,t,n){if(!e||t==null)return null;let r=(await He())[ae(e,t)];if(!r)return null;r.notifyOnMerge=!0;let o=new Map((r.notifyPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.notifyPending=[...o.values()],await Ze(ae(e,t)),r}async function SA(e,t,n){if(!e||t==null)return null;let r=(await He())[ae(e,t)];if(!r)return null;let o=new Map((r.followupPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.followupPending=[...o.values()],await Ze(ae(e,t)),r}async function oc(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Ze(ae(e,t)),n)}async function AA(){return Object.values(await He()).filter(e=>!nL.has(e.state))}async function hn(){return Object.values(await He()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function TA(){if(!Ke())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await dt("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await He(),r=0;for(let[o,s]of Object.entries(n))await At("prlinks",{id:uA(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var lA,Nm,ae,uA,ir,Mm,Cm,dA,tL,nL,Dn=W(()=>{jr();lA=process.env.BOSTRAT_STATE_DIR||cA.join(process.env.HOME||Qj.tmpdir(),".bostrat"),Nm=cA.join(lA,"pr-links.json"),ae=(e,t)=>`${e}#${Number(t)}`,uA=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=Zj.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},ir=null,Mm=null,Cm=Promise.resolve(),dA=async()=>new Set;tL=new Set(["api","observed","reconciled"]);nL=new Set(["merged","closed","lost"])});import rL from"node:fs";import Dm from"node:fs/promises";import $A from"node:path";import oL from"node:os";function MA(e,t=!1){if(!t&&e-_A<sL)return;_A=e;let n=JSON.stringify({windowStart:ha,byCaller:Object.fromEntries(lr),lastHour:ro});IA=IA.then(()=>Dm.mkdir(RA,{recursive:!0})).then(()=>Dm.writeFile(`${ld}.tmp`,n)).then(()=>Dm.rename(`${ld}.tmp`,ld)).catch(()=>{})}function CA(e){e-ha<OA||(ro={start:ha,total:ud(lr),byCaller:Object.fromEntries(lr)},ro.total&&console.log(`[github] ${ro.total} calls last hour`,ro.byCaller),ha=e,lr=new Map,MA(e,!0))}function ur(e="other",t=Date.now()){CA(t),lr.set(e,(lr.get(e)||0)+1),MA(t)}function NA(e=Date.now()){return CA(e),{windowStart:ha,total:ud(lr),byCaller:Object.fromEntries(lr),lastHour:ro,backoffUntil:rs>e?rs:null}}function oo(e){return aL.test(String(e?.message||e||""))}function so(e,t=Date.now()){return rs<=t&&console.warn(`[github] rate limited \u2014 backing off ${EA/6e4} min:`,String(e?.message||e||"").slice(0,200)),rs=Math.max(rs,t+EA),rs}function dd(e=Date.now()){return Math.max(0,rs-e)}var RA,ld,OA,EA,sL,ha,lr,ro,rs,_A,ud,IA,aL,sc=W(()=>{RA=process.env.BOSTRAT_STATE_DIR||$A.join(process.env.HOME||oL.tmpdir(),".bostrat"),ld=$A.join(RA,"github-metrics.json"),OA=60*6e4,EA=5*6e4,sL=6e4,ha=Date.now(),lr=new Map,ro=null,rs=0,_A=0,ud=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(rL.readFileSync(ld,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<OA?(ha=e.windowStart,lr=new Map(Object.entries(e.byCaller||{})),ro=e.lastHour||null):ud(new Map(Object.entries(e.byCaller||{})))&&(ro={start:e.windowStart,total:ud(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}IA=Promise.resolve();aL=/rate limit|too quickly|abuse detection|HTTP 429/i});import PA from"node:fs/promises";import DA from"node:path";import iL from"node:os";function fd({change:e,repo:t=null,number:n=null,githubAt:r=null,observedAt:o=Date.now(),lane:s=null,intervalMs:a=null,source:i=null}){let c=r?o-r:null,l={change:e,repo:t,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};pd.push(l),pd.length>lL&&pd.shift();let u=Bm.get(e)||{count:0,measured:0,totalMs:0,maxMs:0};return u.count+=1,c!=null&&(u.measured+=1,u.totalMs+=c,u.maxMs=Math.max(u.maxMs,c)),Bm.set(e,u),uL(l),l}async function uL(e){try{await PA.mkdir(BA,{recursive:!0}),await PA.appendFile(cL,JSON.stringify(e)+`
|
|
182
|
-
`)}catch{}}function jA(){let e={};for(let[t,n]of Bm)e[t]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:e,recent:pd.slice(-20)}}var BA,cL,lL,pd,Bm,hd=W(()=>{BA=process.env.BOSTRAT_STATE_DIR||DA.join(process.env.HOME||iL.tmpdir(),".bostrat"),cL=DA.join(BA,"github-latency.ndjson"),lL=100,pd=[],Bm=new Map});import{execFile as dL}from"node:child_process";import{promisify as pL}from"node:util";async function fL(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([wa("git",["-C",e,"rev-parse","HEAD"]),wa("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await C({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function Qt(e,t,n={}){let{caller:r="prs",...o}=n,s=await En({cwd:e});ur(r);try{let{stdout:a}=await wa("gh",t,{cwd:e,...hL,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw oo(a)&&so(a),a}}async function Fm(){if(md&&Date.now()-md.at<6e4)return md.data;let e;try{ur("auth");let t=await wa("gh",["auth","status"],{timeout:1e4});e={installed:!0,authenticated:!0,login:`${t.stdout||""}${t.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(t){e=t?.code==="ENOENT"||t?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(e.installed&&!e.authenticated)try{let t=await mi();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return md={at:Date.now(),data:e},e}async function mL(e){try{let{stdout:t}=await wa("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function FA(e){let t=e.name||e.context||"check",n=e.detailsUrl||e.targetUrl||null,r=e.completedAt||e.createdAt||null,o;return e.__typename==="StatusContext"?o=e.state==="SUCCESS"?"pass":e.state==="PENDING"||e.state==="EXPECTED"?"pending":"fail":e.status&&e.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(e.conclusion)?o="pass":o="fail",{name:t,state:o,url:n,completedAt:r}}function jm(e){let t=(e||[]).map(FA),n=t.filter(s=>s.state==="pending").length,r=t.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=t.length&&!n&&r.length?Math.max(...r):null;return{total:t.length,passed:t.filter(s=>s.state==="pass").length,failed:t.filter(s=>s.state==="fail").length,pending:n,failing:t.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function Hm(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function HA(e,t){if(!t)return null;let n=await $e(e);if(!n)return null;try{let r=await Qt(e,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(t)}&per_page=100`,"--jq",".workflow_runs"]),o=new Map;for(let s of JSON.parse(r||"[]"))o.has(s.name)||o.set(s.name,s);return[...o.values()]}catch{return null}}function WA(e){return(e||[]).map(t=>({name:t.name,detailsUrl:t.html_url||null,status:String(t.status||"").toUpperCase(),conclusion:t.conclusion?String(t.conclusion).toUpperCase():null,completedAt:t.status==="completed"&&t.updated_at||null}))}async function qA(e,t){let n=await HA(e,t);return n===null?{...jm([]),unavailable:!0}:jm(WA(n))}function wd(e,t=jm(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",state:e.state??null,mergedAt:e.mergedAt??null,closedAt:e.closedAt??null,additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function gL(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){ma.delete(s);continue}r.add(s),ma.has(s)||ma.set(s,n),o.mergeabilityPending=n-ma.get(s)<wL}for(let o of ma.keys())o.startsWith(`${e}#`)&&!r.has(o)&&ma.delete(o);return t}async function ga(e,t){let n=await dr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await Qt(n.path,["pr","view",String(r),"--json",Um]);return wd(JSON.parse(o))}catch(o){if(!Hm(o))throw o;let s=await Qt(n.path,["pr","view",String(r),"--json",UA]),a=JSON.parse(s);return wd(a,await qA(n.path,a.headRefOid))}}async function Bn(e,{caller:t="prs"}={}){try{let n=await Qt(e,["pr","list","--json",Um,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>wd(r)).sort(LA)}catch(n){if(!Hm(n))throw n;let r=await Qt(e,["pr","list","--json",UA,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>wd(o,await qA(e,o.headRefOid))))).sort(LA)}}function en(){ac.clear()}async function kL(e,t){if(!e)return t;for(let n of t){let r=await pt(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await sd(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await id(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function KA(){let e=await Fm();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await er())await mL(a.path)&&t.push(a);let n=Date.now(),r=dd(n)>0,o=await Promise.all(t.map(async a=>{let i=ac.get(a.path),c=i?.pending?bL:yL;if(i&&(r||n-i.at<c))return i.entry;try{let l=await $e(a.path).catch(()=>null),u=gL(a.path,await Bn(a.path,{caller:"tab"}),n);if(await kL(l,u),i?.entry?.prs)for(let f of u)i.entry.prs.find(h=>h.number===f.number)?.checks?.pending>0&&f.checks.total>0&&f.checks.pending===0&&fd({change:f.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:f.number,githubAt:f.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},p=u.some(f=>f.mergeabilityPending||f.checks.pending>0||f.autoMergeArmed);return ac.set(a.path,{at:Date.now(),entry:d,pending:p}),d}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:jn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of ac.keys())s.has(a)||ac.delete(a);return{auth:e,repos:o}}async function dr(e){let t=(await er()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function os(e){return Ns(e)}async function ya(e,t,{method:n="squash"}={}){let r=await dr(e);if(!ic.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(t);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await En({cwd:r.path})).GH_TOKEN){let a=await Rf().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await Qt(r.path,s)}catch(a){throw new Error(jn(a))}finally{en()}return{ok:!0,number:o}}async function cc(e,t){let n=await dr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Qt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(jn(s))}finally{en()}let o=await $e(n.path).catch(()=>null);return o&&await wA(o,r).catch(()=>{}),{ok:!0,number:r}}async function Wm(e,t){let n=await dr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Qt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(jn(o))}finally{en()}return{ok:!0,number:r}}function qm(e){return e.green&&!e.isDraft}function AL(e){return e.isDraft?"draft":e.mergeable==="CONFLICTING"?`conflicts with ${e.baseRefName}`:e.checks.failed>0?"checks failing":e.checks.pending>0?"checks running":e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":e.mergeStateStatus==="BEHIND"?`behind ${e.baseRefName}`:e.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${e.mergeStateStatus})`}function GA(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:qm(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function VA(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function lc(e,t){let n=a=>a?.firstSeen!=null&&Number.isFinite(Number(a.firstSeen))?Number(a.firstSeen):Number.MAX_SAFE_INTEGER,r=n(e),o=n(t);if(r!==o)return r-o;let s=String(e?.repo||"").localeCompare(String(t?.repo||""));return s||Number(e?.number||0)-Number(t?.number||0)}function zA(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(lc))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function JA(){let e={};for(let[t,n]of Lm)e[t]={...n};return e}async function YA(e,{method:t="merge",onMerged:n=null}={}){let r=await dr(e);if(!ic.has(t))throw new Error(`invalid merge method: ${t}`);if(Lm.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Bn(r.path)).filter(qm).sort((a,i)=>Date.parse(a.createdAt)-Date.parse(i.createdAt));if(!o.length)throw new Error("no PRs ready to merge");let s={running:!0,startedAt:Date.now(),finishedAt:null,method:t,total:o.length,current:o[0].number,queue:o.map(a=>({number:a.number,title:a.title})),merged:[],skipped:[],failed:[]};return Lm.set(r.path,s),EL(s,o,{listPrs:()=>Bn(r.path),merge:a=>ya(r.path,a,{method:t}),sleep:SL,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function TL(e,t){let n=Date.now()+(t.settleMaxMs??vL),r=null;for(;;){let o=null;try{if(o=await t.listPrs(),r=null,!o.some(a=>e.includes(a.number)&&(a.mergeable==="UNKNOWN"||a.mergeStateStatus==="UNKNOWN")))return o}catch(s){r=s}if(Date.now()>=n){if(o)return o;if(r)throw r;return[]}await t.sleep(xL)}}async function EL(e,t,n){try{let r=t;for(let o=0;o<t.length;o++){let s=t[o];if(e.current=s.number,o>0)try{r=await TL(t.slice(o).map(i=>i.number),n)}catch(i){for(let c of t.slice(o))e.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${jn(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){e.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!qm(a)){e.skipped.push({number:a.number,title:a.title,reason:AL(a)});continue}try{await n.merge(a.number),e.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){e.failed.push({number:a.number,title:a.title,reason:jn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),en()}}async function Km(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await wa("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${jn(l)}`)}await fL(e);let o=n||"";if((await En({cwd:e})).GH_TOKEN){let l=await Rf().catch(()=>null);l&&(o=`${o?`${o}
|
|
183
|
-
|
|
184
|
-
`:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await Qt(e,s)}catch(l){throw new Error(jn(l))}finally{en()}let i=a.match(/https:\/\/\S+\/pull\/\d+/)?.[0]??null,c=i?Number(i.match(/\/pull\/(\d+)/)?.[1]):null;return{ok:!0,url:i,number:c}}async function
|
|
153
|
+
`});function HB(e){return{id:e.id,kind:"prompt",groupId:e.groupId,provider:e.provider,box:e.box,agent:e.provider,questionTotal:e.questions.length,answeredVia:"chat",questions:e.questions.map((t,n)=>({index:n,header:t.header||"",question:t.question,multiSelect:!!t.multiSelect,chosen:[]})),ts:e.ts}}function zx(e,t,n){let r=Fm(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function Mn(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Map,l=new Set,u=new Map,d=new Map,p=(k,h)=>{d.set(k,h),t.push(h)},f=k=>{let h=d.get(k);h&&(h.retired=!0)},w=/^Agent "([\s\S]+)" finished$/,m=new Map;for(let k of e||[]){if(k.type!=="tool.called"||k.source!=="transcript")continue;let h=String(k.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(h))for(let v of h.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let D=v[0].split("/").pop().toLowerCase();m.has(D)||m.set(D,[]),m.get(D).push(k.payload?.ts??k.ts)}}let g=3*6e4,y=20*6e4,x=(k,h)=>!!(k?.name&&m.get(String(k.name).toLowerCase()))?.some(D=>D>=h-g&&D<=h+y);for(let k of e||[])if(k.type==="turn.retracted"){r.add(`${k.boxId}|${k.payload?.saidTs}`);let h=Ue(k.payload?.text);h&&(o.has(k.boxId)||o.set(k.boxId,[]),o.get(k.boxId).push(h))}else if(k.type==="turn.user"&&k.source==="orchestrator"){let h=Ue(k.payload?.text);h&&(s.has(k.boxId)||s.set(k.boxId,new Set),s.get(k.boxId).add(h))}else if(k.type==="job.stalled"&&k.payload?.id)i.set(k.payload.id,{ts:he(k),quietMs:Number(k.payload.quietMs)||null});else if(k.type==="job.started"&&k.payload?.id)a.add(k.payload.id),(k.payload.kind||"agent")==="agent"&&k.payload.name&&l.add(k.payload.name);else if(k.type==="turn.user"&&k.payload?.note?.kind==="task"){let h=k.payload.note,v={status:h.status||null,summary:h.summary||null,resultHead:h.resultHead??null,ts:he(k)};h.toolUseId&&c.set(h.toolUseId,v);let D=String(h.summary||"").match(w);D&&u.set(D[1],v)}let b=new Map,I=new Map,$=null,P=new Map,F=new Map,B=new Map,T=new Map,_=new Map,U=new Map,J=new Map,R=new Map,A=new Map,M=new Map,N=new Map,K=new Map,Y=new Map,fe=new Map,Ie=new Map,Ce=[],X=k=>Ce.push(k),et=k=>{if(!Ce.length)return;let h=he(k);for(let v of Ce){if(v.status!=="open"||v.box&&v.box!==k.boxId||(v.ts??0)>h)continue;let D=t.indexOf(v);D>=0&&t.splice(D,1),v.ts=h,t.push(v)}},Ee=new Map,se=new Map,ee=new Map,Oe=new Map,z=new Map,we=new Map,Fe=new Map,O=new Map,ce=()=>{for(let k of O.values())k.questions.length&&t.push(k);O.clear()},ve=null,wt=new Map,Q=6e4,ge=new Map,pt=(k,h)=>{let v=o.get(k);if(!v?.length)return!1;let D=Ue(h),re=s.get(k);return v.some(ke=>{if(!D.startsWith(ke))return!1;let Pe=Ue(D.slice(ke.length));return!!Pe&&!!re?.has(Pe)})};for(let k of e||[]){let h=k.payload||{};switch(k.type){case"turn.user":{if(k.source==="hook"||(Ce.length=0,!String(h.text||"").trim()&&!h.images?.length&&!h.attachments?.length))break;{let v=Fx(h.text);if(v){if(v.kind==="shell-input"){let D={id:k.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:he(k),box:k.boxId,agent:k.provider};t.push(D),wt.set(k.boxId,D)}else{let D=wt.get(k.boxId);D?(D.stdout=v.stdout||null,D.stderr=v.stderr||null,D.done=!0,wt.delete(k.boxId)):t.push({id:k.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:he(k),box:k.boxId,agent:k.provider})}break}}{let v=h.note||Xi(h.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let D=String(v.summary||"").match(w);if(!v.toolUseId&&D&&l.has(D[1]))break}if(v.kind==="command"&&jx(v.command))break;if(v.kind==="resume-summary"){t.push({id:k.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:he(k),box:k.boxId,agent:k.provider});break}v.kind!=="suppress"&&t.push({id:k.id,kind:"event",type:Hx(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:he(k),box:k.boxId,agent:k.provider});break}}if(r.has(`${k.boxId}|${he(k)}`)||k.source==="transcript"&&pt(k.boxId,h.text))break;if(h.kind==="merge-notify"||h.kind==="ship-notify"){t.push({id:k.id,kind:"event",type:h.kind==="ship-notify"?"ship-notified":"merge-notified",text:h.text,ts:he(k),box:k.boxId,agent:k.provider});break}if(h.kind==="mock-picked"||h.kind==="ci-fix"||h.kind==="reconcile"||h.kind==="pr-go"||h.kind==="push-go"||h.kind==="spin-up-view"||h.kind==="prompt-answer"||h.kind==="followup-go"){h.kind==="prompt-answer"&&(ve=null);break}for(let v of P.values())v.status="stale";P.clear();for(let v of B.values())v.status="stale";B.clear();for(let v of Y.values())v.status="stale";Y.clear(),ve&&ve.box===k.boxId&&(t.push(HB(ve)),ve=null),t.push({id:k.id,kind:"message",role:"user",text:h.text,ts:he(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...k.actor==="orchestrator"?{orchestration:h.kind||!0}:{},...h.sourceId?{sourceId:h.sourceId}:{},...h.attachments?.length?{attachments:h.attachments}:{},...h.images?.length?{images:h.images}:{}});break}case"peer.message":{let v=h.from||{};t.push({id:k.id,kind:"event",type:"peer-message",text:h.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:he(k),box:k.boxId,agent:k.provider});break}case"turn.agent":{if(h.model==="<synthetic>"&&/^No response requested\.$/.test(String(h.text||"").trim()))break;let v=X0(h,{codexFailedText:Uo});if(v){t.push({id:k.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:k.provider,legacy:!0,at:he(k),ts:he(k),box:k.boxId,agent:k.provider});break}ce();let D=(h.images||[]).filter(tt=>!x(tt,he(k)));if(!String(h.text||"").trim()&&!D.length)break;if(k.provider==="cursor"){let tt=`${k.boxId}|${h.text}`;if(n.has(tt))break;n.add(tt)}(!ve||ve.box===k.boxId)&&(ve=null);let re=k.provider==="codex"?(h.tools||[]).filter(tt=>!wm.has(tt)&&!ji.has(tt)):h.tools||[],ke=h.text,Pe=null,St=Dm(String(h.text||""));St&&(ke=St.text,Pe={questions:St.questions}),t.push({id:k.id,kind:"message",role:"assistant",text:ke,ts:he(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...Pe?{ask:Pe}:{},...re.length?{tools:re}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...D.length?{images:D}:{}}),et(k),Pe&&(ve={id:k.id,groupId:Bm(k.provider,h.sourceId||k.id,Pe.questions),provider:k.provider,box:k.boxId,questions:Pe.questions,ts:he(k)});break}case"job.started":{if(!h.id)break;let v=he(k),D=c.get(h.id);if(!D&&(h.kind||"agent")==="agent"&&h.name){let At=u.get(h.name);At&&At.ts>=v&&(D=At)}let re=D?null:i.get(h.id)||null,ke={jobId:h.id,jobKind:h.kind||"agent",name:h.name||null,detail:h.detail||null,status:D?D.status==="killed"?"stopped":D.status&&D.status!=="completed"?"failed":"done":re?"stalled":"running",startedTs:v,finishedTs:D?.ts??re?.ts??null,quietMs:re?.quietMs??null,summary:D?.summary??null,resultHead:D?.resultHead??null},Pe=ge.get(k.boxId),St=Pe?.jobs[Pe.jobs.length-1]?.startedTs;if(Pe&&St!=null&&v-St<=Q)Pe.jobs.push(ke);else{let At={id:k.id,kind:"job-dock",dockId:h.id,ts:v,box:k.boxId,agent:k.provider,jobs:[ke]};ge.set(k.boxId,At),t.push(At)}break}case"handoff.done":t.push(mt(k,"lead-handoff"));break;case"subtask.delegated":t.push({...mt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":t.push(mt(k,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let D of P.values())D.status="stale";P.clear();for(let D of B.values())D.status="stale";B.clear()}let v=mt(k,`pr-${h.change}`);if(v.box=k.boxId??null,Vx.has(h.change)&&h.number!=null){let D=zx(b,I,h);if(b.size>=2){for(let ke of I.values())for(let Pe of ke)Pe.grouped=!0;v.groupPrs=[...b.values()];let re=[v];for(let ke of b.keys())I.set(ke,re)}else{let re=I.get(D)??[];re.push(v),I.set(D,re)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let D=Fm(h),re=$&&!$.complete||b.size>=2;if(b.has(D))b.delete(D),I.delete(D);else if(h.number!=null)for(let ke of[...b.keys()])ke.endsWith(`#${h.number}`)&&(b.delete(ke),I.delete(ke));if(re&&h.number!=null){(!$||$.complete)&&($={id:k.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:he(k),ts:he(k),box:k.boxId,agent:k.provider},t.push($)),$.prs.push({number:h.number,url:h.url??null,title:h.title??null,repo:h.repo??null,branch:h.branch??null,change:h.change,ts:he(k)}),$.remaining=[...b.values()],$.complete=b.size===0;break}}t.push(v);break}case"pr.offered":{if(!h.offerId)break;for(let D of P.values())D.status="stale";P.clear();for(let D of B.values())D.status="stale";B.clear();let v={id:k.id,kind:"pr-offer",offerId:h.offerId,excerpt:h.excerpt||null,branch:h.branch||null,base:h.base||null,offered:Array.isArray(h.offered)&&h.offered.length?h.offered:null,toPr:h.toPr&&typeof h.toPr=="object"?{number:h.toPr.number??null}:null,available:Array.isArray(h.available)?h.available:null,defaults:Array.isArray(h.defaults)?h.defaults:null,prState:h.prState||null,openPr:h.openPr&&typeof h.openPr=="object"?h.openPr:null,repos:Array.isArray(h.repos)&&h.repos.length?h.repos:null,status:"open",source:k.source==="cli"||h.via==="cli"?"cli":"transcript",ts:he(k),box:k.boxId,agent:k.provider};P.set(h.offerId,v),F.set(h.offerId,v),t.push(v),v.source==="cli"&&X(v);break}case"pr.offer.answered":{let v=F.get(h.offerId);v&&(v.status=h.action||"dismiss",v.actions=Array.isArray(h.actions)?h.actions:null,v.notify=h.notify===!0,h.existingPr&&typeof h.existingPr=="object"&&(v.existingPr={number:h.existingPr.number??null}),P.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let D of B.values())D.status="stale";B.clear();let v={id:k.id,kind:"pr-exists-offer",offerId:h.offerId,srcOfferId:h.srcOfferId??null,branch:h.branch||null,base:h.base||null,pr:h.pr&&typeof h.pr=="object"?{number:h.pr.number??null,url:h.pr.url??null,title:h.pr.title??null}:null,actions:Array.isArray(h.actions)&&h.actions.length?h.actions:null,notify:h.notify===!0,status:"open",ts:he(k),box:k.boxId,agent:k.provider};B.set(h.offerId,v),T.set(h.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=T.get(h.offerId);v&&(v.status=h.choice||"dismiss",B.delete(h.offerId));break}case"box.state.changed":{let v=h.change==="model"?"model-change":h.change;if(!v)break;let D=mt(k,v);if(v==="model-change"&&(D.to=h.model),v==="node-update"&&D.latest){let re=t.findIndex(ke=>ke.kind==="event"&&ke.type==="node-update"&&ke.latest===D.latest);if(re>=0){let ke=t[re];t[re]={...D,ts:ke.ts,at:ke.at,firstAt:ke.firstAt??ke.ts,updatedAt:D.ts};break}}t.push(D);break}case"track.transferred":case"track.recovered":t.push(mt(k,"track-moved"));break;case"view.state.changed":{if(h.change==="deleted"){f(`view:${h.viewId}`);break}if(h.change!=="created"||h.restarted)break;p(`view:${h.viewId}`,{id:k.id,kind:"view-card",viewId:h.viewId,name:h.name,slug:h.slug,port:h.port,origin:h.origin,ts:he(k),box:k.boxId,agent:k.provider});break}case"view.spinup.failed":{t.push({id:k.id,kind:"view-spinup-failed",name:h.name||null,reason:h.reason||"no-view",ts:he(k),box:k.boxId,agent:k.provider});break}case"mock.state.changed":{if(h.change==="picked"){t.push({id:k.id,kind:"mock-picked",mockId:h.mockId,name:h.name,group:h.group??null,version:h.version??null,siblings:h.siblings??[],ts:he(k),box:k.boxId,agent:k.provider});break}if(h.change==="deleted"){f(`mock:${h.mockId}`);break}if(h.change!=="created")break;p(`mock:${h.mockId}`,{id:k.id,kind:"mock-card",mockId:h.mockId,name:h.name,group:h.group??null,ts:he(k),box:k.boxId,agent:k.provider});break}case"flow.state.changed":{if(h.change==="deleted"){f(`flow:${h.flowId}`);break}if(h.change!=="created")break;p(`flow:${h.flowId}`,{id:k.id,kind:"flow-card",flowId:h.flowId,name:h.name,stepCount:h.stepCount??null,mockIds:h.mockIds??[],ts:he(k),box:k.boxId,agent:k.provider});break}case"runbook.state.changed":{if(h.change==="deleted"){f(`runbook:${h.runbookId}`);break}if(h.change!=="created")break;p(`runbook:${h.runbookId}`,{id:k.id,kind:"runbook-card",runbookId:h.runbookId,name:h.name,ts:he(k),box:k.boxId,agent:k.provider});break}case"ticket.linked":{t.push({id:k.id,kind:"ticket-card",provider:h.provider||"linear",key:h.key,url:h.url,title:h.title??null,linkSource:h.linkSource??null,ts:he(k),box:k.boxId,agent:k.provider});break}case"box.fullscreen.detected":{if(!h.offerId)break;for(let D of J.values())D.box===(h.box||k.boxId)&&(D.status="stale",J.delete(D.offerId));let v={id:k.id,kind:"fullscreen-offer",offerId:h.offerId,status:"open",ts:he(k),box:h.box||k.boxId,agent:h.agent||k.provider};J.set(h.offerId,v),R.set(h.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=R.get(h.offerId);v&&(v.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",J.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let D of _.values())D.key===h.key&&(D.status="stale",_.delete(D.offerId));let v={id:k.id,kind:"ticket-offer",offerId:h.offerId,provider:h.provider||"linear",key:h.key,url:h.url??null,phase:h.phase??null,from:h.from??null,to:h.to?.name??null,prNumber:h.prNumber??null,status:"open",ts:he(k),box:k.boxId,agent:k.provider};_.set(h.offerId,v),U.set(h.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=U.get(h.offerId);v&&(v.status=h.action==="moved"?"moved":"dismiss",_.delete(h.offerId));break}case"ticket.state.changed":{for(let v of _.values())v.key===h.key&&v.to===h.to&&(v.status="stale",_.delete(v.offerId));if(h.mode==="offer")break;t.push(mt(k,"ticket-state"));break}case"ticket.commented":{t.push({id:k.id,kind:"ticket-comment",key:h.key,url:h.url??null,excerpt:h.excerpt??null,ts:he(k),box:k.boxId,agent:k.provider});break}case"ticket.flow.changed":t.push(mt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let D of A.values())D.status="stale";A.clear();let v={id:k.id,kind:"ticket-create-offer",proposalId:h.proposalId,provider:h.provider||"linear",epic:h.epic??null,issues:Array.isArray(h.issues)?h.issues:[],team:h.team??null,needsTeam:!!h.needsTeam,linkCurrentTrack:!!h.linkCurrentTrack,status:"open",ts:he(k),box:k.boxId,agent:k.provider};A.set(h.proposalId,v),M.set(h.proposalId,v),t.push(v),X(v);break}case"ticket.create.answered":{let v=M.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",v.createdCount=h.createdCount??null,v.failedCount=h.failedCount??null,A.delete(h.proposalId));break}case"loop.create.offered":{if(!h.proposalId)break;for(let D of N.values())D.status="stale";N.clear();let v={id:k.id,kind:"loop-create-offer",proposalId:h.proposalId,name:h.name??"",schedule:h.schedule??"",prompt:h.prompt??"",expectation:h.expectation??null,notify:h.notify??"off",assignment:h.assignment??{provider:"claude"},repo:h.repo??null,nodeId:h.nodeId??null,nodeName:h.nodeName??null,status:"open",ts:he(k),box:k.boxId,agent:k.provider};N.set(h.proposalId,v),K.set(h.proposalId,v),t.push(v),X(v);break}case"loop.create.answered":{let v=K.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",N.delete(h.proposalId));break}case"followup.armed":{if(!h.armId)break;let v=h.replaces?Ie.get(h.replaces):null;v&&v.status==="armed"&&(v.status="replaced");let D={id:k.id,kind:"followup-armed",armId:h.armId,trigger:h.trigger??"now",label:h.label??"",prompt:h.prompt??"",why:h.why??null,status:"armed",ts:he(k),box:k.boxId,agent:k.provider};Ie.set(h.armId,D),D.trigger!=="now"&&t.push(D);break}case"followup.armed.cancelled":{let v=Ie.get(h.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!h.offerId)break;for(let re of Y.values())re.trigger===h.trigger&&(re.status="stale",Y.delete(re.offerId));let v=Array.isArray(h.rows)?h.rows:[];for(let re of v){let ke=re.armId?Ie.get(re.armId):null;ke&&ke.status==="armed"&&(ke.status="offered")}let D={id:k.id,kind:"followup-offer",offerId:h.offerId,trigger:h.trigger??"now",repo:h.repo??null,context:h.context&&typeof h.context=="object"?h.context:{},rows:v.map(re=>({followupId:re.followupId??null,armId:re.armId??null,label:re.label??"",prompt:re.prompt??null,promptPreview:re.promptPreview??null,promptHash:re.promptHash??null,origin:re.origin??"operator",why:re.why??null})),status:"open",answer:null,ts:he(k),box:k.boxId,agent:k.provider};Y.set(h.offerId,D),fe.set(h.offerId,D),t.push(D),D.trigger==="now"&&X(D);break}case"followup.answered":{let v=fe.get(h.offerId);v&&(v.status=h.action==="sent"?"sent":h.action==="removed"?"removed":"dismiss",v.answer={followupId:h.followupId??null,armId:h.armId??null,label:h.label??null,promoted:h.promoted??null,revived:h.revived===!0},Y.delete(h.offerId));break}case"followup.create.offered":{if(!h.proposalId)break;for(let D of Ee.values())D.status="stale";Ee.clear();let v={id:k.id,kind:"followup-create-offer",proposalId:h.proposalId,label:h.label??"",prompt:h.prompt??"",trigger:h.trigger??"pr.merged",repo:h.repo??null,why:h.why??null,status:"open",created:null,ts:he(k),box:k.boxId,agent:k.provider};Ee.set(h.proposalId,v),se.set(h.proposalId,v),t.push(v),X(v);break}case"followup.create.answered":{let v=se.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",Ee.delete(h.proposalId));break}case"followup.created":{let v=h.proposalId?se.get(h.proposalId):null;v&&(v.created={followupId:h.followupId??null});break}case"loop.created":{let v=h.proposalId?K.get(h.proposalId):null;v&&(v.created={loopId:h.loopId??null,nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(mt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!h.proposalId||!h.loopId)break;for(let re of ee.values())re.loopId===h.loopId&&(re.status="stale",re.staleReason="superseded",ee.delete(re.proposalId));let v=k.type==="loop.update.offered",D={id:k.id,kind:v?"loop-update-offer":"loop-delete-offer",proposalId:h.proposalId,loopId:String(h.loopId),name:h.name??h.base?.name??"",base:h.base??null,...v?{patch:h.patch??{},changed:Array.isArray(h.changed)?h.changed:Object.keys(h.patch||{})}:{reason:h.reason??""},selfEdit:!!h.selfEdit,status:"open",staleReason:null,ts:he(k),box:k.boxId,agent:k.provider};ee.set(h.proposalId,D),Oe.set(h.proposalId,D),t.push(D),X(D);break}case"loop.update.answered":{let v=Oe.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",ee.delete(h.proposalId));break}case"loop.delete.answered":{let v=Oe.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="delete"?"deleted":h.action==="pause"?"paused":"keep",ee.delete(h.proposalId));break}case"loop.updated":{let v=h.proposalId?Oe.get(h.proposalId):null;v&&(v.applied={changed:Array.isArray(h.changed)?h.changed:[],nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(mt(k,"loop-updated"));break}case"loop.deleted":t.push(mt(k,"loop-deleted"));break;case"loop.paused":t.push(mt(k,"loop-paused"));break;case"planning.change.offered":{if(!h.proposalId||!Array.isArray(h.ops)||!h.ops.length)break;for(let D of z.values())D.status="stale",D.staleReason="superseded",z.delete(D.proposalId);let v={id:k.id,kind:"planning-offer",proposalId:h.proposalId,why:h.why??"",ops:h.ops,base:h.base??{},resolved:h.resolved??{},snapped:!!h.snapped,createsMeRow:!!h.createsMeRow,status:"open",staleReason:null,applied:null,ts:he(k),box:k.boxId,agent:k.provider};z.set(h.proposalId,v),we.set(h.proposalId,v),t.push(v),X(v);break}case"planning.change.answered":{let v=we.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",z.delete(h.proposalId));break}case"planning.changed":{let v=h.proposalId?we.get(h.proposalId):null;v&&(v.applied={results:Array.isArray(h.results)?h.results:[]}),t.push(mt(k,"planning-changed"));break}case"rework.cause.offered":{if(!h.sha||Fe.has(h.sha))break;let v={id:k.id,kind:"rework-cause-offer",sha:h.sha,subject:h.subject??"",linesReworked:Number(h.linesReworked)||0,origins:Array.isArray(h.origins)?h.origins:[],heuristic:h.heuristic??null,intent:h.intent??null,shas:Array.isArray(h.shas)?h.shas:null,pr:h.pr??null,retracts:0,status:"open",cause:null,ts:he(k),box:k.boxId,agent:k.provider};Fe.set(h.sha,v),t.push(v);break}case"rework.cause.answered":{let v=h.sha?Fe.get(h.sha):null;v&&(v.status="answered",v.cause=h.cause??null);break}case"rework.cause.retracted":{let v=h.sha?Fe.get(h.sha):null;v&&(v.status="open",v.cause=null,v.retracts=(v.retracts??0)+1);break}case"ticket.created":{let v={items:Array.isArray(h.items)?h.items:[],failed:Array.isArray(h.failed)?h.failed:[],team:h.team??null},D=h.proposalId?M.get(h.proposalId):null;if(D){D.created=v;break}t.push({id:k.id,kind:"ticket-created",...v,ts:he(k),box:k.boxId,agent:k.provider});break}case"error":{if(!h.kind)break;t.push(mt(k,h.kind));break}case"provider.error":t.push({...mt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":t.push(mt(k,"usage-cap-hit"));break;case"usage.cap.warning":t.push(mt(k,"usage-cap-warning"));break;case"provider.connected":{t.push({id:k.id,kind:"event",type:"provider-connected",provider:h.provider||k.provider,ts:he(k),at:he(k),box:k.boxId,agent:k.provider});break}case"prompt.answered":{if(ve=null,h.control||!h.question)break;let v=h.groupId||h.promptId;if(!v)break;let D=O.get(v);D||(D={id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:he(k)},O.set(v,D));let re=h.questionIndex??0,ke={index:re,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},Pe=D.questions.findIndex(tt=>tt.index===re&&Ue(tt.question)===Ue(ke.question));Pe>=0?D.questions[Pe]=ke:D.questions.push(ke),D.questions.sort((tt,At)=>tt.index-At.index),D.questionTotal=Math.max(D.questionTotal,h.questionTotal??1),D.questions.length>=D.questionTotal&&(t.push(D),O.delete(v));break}case"prompt.dismissed":{ve=null;let v=h.groupId||h.promptId;if(!v||!h.question)break;let re=O.get(v)||{id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:he(k)},ke=h.questionIndex??0;re.questions.some(Pe=>Pe.index===ke&&Ue(Pe.question)===Ue(h.question))||(re.questions.push({index:ke,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:[]}),re.questions.sort((Pe,St)=>Pe.index-St.index)),re.answeredVia="chat",t.push(re),O.delete(v);break}default:break}}let rt=d.size?t.filter(k=>!k.retired):t;return qB(rt.sort((k,h)=>(k.ts??0)-(h.ts??0)))}function qB(e){let t=new Map,n=[];for(let r of e){if(r.kind!=="message"||!r.box){n.push(r);continue}let o=r.role==="assistant"&&!String(r.text||"").trim()&&r.images?.length,s=t.get(r.box);if(o&&s&&(r.ts??0)-s.lastTs<=WB){s.item.images.push(...r.images),s.lastTs=r.ts??s.lastTs;continue}if(o){let a={...r,images:[...r.images]};t.set(r.box,{item:a,lastTs:r.ts??0}),n.push(a)}else t.delete(r.box),n.push(r)}return n}function Um(e,t=null){let n=[];for(let o of e||[]){if(o.type!=="tool.called"||o.source!=="transcript")continue;let s=o.payload||{};String(s.command||"").trim()&&n.push({id:s.id??null,tool:s.tool||null,command:s.command,description:s.description||"",summary:KB(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??Mn(e)).filter(o=>o.kind==="message");return W0(n,r)}function KB(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==Xs(e.command)?t:Wr(e.command,e.description||"")}function mt(e,t){let{ts:n,change:r,kind:o,...s}=e.payload||{};return{id:e.id,kind:"event",type:t,...s,at:he(e),ts:he(e)}}function Jx(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||r.type!=="archived")continue;let o=(r.ts??0)+GB,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&VB.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Yx(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!JB.has(r.type)||!r.box)continue;let o=(r.ts??0)+zB,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||!(a?.kind==="message"&&a.role==="assistant"&&a.box===r.box||a?.kind==="command-batch"&&a.anchorBox===r.box))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Cu(e){return(e||[]).filter(t=>YB.has(t?.kind)&&t.status==="open")}function Xx(e){let t=new Map,n=new Map;for(let r of e||[]){if(r.type!=="pr.state.changed")continue;let o=r.payload||{};if(Vx.has(o.change)&&o.number!=null)zx(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=Fm(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var he,Vx,Fm,WB,GB,VB,zB,JB,YB,Nu=W(()=>{Zs();Ho();ku();Ki();Mu();Lm();he=e=>e.payload?.ts??e.ts;Vx=new Set(["opened","ci-fixed","reconciled","pushed"]),Fm=e=>`${e.repo??""}#${e.number}`;WB=2*6e4;GB=12e4,VB=new Set(["archived","unarchived","opened"]);zB=2500,JB=new Set(["pr-opened","pr-merged","pr-auto-armed"]);YB=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","planning-offer","fullscreen-offer","followup-create-offer"])});function t1(e){let t=null,n=null,r=null;for(let o of e??[]){let s=o?.ts??null;s&&(r=Math.max(r??0,s)),o?.type==="handoff.artifact"&&(t={ts:o.payload?.ts??s,truncated:!!o.payload?.truncated,...o.payload?.reconstructed?{reconstructed:!0}:{}}),o?.type==="code.pushed"&&(n={ts:o.payload?.ts??s,sha:o.payload?.sha??null,ref:o.payload?.ref??null,wip:!!o.payload?.wip})}return{lastArtifact:t,lastPush:n,lastEventAt:r}}function r1(e){for(let t=(e?.length??0)-1;t>=0;t--){let n=e[t];if(n?.type==="handoff.artifact"&&!n.payload?.reconstructed)return n}return null}function o1(e,t){let n=[],r=[],o=new Set,s=new Set;for(let a=(e?.length??0)-1;a>=0;a--){let i=e[a];if(i?.type!=="tool.called")continue;if(t!=null&&(i.ts??0)<=t)break;let c=i.payload||{};c.path&&!o.has(c.path)&&n.length<QB&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<e1&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function tv(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=t1(e),s=r1(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Mn(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-XB);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(ev[r]??ev.failover),l.push(""),o.lastPush?.sha){let p=Qx(n,o.lastPush.ts),f=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${f}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let p=Qx(n,i);l.push(`## Last real checkpoint (written by the previous agent${p?`, ~${p} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=o1(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(p=>`\`${p}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(p=>`\`${p}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let p of c)l.push(`**${p.role==="user"?"operator":"agent"}:** ${n1(p.text,ZB)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let d=l.join(`
|
|
154
|
+
`);return d.length<=Zx?d:`${d.slice(0,Zx)}
|
|
155
|
+
|
|
156
|
+
[\u2026 brief truncated]`}var XB,ZB,Zx,QB,e1,n1,Qx,ev,nv=W(()=>{Nu();XB=12,ZB=2e3,Zx=48e3,QB=30,e1=10;n1=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},Qx=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;ev={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 s1 from"node:fs";import Kr from"node:fs/promises";import Gr from"node:path";function uv(e){let t=Do(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=rv?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,rv).toString("utf8").replace(/�+$/,"")}
|
|
157
|
+
|
|
158
|
+
[\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function m1(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(sv.test(s)){if(r.length>=wv)continue;let a=f1(s.replace(sv,"").replace(/[.;,:]+$/,""),gv,d1);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>ov&&(o=`${o.slice(0,ov-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function yv(e,t,{timeoutMs:n=9e4}={}){let r=Gr.join(t,l1),o=Gr.join(r,u1);await Kr.mkdir(r,{recursive:!0});let s=await Pu(o),a=await be(e);if(!a)throw new Error(`session "${e}" not found`);return await Du(e,a,p1(o)),await Tv(o,s,n),m1(await Kr.readFile(o,"utf8"))}function bv(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===pv||n===hv;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(dv)||n===a1||r.startsWith(fv)||r.startsWith(mv)}function kv(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-h1;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 xv(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 vv(e,{windows:t=[]}={}){if(bv(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 Bu(e){return Hm.get(e)||null}async function Sv(e){let t=Hm.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await be(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:Gr.join(n.cwd,cv,lv)};return Hm.set(e,r),y1(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function y1(e,t){e.step="summarize",await Av(e.name,t),e.step="clear";let n=await be(e.name);await Du(e.name,n,"/clear"),await Wm(w1),e.step="resume",await Du(e.name,n,c1),e.step="done",e.finishedAt=Date.now()}async function Av(e,t,{timeoutMs:n=g1}={}){let r=Gr.join(t,cv),o=Gr.join(r,lv);await Kr.mkdir(r,{recursive:!0});let s=await Pu(o),a=await be(e);await pe({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Du(e,a,i1(o)),await Tv(o,s,n),await pe({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Pu(o)});let i=await Rx(t,o,{exclude:u=>bv(u.role,u.text)});await pe({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await C({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 Kr.readFile(o,"utf8");await C({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...uv(u),ts:Date.now()}})}catch{}}await qf(t);let l=await b1(r,o);return c&&await l0(c,l||o,{box:e,agent:a?.agent??null}),o}async function ju(e,{timeoutMs:t}={}){let n=await be(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return Av(e,n.cwd,t?{timeoutMs:t}:void 0)}async function Lu(e,t,{trackName:n="this Track"}={}){let r=await q({id:e,cwd:t}),o=tv(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Gr.join(t,av);return await Kr.mkdir(Gr.dirname(s),{recursive:!0}),await Kr.writeFile(s,o,"utf8"),await C({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...uv(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),av}async function Pu(e){try{return(await Kr.stat(e)).mtimeMs}catch{return 0}}async function Tv(e,t,n){let r=Date.now()+n;for(;;){if(await Pu(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await Wm(2e3)}}async function b1(e,t){try{if(!s1.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Gr.join(e,`${n}.md`);return await Kr.copyFile(t,r),r}catch{return null}}function Wm(e){return new Promise(t=>setTimeout(t,e))}function iv(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 Du(e,t,n){if(t){let o=iv(t.agent);await sr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await be(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await Ge(e,["Escape"],{kind:"drive-wipe"}),await Wm(150),await Vs(e,gu,{kind:"drive-wipe"}),await at(e,n,{kind:"orchestration-drive",...On(r.agent,n)}),await Vi({sessionName:e,agent:r.agent,agentCmd:iv(r.agent),text:n,flow:"orchestration-drive"})}var cv,lv,rv,dv,pv,fv,a1,i1,c1,mv,hv,l1,u1,ov,wv,gv,d1,p1,sv,f1,h1,w1,g1,Hm,av,qm=W(()=>{ft();ta();In();Wi();Rm();Ox();xi();me();cu();nv();cv=".bostrat/handoff",lv="latest.md",rv=32*1024;dv="Checkpoint: write a work-in-progress handoff",pv="HANDOFF WRITTEN",fv="Resume from .bostrat/handoff/latest.md",a1="/clear",i1=e=>`${dv} 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 ${pv} and take no further action.`,c1=`${fv}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,mv="Beat: write a",hv="BEAT WRITTEN",l1=".bostrat/arc",u1="beat.txt",ov=200,wv=4,gv=5,d1=36,p1=e=>`${mv} 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 ${wv} further lines, each starting with "- " and naming ONE piece in at most ${gv} 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 ${hv} and take no further action.`,sv=/^(?:[-–—*•·]|\d+[.)])\s+/,f1=(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};h1=6e5;w1=3500,g1=3e5,Hm=new Map;av=".bostrat/handoff/status-latest.md"});function zr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Fu.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 Iv(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:zr(o.from,"from",n),toMs:zr(o.to,"to",n)}))}return t}function Gm(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 x1(e){if(!e)return null;let t=String(e).trim();return Vr[t]?t:Ev[t]?Ev[t]:Object.keys(Vr).find(r=>t.startsWith(r))||null}function v1(e){if(!e||e===Vr)return k1;let t=_v.get(e);return t||(t=Iv(e),_v.set(e,t)),t}function $v(e,t,n={}){let{table:r,speed:o}=n,s=v1(r),a=r&&r!==Vr?s[e]?e:null:x1(e);if(!a)return null;let i=Gm(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 Cn(e,t={},n,r){let o=$v(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 S1(e=Vr){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:zr(a.from,"from",n),toMs:zr(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`),Fu.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 T1({now:e=Date.now(),table:t=Vr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...A1,...n},a=[],i=Gm(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(d=>({...d,fromMs:zr(d.from,"from",c),toMs:zr(d.to,"to",c),verifiedMs:Fu.test(String(d.verifiedAt??""))?Date.parse(`${d.verifiedAt}T00:00:00.000Z`):NaN}))}catch(d){a.push(String(d.message));continue}for(let d of u){if(!Number.isFinite(d.verifiedMs)){a.push(`${c}: window ${d.from??"\u2026"} \u2192 ${d.to??"now"} has no verifiedAt`);continue}let p=i>=d.fromMs&&i<=d.toMs,f=d.fromMs>i&&d.fromMs-i<=o*Km;p&&i-d.verifiedMs>r*Km&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),f&&d.fromMs-d.verifiedMs>s*Km&&a.push(`${c}: scheduled rate change on ${d.from} was last verified ${d.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function oa({now:e=Date.now(),table:t=Vr,...n}={}){let r=Gm(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=zr(l.from,"from",i),d=zr(l.to,"to",i);r>=u&&r<=d&&Fu.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=[...S1(t),...T1({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Vr,Ev,Fu,k1,_v,Rv,A1,Km,ir=W(()=>{Vr={"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)."}]},Ev={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"},Fu=/^\d{4}-\d{2}-\d{2}$/;k1=Iv(Vr);_v=new WeakMap;Rv=(e,t,n)=>$v(e,t,n)!==null;A1=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Km=864e5});function E1(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Mv(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Xt(e){let t=e.payload?.model||"unknown",n=E1(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=Cn(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&&!Rv(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Jr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(p=>p.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=Ov();for(let p of n){let{usd:f,model:w,tokens:m,repriced:g,unpriced:y,asRecorded:x}=Xt(p);i+=x;let b=p.provider||"unknown",I=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(w)),a+=f,Mv(d,m),r[w]||={usd:0,tokens:Ov(),events:0},r[w].usd+=f,r[w].events+=1,Mv(r[w].tokens,m),o[b]||={usd:0,events:0},o[b].usd+=f,o[b].events+=1,s[I]||={usd:0,events:0,provider:b,models:new Set,label:t[I]||I},s[I].usd+=f,s[I].events+=1,w!=="unknown"&&s[I].models.add(w),p.epoch!=null){let $=(s[I].epochs||={})[p.epoch]||={usd:0,events:0,provider:b,models:new Set};$.usd+=f,$.events+=1,$.provider=b,w!=="unknown"&&$.models.add(w)}}return{totalUsd:sa(a),asRecordedUsd:sa(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Uu(r,p=>({...p,usd:sa(p.usd)})),byProvider:Uu(o,p=>({...p,usd:sa(p.usd)})),byBox:Uu(s,p=>({usd:sa(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:Uu(p.epochs,f=>({usd:sa(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var Ov,sa,Uu,Yr=W(()=>{ir();Ov=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});sa=e=>Math.round(e*1e4)/1e4,Uu=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function _1(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 Cv(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 d=u.payload||{};!d.repo||d.number==null||(d.change==="merged"?o.set(`${d.repo}#${d.number}`,d):d.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(d=>{let[p,f]=d.split("#");return`${p.split("/").pop()}#${f}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Vm(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Vm(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(d=>`${d.fromAgent}\u2192${d.toAgent}`).join(", ");n.push(`${Vm(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Jr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?_1(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Vm,Nv=W(()=>{Yr();Vm=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as I1}from"node:child_process";import{promisify as $1}from"node:util";import{randomUUID as R1}from"node:crypto";async function zm(e,t){let n=Date.now()+t;for(;;){if(await or(e))return!0;if(Date.now()>n)return!1;await Zi(O1)}}async function C1(e,t){let n=Pv[t]||Pv.default;n.escape&&(await Ge(e,["Escape"],{kind:"swap-exit"}),await Zi(150)),n.wipe&&await Vs(e,gu,{kind:"swap-exit"}),await yu(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=On(t).submitDelayMs||0;await Zi(Math.max(r,250)),await Ge(e,["Enter"],{kind:"swap-exit"})}async function Dv(e,t){try{let{stdout:n}=await Ko(ne,oe("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Lv(e){await Ko(ne,oe("respawn-pane","-k","-t",e))}async function Jm(e,{exitTimeoutMs:t=Bv,fromAgent:n=null}={}){if(!Be(e))throw new Error("invalid session name");let r=!1;if(await or(e))return{forced:r};let o=n||(await be(e))?.agent||"agent";if(await C1(e,o),!await zm(e,t)&&(r=!0,await pe({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Lv(e),!await zm(e,jv)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r}}async function Ym(e,t={}){if(!Be(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await be(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||Ur(n),a=Number(t.exitTimeoutMs)||Bv;await pe({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let{forced:i}=await Jm(e,{exitTimeoutMs:a,fromAgent:o}),c=s==="claude"&&jo(n),l=c?Ll():null,u=await Dv(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await Ko(ne,oe("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await Ko(ne,oe("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?du(g,l):g}if(d&&!i&&(await Lv(e),!await zm(e,jv)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||R1(),w=p?n:Oi(n,f,e),m=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await Cr(r.cwd),s==="codex"&&await Cs(r.cwd),s==="cursor"&&await Ns(r.cwd),await Lo(e),await Ko(ne,oe("set-option","-t",e,"@bostrat-sid",f)),await Ko(ne,oe("set-option","-t",e,"@bostrat-agent",s)),await Zi(M1),c&&Ri().length&&(await Dv(e,$i)||await Ko(ne,oe("set-environment","-t",e,$i,"1")).catch(()=>{}),await at(e,`export ${$i}=1`,{kind:"swap-env"}),await Zi(150)),await at(e,w,{kind:"swap-launch"}),await pe({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:f,forced:i,envRespawned:d}),{name:e,cwd:r.cwd,sessionId:f,agent:s,pinned:m,forced:i,envRespawned:d,launchCmd:w}}var Ko,Zi,Bv,jv,O1,M1,Pv,Fv=W(()=>{ft();di();Ul();Hl();Wi();In();Ko=$1(I1),Zi=e=>new Promise(t=>setTimeout(t,e)),Bv=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,jv=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,O1=250,M1=400,Pv={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"}}});function Xm(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Zm({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!Xm(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),Uv);try{let a=await Hv(`${Ne(r)}/v1/loops/${encodeURIComponent(e)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:t,...n?{note:n}:{}}),signal:o.signal}),i=await a.json().catch(()=>({}));return a.ok?{ok:!0,source:"plane",status:a.status,run:i?.run||null}:{ok:!1,source:"plane",status:a.status,error:i?.error||`plane ${a.status}`}}catch(a){return{ok:!1,source:"unreachable",error:a?.message||String(a)}}finally{clearTimeout(s)}}async function Qi(e,{provider:t=null,cls:n="other",status:r=null,text:o="",note:s=null}={},{env:a=process.env,now:i=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!Xm(a))return{ok:!1,source:"unconfigured"};let c=Hu.get(e.id)||0;if(i()-c<N1)return{ok:!1,source:"debounced"};Hu.set(e.id,i());let l=await ec({env:a}),u=l.loops.find(f=>f.trackId===e.id);if(!u)return Hu.delete(e.id),{ok:!1,source:l.source==="plane"?"no-loop":l.source};let d=s?String(s).replace(/\s+/g," ").trim():`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`,p=await Zm({loopId:u.id,outcome:"errored",note:d.slice(0,500),env:a});return p.ok||Hu.delete(e.id),{...p,loop:{id:u.id,name:u.name}}}async function ec({env:e=process.env}={}){if(!Xm(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),Uv);try{let r=await Hv(`${Ne(e)}/v1/loops`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},signal:t.signal});if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json();return{loops:Array.isArray(o?.loops)?o.loops:[],source:"plane"}}catch(r){return{loops:[],source:"unreachable",error:r?.message||String(r)}}finally{clearTimeout(n)}}var Uv,Hv,N1,Hu,Wu=W(()=>{gt();Uv=1e4,Hv=(...e)=>fetch(...e);N1=10*6e4,Hu=new Map});import{execFile as P1}from"node:child_process";import qu from"node:fs/promises";import Qm from"node:path";import{promisify as D1}from"node:util";function W1(e){let n=String(e||"").trim().match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?/);return n?n[0]:null}async function q1(e,{env:t=process.env}={}){let n=String(e||"").trim();if(!n)return null;let r=n.includes("/")?[Qm.resolve(n)]:String(t.PATH||"").split(Qm.delimiter).filter(Boolean).map(o=>Qm.join(o,n));for(let o of r)try{await qu.access(o,qu.constants.X_OK);let s=await qu.realpath(o),a=await qu.stat(s);if(!a.isFile())continue;return{path:s,mtimeMs:a.mtimeMs}}catch{}return null}async function Go({agent:e=null,agentCmd:t=null,env:n=process.env}={}){let r=String(t||(e?n[F1[e]]||L1[e]:"")||"").trim();if(!r)return null;let{realClaude:o,realCodex:s,realCursor:a}=Hi({agent:e,agentCmd:r});if(!(o||s||a))return null;let i=await q1(r.split(/\s+/)[0],{env:n});if(!i)return null;let c=`${i.path}@${i.mtimeMs}`;return eh.has(c)||eh.set(c,Promise.resolve().then(()=>H1(i.path,{agent:e})).then(l=>W1(l)).catch(()=>null)),eh.get(c)}var B1,j1,L1,F1,eh,U1,H1,Wv=W(()=>{ta();B1=D1(P1),j1=8e3,L1={claude:"claude",codex:"codex",cursor:"cursor-agent"},F1={claude:"BOSTRAT_AGENT_CMD",codex:"BOSTRAT_CODEX_CMD",cursor:"BOSTRAT_CURSOR_CMD"},eh=new Map,U1=async e=>(await B1(e,["--version"],{timeout:j1})).stdout,H1=U1});function J1(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return qv.test(String(e.content||""))?String(e.content):null;if(e.type==="attachment"){let n=e.attachment;return n?.type==="queued_command"&&n.commandMode==="task-notification"&&typeof n.prompt=="string"?n.prompt:null}let t=e.message?.content;return typeof t=="string"&&qv.test(t)?t:null}async function Kv(e,t={}){return(await Vv(e,t)).launches}async function Gv(e,t={}){let{launches:n,done:r}=await Vv(e,t);return n.filter(o=>!r.has(o.id))}async function Vv(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await Nt(e,t)}catch{return{launches:[],done:new Set}}let o=new Map,s=new Set,a=new Set,i=new Map;for(let l of r.split(`
|
|
159
|
+
`)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=J1(d);if(p){let m=p.match(z1)?.[1]?.trim();m&&a.add(m);continue}let f=d.message?.content;if(!Array.isArray(f))continue;let w=d.timestamp?Date.parse(d.timestamp):null;for(let m of f)if(!(!m||typeof m!="object")){if(m.type==="tool_use"&&m.id){if(m.name==="Agent"){let g=m.input||{};o.set(m.id,{id:m.id,kind:"agent",name:String(g.description||"").trim()||null,detail:String(g.subagent_type||"").trim()||null,ts:w,proven:!1})}else if(m.name==="Bash"){let g=String(m.input?.command||"").trim(),y={id:m.id,kind:"command",name:String(m.input?.description||"").trim()||(g?Xs(g):null),detail:g?Xs(g):null,ts:w,proven:m.input?.run_in_background===!0};y.proven?o.set(m.id,y):i.set(m.id,y)}}else if(m.type==="tool_result"&&m.tool_use_id){let g=Y1(m.content);if(K1.test(g)&&s.add(m.tool_use_id),g.match(G1)){let x=i.get(m.tool_use_id);x&&(i.delete(m.tool_use_id),x.proven=!0,x.outputFile=g.match(V1)?.[1]?.replace(/\.$/,"")||null,o.set(x.id,x))}}}}let c=[];for(let l of o.values()){if(!l.proven&&!s.has(l.id))continue;let{proven:u,...d}=l;c.push(d)}return{launches:c.slice(-n),done:a}}var K1,G1,V1,qv,z1,Y1,zv=W(()=>{dn();Zs();K1=/^Async (?:agent|task) launched/i,G1=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,V1=/Output is being written to:\s*(\S+)/i,qv=/^\s*<task-notification>/i,z1=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;Y1=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 Xr(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 X1(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 Jv(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:pn(`read ${Xr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${aa(r)}`:`Read ${aa(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Xr(t.path,n):null,s=t?.glob?` --glob ${th(t.glob)}`:"",a=pn(String(r),40);return{command:pn(`grep ${th(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?Xr(t.target_directory,n):null;return{command:pn(`glob ${th(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${pn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:pn(`edit ${Xr(t.path,n)}`,140),description:`Edit ${aa(t.path)}`}:null;case"Write":return t?.path?{command:pn(`write ${Xr(t.path,n)}`,140),description:`Write ${aa(t.path)}`}:null;case"Delete":return t?.path?{command:pn(`delete ${Xr(t.path,n)}`,140),description:`Delete ${aa(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Xr(s,n)).filter(Boolean);return{command:pn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=X1(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:pn(`apply_patch ${Xr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${aa(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:pn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Ku,pn,aa,th,Yv=W(()=>{Ku=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),pn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,aa=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);th=e=>`"${String(e).replace(/"/g,'\\"')}"`});import tc from"node:fs";import Z1 from"node:fs/promises";import Vo from"node:path";import Q1 from"node:os";import ej from"node:crypto";import tj from"node:zlib";function Qv(e){let t=ej.createHash("md5").update(String(e)).digest("hex");return Vo.join(nj,t)}function eS(e){try{let t=JSON.parse(tc.readFileSync(Vo.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 rj(e){let t=Qv(e),n;try{n=tc.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=Vo.join(t,o.name),a=Vo.join(s,"store.db");if(!tc.existsSync(a))continue;let i=eS(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 Gu(e,t){if(!e)return null;if(t){let n=Vo.join(Qv(e),t),r=Vo.join(n,"store.db");if(tc.existsSync(r))return{id:t,dir:n,store:r,...eS(n)||{createdAtMs:null,updatedAtMs:null}}}return rj(e)}function Xv(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function oj(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=tj.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function sj(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 aj(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Ku.has(r.toolName))continue;let o=Jv(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 nh(e,t){if(!Zv)return ia;let{DatabaseSync:n}=Zv,r;try{r=new n(e,{readOnly:!0})}catch{return ia}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 ia;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return ia}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Xv(r,s.latestRootBlobId):null;if(!i)return{...ia,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of sj(i)){let w=oj(Xv(r,f));if(!w)continue;let m=w.providerOptions?.cursor;if(m?.requestId&&p.push(m.requestId),m?.modelProviderMessageId&&p.push(m.modelProviderMessageId),w.role!=="assistant")continue;if(Array.isArray(w.content))for(let x of w.content){let b=x?.providerOptions?.cursor?.modelName;b&&(d=b)}l.push(...aj(w.content,t).map((x,b)=>({...x,id:x.id||`${f}:${b}`}))),u.push(...cj(w.content));let g=ij(w.content);if(!g)continue;let y=[...new Set(u)];u=[],c.push({id:f,text:g,tools:y.length?y:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return ia}finally{try{r.close()}catch{}}}function tS(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(tc.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 nS(e,t,{limit:n=80}={}){let r=Gu(e,t);if(!r)return[];let{turns:o,model:s}=await nh(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=tS(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 rS(e,t){let n=Gu(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await nh(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 oS(e,t,{limit:n=80}={}){let r=Gu(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await nh(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=tS(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Wr(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Wr(u.command,u.description),ts:i+1});return l}async function sS(e,t){let n=Gu(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await Z1.stat(n.store)).mtimeMs)}catch{return null}}var nj,ij,cj,Zv,ia,rh=W(()=>{Zs();Yv();nj=process.env.BOSTRAT_CURSOR_CHATS||Vo.join(Q1.homedir(),".cursor","chats");ij=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(`
|
|
160
|
+
`).trim():"",cj=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],Zv=process.getBuiltinModule?.("node:sqlite"),ia={turns:[],trailingCommands:[],model:null,requestIds:[]}});import lj from"node:fs/promises";function ih(e){return aS.set(e.agent,e),e}function Zr(e){return aS.get(e)||uj}async function ch(e,t={}){return(await Zr(e.agent).readMessages(e,t)).map(Vu(e))}async function iS(e,t={}){return(await Zr(e.agent).readCommands(e,t)).map(Vu(e))}async function cS(e,t={}){return(await Zr(e.agent).readJobs(e,t)).map(Vu(e))}async function lS(e,t={}){return(await Zr(e.agent).readOpenJobs(e,t)).map(Vu(e))}var ca,oh,sh,ah,uj,aS,Vu,lh=W(()=>{dn();xu();Zs();zv();rh();Ho();ca=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async readOpenJobs(){return[]}async updatedAt(){return null}},oh=class extends ca{transcript(t){return!t?.cwd||!t?.sessionId?null:un(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?ym(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?H0(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?Kv(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?Gv(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await lj.stat(n)).mtimeMs)}catch{return null}}},sh=class extends ca{async readMessages(t,n){return nS(t.cwd,t.sessionId,n)}async readCommands(t,n){return oS(t.cwd,t.sessionId,n)}async updatedAt(t){return sS(t.cwd,t.sessionId)}},ah=class extends ca{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return G0(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return V0(t.cwd,this.sessionId(t),n)}async updatedAt(t){return z0(t.cwd,this.sessionId(t))}},uj=new ca("unknown"),aS=new Map;ih(new oh("claude",fm));ih(new sh("cursor",Ku));ih(new ah("codex",ji));Vu=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function eo(e){let t=e.search(fh);return(t>=0?e.slice(0,t):e).trim()}function dj(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function pj(e){let t=String(e).trim();return!!(!t||Qr.test(e)||fh.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function fj(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=mj(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function mj(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(p=>p.length>3&&n.includes(p)).length;if(u)return u;let d=l.slice(0,8).trim();return d.length>=4&&n.includes(d)?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 uS(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function hj(e,t=""){let n=String(e);if(!pS.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
161
|
+
`),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 d=r[u].match(zo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Qr.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:eo(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 gj(e,t=""){let n=String(e).replace(/\r/g,"").split(`
|
|
162
|
+
`),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!fS.test(n[r]))return null;let o=r-1;for(;o>=0&&n[o].trim()==="";)o--;let s=[];for(;o>=0;o--){let c=n[o].match(zo);if(!c)break;s.unshift({cursor:!!c[1],n:Number(c[2]),label:c[4].trim()})}if(s.length<2||s.some((c,l)=>c.n!==l+1))return null;let a=[];for(let c=o;c>=0&&a.length<6&&!(wj.test(n[c])||Qr.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:eo(c.label),description:""}));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,s.findIndex(c=>c.cursor)),promptId:`claude:confirm-gate:${i.map(c=>c.label).join("|")}`.slice(0,240),questions:[{question:a.join(" ")||"Claude Code is asking you to confirm",header:"Confirm",multiSelect:!1,options:i}]}}function yj(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
163
|
+
`),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(zo);l&&o.push({cursor:!!l[1],label:l[4].trim()})}let s=o.filter(c=>/^(submit answers|cancel)$/i.test(c.label));if(s.length<2)return null;let a=s.map(c=>({label:c.label,description:""})),i=Math.max(0,s.findIndex(c=>c.cursor));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:i,review:!0,promptId:"claude:review:submit-answers",questions:[{question:"Ready to submit your answers?",header:"Review",multiSelect:!1,options:a}]}}function kj(e,t=""){let n=String(e);if(!uh.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
164
|
+
`),o=-1;for(let u=r.length-1;u>=0;u--)if(bj.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let d=r[u].match(zo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Qr.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>uh.test(u.label)))return null;let i=s.map(u=>({label:eo(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=a.join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:resume-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Resume",multiSelect:!1,options:i}]}}function mh(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(zo);o&&t.push({line:r,cursor:!!o[1],n:Number(o[2]),label:o[4].trim()})}let n=t.sort((r,o)=>r.n-o.n);return n.length<2||n.some((r,o)=>r.n!==o+1)?null:n}function xj(e,t=""){let n=String(e);if(!mS.test(n)||!hS.test(n)||Jo.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
165
|
+
`),o=mh(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"theme",promptId:`claude:setup:theme:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks: choose the text style that looks best with your terminal. You can change it later with /theme.",header:"Theme",multiSelect:!1,options:o.map(s=>({label:eo(s.label),description:""}))}]}:null}function vj(e,t=""){let n=String(e);if(!wS.test(n)||Jo.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
166
|
+
`),o=mh(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:eo(i),description:c.join("\xB7").trim()}});return{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(a=>a.cursor)),setup:"login-method",promptId:`claude:setup:login-method:${s.map(a=>a.label).join("|")}`.slice(0,200),questions:[{question:"How do you want to sign in to Claude? A Claude subscription (Pro/Max/Team) uses your existing plan; a Console account bills API usage. Your login stays on this box \u2014 bostrat never sees it.",header:"Log in",multiSelect:!1,options:s}]}}function Aj(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!Sj.test(o)||hh.test(e[r]))break;n+=o}return n}function Tj(e,t=""){let n=String(e);if(!hh.test(n)||Jo.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
167
|
+
`),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=Aj(r,s);break}return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,answerMode:"text",setup:"oauth",url:o,inputLabel:"Paste your sign-in code",promptId:"claude:setup:oauth",questions:[{question:"Open the sign-in link, approve access, then paste the code you're shown back here. The code goes straight to the Claude CLI on your box \u2014 bostrat relays the keystrokes and never stores it.",header:"Log in",multiSelect:!1,options:[]}]}:null}function _j(e,t=""){let n=String(e);if(!dh.test(n)||!Ej.test(n)||Jo.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
|
|
168
|
+
`)].reverse().find(a=>dh.test(a))||"OAuth error").trim();return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"oauth-error",promptId:`claude:setup:oauth-error:${s}`.slice(0,200),questions:[{question:`${s} \u2014 retry to get a fresh sign-in link.`,header:"Log in",multiSelect:!1,options:[{label:"Retry sign-in",description:"Mints a new sign-in link and code"}]}]}}function Ij(e,t=""){let n=String(e);if(!gS.test(n)||Jo.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
169
|
+
`),o=mh(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"trust",promptId:`claude:setup:trust:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks whether it can read, edit, and run files in this workspace. This box's workspace is bostrat-managed scratch space, so trusting it is safe.",header:"Folder trust",multiSelect:!1,options:o.map(s=>({label:eo(s.label),description:""}))}]}:null}function $j(e,t=""){let n=String(e);if(Jo.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
170
|
+
`),o=-1;for(let l=r.length-1;l>=0;l--)if(r[l].trim()!==""){o=l;break}if(o<0)return null;let s=r[o].match(yS);if(!s)return null;let a=[];for(let l=o-1;l>=0&&a.length<3;l--){let u=r[l].trim();if(!u){if(a.length)break;continue}if(Qr.test(r[l])||fh.test(u))break;a.unshift(u)}let i=s[1].trim();i&&a.push(i);let c=a.join(" ")||"Claude Code is waiting for you to continue.";return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"continue",promptId:`claude:setup:continue:${c}`.slice(0,200),questions:[{question:c,header:"Continue",multiSelect:!1,options:[{label:"Continue",description:""}]}]}}function Rj(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(ph.test(e[r])){t=r;break}if(t<0)return null;let n=-1;for(let r=t-1;r>=0;r--)if(/[☐☒]/.test(e[r])){n=r;break}return n<0?null:{headerLine:n,chatLine:t,optStart:n+1,optEnd:t}}function Oj(e,t){let n=e.find(s=>/^type something\b/i.test(s.label));if(n)return n;if(e.length<2)return null;let r=e[e.length-1];if(zu.test(r.label))return null;let o=null;for(let s=r.line+1;s<Math.min(t.length,r.line+3);s++){let a=t[s].replace(/^\s*❯/,"").trim();if(a){o=a;break}}return o&&(Qr.test(o)||/^submit\b/i.test(o))?r:null}function Mj(e,t=""){let n=String(e);if(!dS.test(n)||!ph.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
171
|
+
`),o=Rj(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let _=i;_<c;_++){let U=r[_].match(zo);U&&(u<0&&(u=_),l.push({line:_,cursor:!!U[1],checked:U[3]!=null&&U[3]!==" ",hasCheckbox:U[3]!=null,label:U[4].trim(),desc:""}))}if(!l.length)return null;for(let _ of l)for(let U=_.line+1;U<Math.min(r.length,_.line+4)&&!(zo.test(r[U])||Qr.test(r[U]));U++){let J=r[U].trim();if(!(!J||pj(r[U])||zu.test(J))){_.desc=dj(J);break}}let d=Oj(l,r),p=l.filter(_=>_!==d&&!zu.test(_.label));if(!p.length)return null;let f=p.some(_=>_.hasCheckbox),w=d?.cursor?p.length:Math.max(0,p.findIndex(_=>_.cursor)),m=d&&!zu.test(d.label)?eo(d.label):"",g=s>=0?s+1:0,y=[];for(let _=g;_<u;_++){let U=r[_].trim();U&&!Qr.test(r[_])&&!/[☐☒]/.test(r[_])&&y.push(U)}let x=y.join(" ")||(s>=0?uS(r[s]):"")||"The agent is asking a question",b=s>=0?fj(r[s],x):null,I=b?.currentTabLabel||(s>=0?uS(r[s]):""),$=p.map(_=>({label:eo(_.label),description:_.desc})),P=$.map(_=>_.label).join("|"),B=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${I}:${x}:${P}`.slice(0,240),T=b?`claude:ask:${b.tabs.map(_=>_.label).join("|")}`.slice(0,240):B;return{provider:"claude",box:t,multiSelect:f,cursorIndex:w,promptId:B,groupId:T,...d?{custom:!0,customIndex:p.length,customText:m}:{},dismissable:!0,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:x,header:I,multiSelect:f,options:$}]}}function to(e,t){let n=String(t||"");return n?e==="claude"?dS.test(n)&&ph.test(n)||pS.test(n)||uh.test(n)||fS.test(n.trimEnd().split(`
|
|
172
|
+
`).pop()||"")?!0:Jo.test(n)?!1:mS.test(n)&&hS.test(n)||wS.test(n)||hh.test(n)||dh.test(n)||gS.test(n)||yS.test(n.trimEnd().split(`
|
|
173
|
+
`).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function Nn(e,t){return!e||!t?null:e.agent==="claude"?yj(t,e.name)||Mj(t,e.name)||hj(t,e.name)||kj(t,e.name)||_j(t,e.name)||Tj(t,e.name)||vj(t,e.name)||xj(t,e.name)||Ij(t,e.name)||$j(t,e.name)||gj(t,e.name):e.agent==="cursor"||e.agent==="codex"?lx(e.agent,t,e.name):null}async function wh(e){if(!e)return null;let t=await ln(e.name).catch(()=>"");return Nn(e,t)}function gh(e,t){let n=Array.isArray(t?.[0])?t[0].filter(a=>Number.isInteger(a)&&a>=0):[],r=Number.isInteger(e?.cursorIndex)?e.cursorIndex:0,o=(a,i)=>{let c=i-a;return Array.from({length:Math.abs(c)},()=>c>0?"Down":"Up")},s=[];if(e?.multiSelect){let a=r;for(let i of[...n].sort((c,l)=>c-l))s.push(...o(a,i),"Enter"),a=i;s.push("Tab","Enter")}else{let a=n.length?n[0]:0;s.push(...o(r,a),"Enter")}return s}function bS(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:gh(e,t).map(d=>({key:d})),text:"",post:[]};let o=Array.isArray(t?.[0])?t[0].filter(d=>Number.isInteger(d)&&d>=0):[],s=Number.isInteger(e.customIndex)?e.customIndex:e.questions?.[0]?.options?.length??0,a=Number.isInteger(e.cursorIndex)?e.cursorIndex:0,i=(d,p)=>{let f=p-d;return Array.from({length:Math.abs(f)},()=>({key:f>0?"Down":"Up"}))},c=[],l=a,u=typeof e.customText=="string"?e.customText.length:0;if(u>0&&a===s&&c.push(...Array.from({length:u+2},()=>({key:"BSpace"}))),e.multiSelect){for(let d of[...o].sort((p,f)=>p-f))c.push(...i(l,d),{key:"Enter"}),l=d;return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Down"},{key:"Enter"}]}}return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Enter"}]}}function kS(e,t){let n=Number.isInteger(e?.questionIndex)?e.questionIndex:0,o=(Number.isInteger(t)?t:n)-n;if(!o)return[];let s=o>0?"Tab":"BTab";return Array.from({length:Math.abs(o)},()=>s)}var dS,ph,zo,zu,Qr,fh,pS,fS,wj,uh,bj,Jo,mS,hS,wS,hh,Sj,dh,Ej,gS,yS,yh=W(()=>{ft();Su();dS=/to navigate\b.*\bEsc to cancel|Enter to select\b/,ph=/Chat about this/i,zo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,zu=/^(type something|chat about this|submit)\b/i,Qr=/^[─—-]{6,}\s*$/,fh=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;pS=/^\s*Switch model\?\s*$/m;fS=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,wj=/^\s*[─—▔-]{6,}\s*$/;uh=/Resume from summary/i,bj=/^\s*This session is\b/;Jo=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;mS=/Choose the text style that looks best with your terminal/,hS=/Let's get started\./;wS=/Select login method:/;hh=/Paste code here if prompted/,Sj=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;dh=/OAuth error:/,Ej=/Press Enter to retry\./;gS=/Quick safety check: Is this a project you created or one you trust/;yS=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Ju(e,t,n){if(!e||!t)return null;for(let r of Cj)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function Pj(e){let t=bh.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},bh.set(e,t)),t}function SS(e,t,n=Date.now()){let r=Pj(e);if(r.sentAt=r.sentAt.filter(s=>n-s<vS),r.sentAt.length>=xS)return{action:"give-up"};if(n-r.last<Nj)return{action:"wait"};r.last=n,r.sentAt.push(n);let o=!r.emitted.has(t);return o&&r.emitted.add(t),{action:"send",first:o}}function AS(e,t=Date.now()){let n=bh.get(e);return n?n.sentAt.filter(r=>t-r<vS).length>=xS:!1}var Cj,Nj,xS,vS,bh,kh=W(()=>{Cj=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
|
|
174
|
+
${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];Nj=5e3,xS=5,vS=3600*1e3,bh=new Map});function la(e){return typeof e=="string"?e.trim():""}var TS=W(()=>{});import{execFile as Dj}from"node:child_process";import{promisify as Bj}from"node:util";async function ze(e,t,{input:n}={}){let r=vh("git",["-C",e,...t],{maxBuffer:ES});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function ua(e){if(!e)return!1;try{let{stdout:t}=await ze(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function _S(e){let{stdout:t}=await ze(e,["rev-parse","--show-toplevel"]);return t.trim()}async function jj(e){try{return await ze(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function da(e,t="bostrat: subtask snapshot"){let{stdout:n}=await ze(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>vh("git",["-C",e,...a],{maxBuffer:ES,env:o,...i});try{let a=await jj(e);a&&await s(["read-tree","HEAD"]),await s(["add","-A"]);let{stdout:i}=await s(["write-tree"]),c=i.trim(),l=a?["commit-tree",c,"-p","HEAD","-m",t]:["commit-tree",c,"-m",t],{stdout:u}=await s(l);return u.trim()}finally{try{await vh("rm",["-f",r])}catch{}}}async function Sh(e,t,{trailers:n=[]}={}){let{stdout:r}=await ze(e,["status","--porcelain"]);return r.trim()?(await ze(e,["add","-A"]),await ze(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function Yo(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await ze(e,["status","--porcelain"]),r=n.split(`
|
|
175
|
+
`).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function Xo(e,t){if(!t)return 0;try{let{stdout:n}=await ze(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function Zo(e,t,n,r){return await ze(e,["worktree","add","--no-track","-b",n,t,r]),t}async function Ah(e,t){try{return await ze(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function nc(e,t,n){return await ze(e,["worktree","add","--end-of-options",t,n]),t}async function Qo(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await ze(e,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(t.trim())return t.trim()}catch{}for(let[t,n]of[["refs/remotes/origin/main","origin/main"],["refs/remotes/origin/master","origin/master"],["refs/heads/main","main"],["refs/heads/master","master"]])try{return await ze(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Th(e){await ze(e,["init","-q"]),await ze(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function Et(e,t){try{await ze(e,["worktree","remove","--force",t])}catch{try{await ze(e,["worktree","prune"])}catch{}}}function Lj(e){let t=/(\d+) files? changed/.exec(e),n=/(\d+) insertions?\(\+\)/.exec(e),r=/(\d+) deletions?\(-\)/.exec(e);return{files:t?Number(t[1]):0,insertions:n?Number(n[1]):0,deletions:r?Number(r[1]):0}}function Eh(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function _h(e,t,n,r){let{stdout:o}=await ze(e,Eh(["diff","--shortstat",t,n],r));return Lj(o)}async function Ih(e,t,n,r){let{stdout:o}=await ze(e,Eh(["diff","--name-only",t,n],r));return o.split(`
|
|
176
|
+
`).map(s=>s.trim()).filter(Boolean)}async function $h(e,t,n,r){let{stdout:o}=await ze(e,Eh(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await xh(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await xh(e,o,["--3way","--whitespace=nowarn"]),a=await Fj(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await xh(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function xh(e,t,n){try{return await ze(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function Fj(e){try{let{stdout:t}=await ze(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
|
|
177
|
+
`).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var vh,ES,Yu=W(()=>{vh=Bj(Dj),ES=64*1024*1024});function Xu(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!Uj.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var Le,Uj,Zt=W(()=>{Le=e=>!!(e&&(e.archivedAt||e.transferredTo)),Uj=new Set(["merged","conflict","canceled","failed","handed-off"])});import Rh from"node:fs/promises";import $S from"node:path";import Hj from"node:os";function CS(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function NS(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function PS(e){let t=new Date(CS(e));return t.setDate(t.getDate()+7),t.getTime()}function DS(e){let t=new Date(NS(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Qu(e=Date.now()){for(let[t,n]of Object.entries(pa)){let r=n.startOf(e);if(r!==cr[t]){cr[t]=r;for(let o of es.values())o[t]=0;for(let o of fa)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&fa.delete(o)}}}function BS(e,t){let n=fn?.caps?.[e]?.[pa[t].capKey];return Number.isFinite(n)&&n>0?n:null}function no(e,t=Date.now()){if(!e||!Mh||!fn?.caps)return null;Qu(t);let n=es.get(e);for(let r of Object.keys(pa)){let o=BS(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Zu(s),resetsAt:pa[r].nextStart(t)}}return null}function jS(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${cr[t.window]}`;return fa.has(n)?!1:(fa.add(n),!0)}function IS(e,t,n,r=Date.now()){if(!e||!t)return;Qu(r);let o=Wj(e);for(let[s,a]of Object.entries(pa))n>=cr[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function qj(e,t,n=Date.now()){if(!fn?.caps||!Oh)return;let r=es.get(e);if(r)for(let[o,s]of Object.entries(pa)){let a=BS(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*MS||i>=a)continue;let c=`warn:${e}:${o}:${cr[o]}`;if(!fa.has(c)){fa.add(c);try{let l=await Oh(t);if(!l)continue;await C(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Zu(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function LS(e){let t={};for(let[n,r]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 o={};for(let s of["weeklyUsd","monthlyUsd"]){let a=r?.[s];if(a==null||a==="")continue;let i=Number(a);if(!Number.isFinite(i)||i<=0)throw new Error(`${n}.${s} must be a positive number or null`);o[s]=i}Object.keys(o).length&&(t[n]=o)}return t}async function ed(e,{source:t="local",updatedAt:n=Date.now()}={}){fn={caps:LS(e),updatedAt:n,source:t};try{await Rh.mkdir(RS,{recursive:!0}),await Rh.writeFile(OS(),JSON.stringify(fn,null,2))}catch{}return rc()}function rc(e=Date.now()){Qu(e);let t=new Set([...es.keys(),...Object.keys(fn?.caps||{})]),n={};for(let r of t){let o=es.get(r);n[r]={weeklyUsd:Zu(o?.weekly||0),monthlyUsd:Zu(o?.monthly||0)}}return{caps:fn?.caps||{},configured:!!fn,seeded:Mh,updatedAt:fn?.updatedAt??null,spent:n,windows:{weekly:{start:cr.weekly,resetsAt:PS(e)},monthly:{start:cr.monthly,resetsAt:DS(e)}},warnPct:MS}}async function FS({listTracks:e,getTrack:t}={}){Oh=t||null,Qu();try{let o=JSON.parse(await Rh.readFile(OS(),"utf8"));fn={caps:LS(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{fn=null}let n=Date.now();Je.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Xt(o);IS(o.provider||"unknown",s,o.ts??Date.now()),qj(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(cr.weekly,cr.monthly);for(let o of await e?.()||[]){let s;try{s=await q(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||IS(a.provider||"unknown",Xt(a).usd,i,n)}}return Mh=!0,rc()}var RS,OS,MS,pa,fn,Mh,cr,es,fa,Oh,Wj,Zu,td=W(()=>{me();Yr();RS=process.env.BOSTRAT_STATE_DIR||$S.join(process.env.HOME||Hj.tmpdir(),".bostrat"),OS=()=>$S.join(RS,"usage-caps.json"),MS=.8;pa={weekly:{startOf:CS,nextStart:PS,capKey:"weeklyUsd"},monthly:{startOf:NS,nextStart:DS,capKey:"monthlyUsd"}},fn=null,Mh=!1,cr={weekly:0,monthly:0},es=new Map,fa=new Set,Oh=null,Wj=e=>{let t=es.get(e);return t||(t={weekly:0,monthly:0},es.set(e,t)),t};Zu=e=>Math.round(e*1e4)/1e4});import Kj from"node:fs/promises";import Gj from"node:os";import US from"node:path";function Ch(e){return e==="codex"?Yj:e==="cursor"?VS:KS}function HS(e){let t=String(e||"").split(`
|
|
178
|
+
`),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function WS(e){let t=String(e||"").split(`
|
|
179
|
+
`),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function Xj(e){let t=String(e||"").split(`
|
|
180
|
+
`);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function qS(e){let t=String(e||"").split(`
|
|
181
|
+
`),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function zS(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim();if(e==="codex"){let[r,o]=n.split(/[\s:]+/);if(o&&!GS.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=VS.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!Jj.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function oc(e,t,{timeoutMs:n=Vj}={}){let r=Date.now()+n;for(;;){let o=await De(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await nd(zj)}}async function Zj(e,t){return await at(e,`/model ${t.model}`,On("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function Qj(e,t){await wu(e),await at(e,"/model",{enter:!1}),await nd(250),await Ge(e,["Enter"],{kind:"model-switch"});let n=await oc(e,HS);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Ge(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${t.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=Xj(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await at(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await oc(e,i=>WS(i)||!HS(i)&&o(i)&&{done:o(i)});if(!s)throw await Ge(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?GS.get(t.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await Ge(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await at(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await oc(e,i=>!WS(i)&&o(i));if(!a)throw new Error("codex never confirmed the model change");return{verified:!0,model:a.model,effort:a.effort}}async function eL(){let e=US.join(process.env.CURSOR_CONFIG_DIR||US.join(Gj.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await Kj.readFile(e,"utf8"))?.model||null}catch{return null}}async function tL(e,t){await wu(e),await yu(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await oc(e,qS),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(t.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await oc(e,qS,{timeoutMs:1500});if(s=l?.rows.find(u=>u.active)||null,s&&o(s))break;if(!l||!l.rows.some(o)){s=null;break}await Ge(e,["Down"],{kind:"model-switch"}),await nd(250)}if(!n||!s||!o(s)){await Ge(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Ge(e,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${t.filter}"`:"cursor model picker didn't open")}await Ge(e,["Enter"],{kind:"model-switch"}),await nd(800);let a=await eL();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function JS(e,t,n){return e==="codex"?Qj(t,n):e==="cursor"?tL(t,n):Zj(t,n)}var nd,Vj,zj,KS,Jj,Yj,GS,VS,YS=W(()=>{ft();Wi();nd=e=>new Promise(t=>setTimeout(t,e)),Vj=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,zj=300,KS=[{alias:"default",label:"Default"},{alias:"opus",label:"Opus 5"},{alias:"sonnet",label:"Sonnet 5"},{alias:"haiku",label:"Haiku 4.5"},{alias:"fable",label:"Fable 5.1"},{alias:"opusplan",label:"Opus Plan"}],Jj=new Set([...KS.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5","claude-fable-5-1"]),Yj=[{alias:"gpt-5.6-sol",label:"GPT-5.6 Sol"},{alias:"gpt-5.6-terra",label:"GPT-5.6 Terra"},{alias:"gpt-5.6-luna",label:"GPT-5.6 Luna"},{alias:"gpt-5.5",label:"GPT-5.5"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}],GS=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),VS=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5-high",label:"Opus 5"},{alias:"claude-fable-5-1-high",label:"Fable 5.1"},{alias:"claude-sonnet-5-high",label:"Sonnet 5"},{alias:"cursor-grok-4.6-high",label:"Cursor Grok 4.6"},{alias:"gpt-5.6-sol-high",label:"GPT-5.6 Sol High"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function sd(e){let t=e||{},n=nL(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function nL(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:it(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint,cliVersion:e.cliVersion??null}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:it(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:it(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:it(e.agent),payload:{...Pn(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:it(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Pn(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{change:"subtask-resumed",...Pn(e)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"model",model:e.to,from:e.from??null,verified:e.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:"codex",payload:{change:"cli-update",from:e.from??null,to:e.to??null,status:e.status,...e.error?{error:e.error}:{}}};case"node-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",payload:{change:"node-update",...Pn(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Pn(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Pn(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason,cliVersion:e.cliVersion??null}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{...Pn(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Pn(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{kind:"retag-failed",action:e.action??"reshape",reason:e.reason,rolledBack:e.rolledBack!==!1,...e.recovered?{recovered:!0}:{}}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};case"delivery-held":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{kind:"delivery-held",...Pn(e)}};case"startup-gate":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:it(e.agent),payload:{kind:"startup-gate",...Pn(e)}};default:return null}}function QS(e,t){let n=sd(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;ad(()=>C(r,n))}async function eA(e){if(!(!e?.id||XS.has(e.id))){XS.add(e.id);try{let t=await q(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=sd(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await C(e,o)}}catch{}}}function Pn(e){let{type:t,at:n,...r}=e;return r}function tA(e,t,n){!n?.promptId||od.get(e.id)===n.promptId||(od.set(e.id,n.promptId),ad(()=>C(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:it(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function nA(e,t,n,r={}){od.delete(e.id),ad(()=>C(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:it(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function Nh(e,t,n,r={}){od.delete(e.id),ad(()=>C(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:it(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var it,rd,ad,ZS,XS,od,Ph=W(()=>{me();it=e=>e||null;rd=Promise.resolve(),ad=e=>(rd=rd.then(e).catch(()=>{}),rd),ZS=()=>rd;XS=new Set;od=new Map});function iL(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function cA(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of iL(n).reverse()){if(!rL.test(r))continue;let o=r.endsWith("?")&&r.length<=aL&&sL.test(r);if(oL.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function uA(e){let t=String(e||""),n=[];cL.test(t)&&n.push("commit"),lA.test(t)&&n.push("rebase"),lL.test(t)&&n.push("push");let r=dL.test(t);!r&&uL.test(t)&&n.push("pr");let o=null;if(r){let s=t.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||t.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function dA(e){return lA.test(String(e||""))}function ma(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(f=>`${f.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let f=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${f} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${f} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let f=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",w=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${w}${f}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${f}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${w}${f}`:`push this branch${l} to the remote${f}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let d=[];a.has("commit")||d.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&d.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&d.push("don't push"),a.has("pr")||d.push("don't open a pull request");let p=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return d.length&&(p+=` ${d.join(", and ").replace(/^./,f=>f.toUpperCase())}.`),a.has("pr")&&(p+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),p}function pA(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(e)?e:["commit","push","pr"]),a=t?` on this branch (${t})`:"",i=[];s.has("commit")&&i.push(`commit the work${a} with a clear commit message`),s.has("rebase")&&i.push(`rebase ${s.has("commit")?"the branch":`this branch${t?` (${t})`:""}`} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`),i.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),i.push("push the new branch to the remote"),i.push(`open a pull request${n?` against ${n}`:""} from the new branch with a concise title and a description of what changed and why (use \`gh pr create\`)`);let c=[];s.has("commit")||c.push("don't create any new commits \u2014 ship what's already committed"),o&&!s.has("rebase")&&c.push("don't rebase \u2014 leave the branch's history as it is");let l=`Yes \u2014 go ahead, as a NEW pull request: ${i.join(", then ")}.`;return c.length&&(l+=` ${c.join(", and ").replace(/^./,u=>u.toUpperCase())}.`),l+=` Leave the existing open PR${r?` #${r}`:""}${t?` and its remote branch (${t})`:" and its remote branch"} exactly as they are \u2014 don't push ${t||"the old branch"} itself.`,l}function fA(e,t=Date.now()){let n=[],r=null;for(let o of e||[]){let s=o.payload||{},a=s.ts??o.ts;if(o.type==="pr.offer.answered"&&s.action==="pr"){r={box:o.boxId,from:a,lastActivity:a};continue}if(o.type==="pr.exists.answered"&&s.choice==="new"){r={box:o.boxId,from:a,lastActivity:a};continue}!r||a==null||a<r.from||(o.type==="pr.offer.answered"||o.type==="pr.exists.answered"?r=null:o.type==="pr.state.changed"&&s.change==="opened"?(n.push({box:r.box,from:r.from,to:a,settled:!0}),r=null):o.type==="turn.user"&&o.source!=="hook"&&!s.kind&&String(s.text||"").trim()?r=null:o.boxId===r.box&&/^(?:turn|tool)\./.test(o.type)&&(r.lastActivity=Math.max(r.lastActivity,a)))}return r&&t-r.lastActivity<=pL&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function mA(e,t){let n=new Set;for(let r of t||[]){if(!r.settled)continue;let o=null;for(let s of e||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+fL||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function hA(e){let t=(Array.isArray(e)?e:[]).filter(r=>rA[r]).map(r=>rA[r]);return`The ship you were given the go-ahead for${t.length?` (${t.join(", then ")})`:""} should now be complete. This is an automated ship notification the operator armed on the offer: carry straight on with this Track's follow-up work (dependent tasks, cleanup, next steps) \u2014 don't wait for review or merge. If a ship step failed or is unfinished, finish the ship first. If nothing needs doing, say so briefly.`}var oA,sA,aA,iA,rL,oL,sL,aL,ro,cL,lA,lL,uL,dL,pL,fL,rA,ts=W(()=>{oA=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional|amend(?:ed)?|squash|merge|follow[\s-]?up|clean[\s-]?up)\s)commit(?!s\b)(?!\s+(?:history|log|message|hash|sha)s?\b)/.source,sA=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional)\s)push(?!\s+notifications?\b)(?:\s+(?:it|this|that|them|everything|the\s+\w+))?\s*(?:up)?/.source,aA=/open(?:\s+up)?\s+(?:a|the|that)\s+(?:draft\s+)?(?:pr|pull\s+request)|creat(?:e|ing)\s+(?:a|the)\s+(?:draft\s+)?(?:pr|pull\s+request)|rais(?:e|ing)\s+(?:a|the)\s+(?:pr|pull\s+request)|put\s+up\s+(?:a|the)\s+(?:pr|pull\s+request)|send\s+(?:up\s+)?(?:a|the)\s+(?:pr|pull\s+request)/.source,iA=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|clean|interactive)\s)rebase(?!s\b)(?:\s+(?:it|this|that|them|(?:this|that|the)\s+branch))?(?:\s+(?:on(?:to)?|against|atop|over)\s+\S+)?/.source,rL=new RegExp(`\\b(?:${oA}|${sA}|${aA}|${iA})\\b`,"i"),oL=/\b(?:want\s+me\s+to|would\s+you\s+like(?:\s+me)?(?:\s+to)?|should\s+i|shall\s+i|do\s+you\s+want(?:\s+me)?(?:\s+to)?|happy\s+to|ready\s+for\s+me\s+to|let\s+me\s+know\s+(?:if|when|whether|and)|say\s+the\s+word|give\s+me\s+the\s+(?:word|go[\s-]?ahead)|if\s+you(?:'d|\s+would)?\s+(?:like|want|prefer)|just\s+say\s+(?:so|yes|go))\b/i,sL=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,aL=90;ro=["commit","rebase","push","pr"],cL=new RegExp(`\\b(?:${oA})\\b`,"i"),lA=new RegExp(`\\b(?:${iA})\\b`,"i"),lL=new RegExp(`\\b(?:${sA})\\b`,"i"),uL=new RegExp(`\\b(?:${aA})\\b`,"i"),dL=/\b(?:to|into|onto|on|updat(?:e|es|ing))\s+(?:the|that|this)\s+(?:open\s+|existing\s+|current\s+|same\s+)?(?:draft\s+)?(?:pr|pull\s+request)\b/i;pL=3e4;fL=2500;rA={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import mL from"node:crypto";import id from"node:fs/promises";import wA from"node:path";import hL from"node:os";function kA(e){bA=typeof e=="function"?e:async()=>new Set}function wL(e,t,n){if(e.originNode&&e.originNode===t)return!0;let r=e.data?.trackId;return!!r&&n.has(r)}async function He(){return lr||(Dh??=id.readFile(jh,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(lr=e,!t&&qe()){let{records:n,source:r}=await lt("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){let o=a0(),s=await bA().catch(()=>new Set),a=0;for(let i of n){if(i.deletedAt||!i.data?.repo||i.data?.number==null)continue;if(!wL(i,o,s)){a++;continue}let{id:c,updatedAt:l,...u}=i.data;lr[ie(u.repo,u.number)]=u}a&&console.log(`[pr-links] restore: ${Object.keys(lr).length} link(s) re-seeded, ${a} other-node record(s) left on the plane`),Object.keys(lr).length&&await Lh().catch(()=>{})}}return lr}).finally(()=>Dh=null),Dh)}async function Lh(){let e=JSON.stringify({links:lr},null,2),t=`${jh}.${process.pid}.tmp`;await id.mkdir(gA,{recursive:!0}),await id.writeFile(t,e),await id.rename(t,jh)}async function Ye(e){Bh=Bh.then(Lh,Lh),await Bh.catch(()=>{});let t=lr?.[e];t&&Tt("prlinks",{id:yA(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ut({repo:e,number:t,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!e||!Number.isInteger(Number(t))||!n)return{link:null,created:!1};let i=await He(),c=ie(e,t);return i[c]?{link:i[c],created:!1}:(i[c]={repo:e,number:Number(t),trackId:n,url:r,headRef:o,title:s,source:a,announced:gL.has(a),firstSeen:Date.now()},await Ye(ie(e,t)),{link:i[c],created:!0})}async function ur(e,t){if(!e||t==null)return null;let n=(await He())[ie(e,t)];return!n||n.announced?null:(n.announced=!0,await Ye(ie(e,t)),n)}async function xA(e,t){if(!e||t==null)return!1;let n=(await He())[ie(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await Ye(ie(e,t)),!0):!1}async function ut(e,t){return!e||t==null?null:(await He())[ie(e,t)]??null}async function oo(e,t,n){if(!e||t==null)return null;let r=(await He())[ie(e,t)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,delete r.followupPending,await Ye(ie(e,t)),r):null}async function vA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[ie(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Ye(ie(e,t)),o):null}async function SA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[ie(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Ye(ie(e,t)),o):null}async function cd(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[ie(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Ye(ie(e,t)),r)}async function ld(e,t){if(!e||t==null)return null;let n=(await He())[ie(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Ye(ie(e,t)),n)}async function ud(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[ie(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Ye(ie(e,t)),r)}async function dd(e,t){if(!e||t==null)return null;let n=(await He())[ie(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Ye(ie(e,t)),n)}async function AA(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await He())[ie(e,t)];return r?(r.baseFoldAt=n,await Ye(ie(e,t)),r):null}async function TA(e,t,{misses:n,until:r}){if(!e||t==null)return null;let o=(await He())[ie(e,t)];return o?(o.brokerRefused={misses:Number(n)||0,until:Number(r)||0},await Ye(ie(e,t)),o):null}async function EA(e,t){if(!e||t==null)return null;let n=(await He())[ie(e,t)];return n?.brokerRefused?(delete n.brokerRefused,await Ye(ie(e,t)),n):null}async function _A(e,t){if(!e||t==null)return null;let n=(await He())[ie(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Ye(ie(e,t)),n)}async function IA(e,t,n){if(!e||t==null||!n)return null;let r=(await He())[ie(e,t)];return r?(r.lastHeadSha=n,await Ye(ie(e,t)),r):null}async function $A(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await He())[ie(e,t)];if(!r)return{prev:null,link:null};let o=r.verdict??null;return o&&o.blocked===(n.blocked??null)&&(o.sha??null)===(n.sha??null)||(r.verdict={blocked:n.blocked??null,sha:n.sha??null,at:n.at??Date.now()},await Ye(ie(e,t))),{prev:o,link:r}}async function sc(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await He())[ie(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Ye(ie(e,t)),r):null}async function ns(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[ie(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Ye(ie(e,t)),r):null}async function rs(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[ie(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Ye(ie(e,t)),r):null}async function RA(e,t,n){if(!e||t==null)return null;let r=(await He())[ie(e,t)];if(!r)return null;r.notifyOnMerge=!0;let o=new Map((r.notifyPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.notifyPending=[...o.values()],await Ye(ie(e,t)),r}async function OA(e,t,n){if(!e||t==null)return null;let r=(await He())[ie(e,t)];if(!r)return null;let o=new Map((r.followupPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.followupPending=[...o.values()],await Ye(ie(e,t)),r}async function ac(e,t){if(!e||t==null)return null;let n=(await He())[ie(e,t)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Ye(ie(e,t)),n)}async function MA(){return Object.values(await He()).filter(e=>!yL.has(e.state))}async function mn(){return Object.values(await He()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function CA(){if(!qe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await lt("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await He(),r=0;for(let[o,s]of Object.entries(n))await Tt("prlinks",{id:yA(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var gA,jh,ie,yA,lr,Dh,Bh,bA,gL,yL,Dn=W(()=>{Fr();gA=process.env.BOSTRAT_STATE_DIR||wA.join(process.env.HOME||hL.tmpdir(),".bostrat"),jh=wA.join(gA,"pr-links.json"),ie=(e,t)=>`${e}#${Number(t)}`,yA=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=mL.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},lr=null,Dh=null,Bh=Promise.resolve(),bA=async()=>new Set;gL=new Set(["api","observed","reconciled"]);yL=new Set(["merged","closed","lost"])});import bL from"node:fs";import Fh from"node:fs/promises";import BA from"node:path";import kL from"node:os";function FA(e,t=!1){if(!t&&e-PA<xL)return;PA=e;let n=JSON.stringify({windowStart:ha,byCaller:Object.fromEntries(dr),lastHour:so});DA=DA.then(()=>Fh.mkdir(jA,{recursive:!0})).then(()=>Fh.writeFile(`${pd}.tmp`,n)).then(()=>Fh.rename(`${pd}.tmp`,pd)).catch(()=>{})}function UA(e){e-ha<LA||(so={start:ha,total:fd(dr),byCaller:Object.fromEntries(dr)},so.total&&console.log(`[github] ${so.total} calls last hour`,so.byCaller),ha=e,dr=new Map,FA(e,!0))}function pr(e="other",t=Date.now()){UA(t),dr.set(e,(dr.get(e)||0)+1),FA(t)}function HA(e=Date.now()){return UA(e),{windowStart:ha,total:fd(dr),byCaller:Object.fromEntries(dr),lastHour:so,backoffUntil:os>e?os:null}}function ao(e){return vL.test(String(e?.message||e||""))}function io(e,t=Date.now()){return os<=t&&console.warn(`[github] rate limited \u2014 backing off ${NA/6e4} min:`,String(e?.message||e||"").slice(0,200)),os=Math.max(os,t+NA),os}function md(e=Date.now()){return Math.max(0,os-e)}var jA,pd,LA,NA,xL,ha,dr,so,os,PA,fd,DA,vL,ic=W(()=>{jA=process.env.BOSTRAT_STATE_DIR||BA.join(process.env.HOME||kL.tmpdir(),".bostrat"),pd=BA.join(jA,"github-metrics.json"),LA=60*6e4,NA=5*6e4,xL=6e4,ha=Date.now(),dr=new Map,so=null,os=0,PA=0,fd=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(bL.readFileSync(pd,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<LA?(ha=e.windowStart,dr=new Map(Object.entries(e.byCaller||{})),so=e.lastHour||null):fd(new Map(Object.entries(e.byCaller||{})))&&(so={start:e.windowStart,total:fd(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}DA=Promise.resolve();vL=/rate limit|too quickly|abuse detection|HTTP 429/i});import WA from"node:fs/promises";import qA from"node:path";import SL from"node:os";function wd({change:e,repo:t=null,number:n=null,githubAt:r=null,observedAt:o=Date.now(),lane:s=null,intervalMs:a=null,source:i=null}){let c=r?o-r:null,l={change:e,repo:t,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};hd.push(l),hd.length>TL&&hd.shift();let u=Uh.get(e)||{count:0,measured:0,totalMs:0,maxMs:0};return u.count+=1,c!=null&&(u.measured+=1,u.totalMs+=c,u.maxMs=Math.max(u.maxMs,c)),Uh.set(e,u),EL(l),l}async function EL(e){try{await WA.mkdir(KA,{recursive:!0}),await WA.appendFile(AL,JSON.stringify(e)+`
|
|
182
|
+
`)}catch{}}function GA(){let e={};for(let[t,n]of Uh)e[t]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:e,recent:hd.slice(-20)}}var KA,AL,TL,hd,Uh,gd=W(()=>{KA=process.env.BOSTRAT_STATE_DIR||qA.join(process.env.HOME||SL.tmpdir(),".bostrat"),AL=qA.join(KA,"github-latency.ndjson"),TL=100,hd=[],Uh=new Map});import{execFile as _L}from"node:child_process";import{promisify as IL}from"node:util";async function $L(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([ga("git",["-C",e,"rev-parse","HEAD"]),ga("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await C({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function Qt(e,t,n={}){let{caller:r="prs",...o}=n,s=await En({cwd:e});pr(r);try{let{stdout:a}=await ga("gh",t,{cwd:e,...RL,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw ao(a)&&io(a),a}}async function qh(){if(yd&&Date.now()-yd.at<6e4)return yd.data;let e;try{pr("auth");let t=await ga("gh",["auth","status"],{timeout:1e4});e={installed:!0,authenticated:!0,login:`${t.stdout||""}${t.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(t){e=t?.code==="ENOENT"||t?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(e.installed&&!e.authenticated)try{let t=await gi();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return yd={at:Date.now(),data:e},e}async function OL(e){try{let{stdout:t}=await ga("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function zA(e){let t=e.name||e.context||"check",n=e.detailsUrl||e.targetUrl||null,r=e.completedAt||e.createdAt||null,o;return e.__typename==="StatusContext"?o=e.state==="SUCCESS"?"pass":e.state==="PENDING"||e.state==="EXPECTED"?"pending":"fail":e.status&&e.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(e.conclusion)?o="pass":o="fail",{name:t,state:o,url:n,completedAt:r}}function Hh(e){let t=(e||[]).map(zA),n=t.filter(s=>s.state==="pending").length,r=t.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=t.length&&!n&&r.length?Math.max(...r):null;return{total:t.length,passed:t.filter(s=>s.state==="pass").length,failed:t.filter(s=>s.state==="fail").length,pending:n,failing:t.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function Gh(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function YA(e,t){if(!t)return null;let n=await Re(e);if(!n)return null;try{let r=await Qt(e,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(t)}&per_page=100`,"--jq",".workflow_runs"]),o=new Map;for(let s of JSON.parse(r||"[]"))o.has(s.name)||o.set(s.name,s);return[...o.values()]}catch{return null}}function XA(e){return(e||[]).map(t=>({name:t.name,detailsUrl:t.html_url||null,status:String(t.status||"").toUpperCase(),conclusion:t.conclusion?String(t.conclusion).toUpperCase():null,completedAt:t.status==="completed"&&t.updated_at||null}))}async function ZA(e,t){let n=await YA(e,t);return n===null?{...Hh([]),unavailable:!0}:Hh(XA(n))}function bd(e,t=Hh(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",state:e.state??null,mergedAt:e.mergedAt??null,closedAt:e.closedAt??null,additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function CL(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){wa.delete(s);continue}r.add(s),wa.has(s)||wa.set(s,n),o.mergeabilityPending=n-wa.get(s)<ML}for(let o of wa.keys())o.startsWith(`${e}#`)&&!r.has(o)&&wa.delete(o);return t}async function ya(e,t){let n=await fr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await Qt(n.path,["pr","view",String(r),"--json",Kh]);return bd(JSON.parse(o))}catch(o){if(!Gh(o))throw o;let s=await Qt(n.path,["pr","view",String(r),"--json",JA]),a=JSON.parse(s);return bd(a,await ZA(n.path,a.headRefOid))}}async function Bn(e,{caller:t="prs"}={}){try{let n=await Qt(e,["pr","list","--json",Kh,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>bd(r)).sort(VA)}catch(n){if(!Gh(n))throw n;let r=await Qt(e,["pr","list","--json",JA,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>bd(o,await ZA(e,o.headRefOid))))).sort(VA)}}function en(){cc.clear()}async function DL(e,t){if(!e)return t;for(let n of t){let r=await ut(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await cd(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await ud(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function QA(){let e=await qh();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await nr())await OL(a.path)&&t.push(a);let n=Date.now(),r=md(n)>0,o=await Promise.all(t.map(async a=>{let i=cc.get(a.path),c=i?.pending?PL:NL;if(i&&(r||n-i.at<c))return i.entry;try{let l=await Re(a.path).catch(()=>null),u=CL(a.path,await Bn(a.path,{caller:"tab"}),n);if(await DL(l,u),i?.entry?.prs)for(let f of u)i.entry.prs.find(m=>m.number===f.number)?.checks?.pending>0&&f.checks.total>0&&f.checks.pending===0&&wd({change:f.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:f.number,githubAt:f.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},p=u.some(f=>f.mergeabilityPending||f.checks.pending>0||f.autoMergeArmed);return cc.set(a.path,{at:Date.now(),entry:d,pending:p}),d}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:jn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of cc.keys())s.has(a)||cc.delete(a);return{auth:e,repos:o}}async function fr(e){let t=(await nr()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function ss(e){return Ps(e)}async function ba(e,t,{method:n="squash"}={}){let r=await fr(e);if(!lc.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(t);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await En({cwd:r.path})).GH_TOKEN){let a=await Nf().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await Qt(r.path,s)}catch(a){throw new Error(jn(a))}finally{en()}return{ok:!0,number:o}}async function uc(e,t){let n=await fr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Qt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(jn(s))}finally{en()}let o=await Re(n.path).catch(()=>null);return o&&await AA(o,r).catch(()=>{}),{ok:!0,number:r}}async function Vh(e,t){let n=await fr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Qt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(jn(o))}finally{en()}return{ok:!0,number:r}}function zh(e){return e.green&&!e.isDraft}function FL(e){return e.isDraft?"draft":e.mergeable==="CONFLICTING"?`conflicts with ${e.baseRefName}`:e.checks.failed>0?"checks failing":e.checks.pending>0?"checks running":e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":e.mergeStateStatus==="BEHIND"?`behind ${e.baseRefName}`:e.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${e.mergeStateStatus})`}function eT(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:zh(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function tT(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function dc(e,t){let n=a=>a?.firstSeen!=null&&Number.isFinite(Number(a.firstSeen))?Number(a.firstSeen):Number.MAX_SAFE_INTEGER,r=n(e),o=n(t);if(r!==o)return r-o;let s=String(e?.repo||"").localeCompare(String(t?.repo||""));return s||Number(e?.number||0)-Number(t?.number||0)}function nT(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(dc))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function rT(){let e={};for(let[t,n]of Wh)e[t]={...n};return e}async function oT(e,{method:t="merge",onMerged:n=null}={}){let r=await fr(e);if(!lc.has(t))throw new Error(`invalid merge method: ${t}`);if(Wh.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Bn(r.path)).filter(zh).sort((a,i)=>Date.parse(a.createdAt)-Date.parse(i.createdAt));if(!o.length)throw new Error("no PRs ready to merge");let s={running:!0,startedAt:Date.now(),finishedAt:null,method:t,total:o.length,current:o[0].number,queue:o.map(a=>({number:a.number,title:a.title})),merged:[],skipped:[],failed:[]};return Wh.set(r.path,s),HL(s,o,{listPrs:()=>Bn(r.path),merge:a=>ba(r.path,a,{method:t}),sleep:LL,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function UL(e,t){let n=Date.now()+(t.settleMaxMs??jL),r=null;for(;;){let o=null;try{if(o=await t.listPrs(),r=null,!o.some(a=>e.includes(a.number)&&(a.mergeable==="UNKNOWN"||a.mergeStateStatus==="UNKNOWN")))return o}catch(s){r=s}if(Date.now()>=n){if(o)return o;if(r)throw r;return[]}await t.sleep(BL)}}async function HL(e,t,n){try{let r=t;for(let o=0;o<t.length;o++){let s=t[o];if(e.current=s.number,o>0)try{r=await UL(t.slice(o).map(i=>i.number),n)}catch(i){for(let c of t.slice(o))e.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${jn(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){e.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!zh(a)){e.skipped.push({number:a.number,title:a.title,reason:FL(a)});continue}try{await n.merge(a.number),e.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){e.failed.push({number:a.number,title:a.title,reason:jn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),en()}}async function Jh(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await ga("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${jn(l)}`)}await $L(e);let o=n||"";if((await En({cwd:e})).GH_TOKEN){let l=await Nf().catch(()=>null);l&&(o=`${o?`${o}
|
|
183
|
+
|
|
184
|
+
`:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await Qt(e,s)}catch(l){throw new Error(jn(l))}finally{en()}let i=a.match(/https:\/\/\S+\/pull\/\d+/)?.[0]??null,c=i?Number(i.match(/\/pull\/(\d+)/)?.[1]):null;return{ok:!0,url:i,number:c}}async function sT(e,t){let n=await fr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await Qt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(jn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Gh(i))throw i;let c=await Qt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await YA(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(jn(i));o=XA(l).map(zA).filter(u=>u.state==="fail").map(u=>({name:u.name,link:u.url}))}let s=new Set,a=[];for(let i of o){let c=WL(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await Qt(n.path,["run","view",c,"--log-failed"]).then(u=>qL(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function WL(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function qL(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
|
|
185
185
|
`);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
|
|
186
186
|
`+o.slice(-t).join(`
|
|
187
187
|
`)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
|
|
188
188
|
`+r.slice(-n)),r}function jn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
|
|
189
|
-
`).find(n=>n.trim())||"gh failed"}var
|
|
190
|
-
`)){let r=n.trim(),o=/^([A-Za-z-]+):\s*(.+)$/.exec(r);if(!o)continue;let s=o[1].toLowerCase(),a=o[2].trim();if(s===
|
|
191
|
-
`)){if(o.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1,hunks:[]},r=null,t.push(n);continue}if(n)if(o.startsWith("--- ")&&!r){let s=o.slice(4).trim();n.oldPath=s==="/dev/null"?null:s.replace(/^a\//,"")}else if(o.startsWith("+++ ")&&!r){let s=o.slice(4).trim();n.newPath=s==="/dev/null"?null:s.replace(/^b\//,"")}else if(o.startsWith("Binary files"))n.binary=!0;else if(o.startsWith("@@")){let s=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(o);if(!s)continue;let a=Number(s[1]),i=s[2]==null?1:Number(s[2]),c=Number(s[3]),l=s[4]==null?1:Number(s[4]);i>0&&n.deleted.push([a,i]),n.added+=l,r={oldStart:a,oldCount:i,newStart:c,newCount:l,del:[],add:[]},n.hunks.push(r)}else r&&o.startsWith("-")?r.del.push(o.slice(1)):r&&o.startsWith("+")&&r.add.push(o.slice(1))}return t}function
|
|
192
|
-
`)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function
|
|
189
|
+
`).find(n=>n.trim())||"gh failed"}var ga,RL,yd,Kh,JA,ML,wa,VA,NL,PL,cc,lc,BL,jL,LL,Wh,as=W(()=>{Pr();gt();Dn();ic();gd();me();ga=IL(_L),RL={timeout:3e4,maxBuffer:8*1024*1024};yd=null;Kh="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",JA=Kh.replace("statusCheckRollup,","");ML=9e4,wa=new Map;VA=(e,t)=>e.number-t.number;NL=3e4,PL=1500,cc=new Map;lc=new Set(["squash","merge","rebase"]);BL=2500,jL=9e4,LL=e=>new Promise(t=>setTimeout(t,e));Wh=new Map});import{execFile as KL}from"node:child_process";import{promisify as GL}from"node:util";async function zL(e,t){try{let{stdout:n}=await VL("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function JL(e,t,n,{rebase:r=!1,listPrs:o=Bn}={}){let s=await Yo(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Xo(e.dir,n).catch(()=>0),i=t?await zL(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(m=>m.headRefName===t)||null,u=l?"open":"none"}catch{}let d=s||a>0,p=[];s&&p.push("commit"),r&&p.push("rebase"),(s||c)&&p.push("push"),d&&(u!=="open"||s||c)&&p.push("pr");let f=p.filter(w=>!(w==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:kd.filter(w=>p.includes(w)),defaults:kd.filter(w=>f.includes(w))}}async function xd(e,{branch:t,rebase:n=!1,listPrs:r=Bn}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(p=>p?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await ua(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await JL(p,t,p.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(p=>p.dirty||p.aheadBase>0||p.openPr),c=i.length?i:a,l=kd.filter(p=>c.some(f=>f.available.includes(p))),u=kd.filter(p=>c.some(f=>f.defaults.includes(p))),d=c.filter(p=>p.openPr);return{available:l,defaults:u,prState:d.length?"open":c.every(p=>p.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(p=>({name:p.name,slug:p.slug,dirty:p.dirty,unpushed:p.unpushed,prState:p.prState,openPr:p.openPr}))}}var VL,kd,Yh=W(()=>{Yu();as();VL=GL(KL),kd=["commit","rebase","push","pr"]});function vd(e,t,n){let{state:r,reason:o}=Am(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of pc)a-c.at>=aT()&&pc.delete(i);pc.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=pc.get(e);return s?Date.now()-s.at>=aT()?(pc.delete(e),!1):s.busy:!1}async function Xh(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await De(e,{lines:Xe}).catch(()=>"");if(!vd(e,t,r))return hx(t,r)?{working:!0,prompted:!1}:n;if(to(t,r)){let o=await ln(e).catch(()=>r),s=Nn({name:e,agent:t},o);if(s)return!Ju({name:e,agent:t},s,o)||AS(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function is(e,t){return(await Xh(e,t)).working}var aT,pc,fc=W(()=>{ft();ta();yh();kh();aT=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,pc=new Map});import{execFile as YL}from"node:child_process";import{promisify as XL}from"node:util";async function co(e){if(!e)return null;let t=iT.get(e);if(t&&Date.now()-t.at<QL)return t.branch;let n=null;try{let{stdout:r}=await ZL("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return iT.set(e,{at:Date.now(),branch:n}),n}function cT(e){return String(e||"").match(eF)?.[1]??null}function lT(e,t){let n=cT(e);return!!n&&!!t&&n===t}function uT(e,t){let n=cT(e);return!!n&&n!==t}function tF(e){let t=e?.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.dir).filter(Boolean):[t?.dir||e?.cwd].filter(Boolean)}async function ka(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of tF(e))n(await co(r));return t}async function Sd(e,t,n=()=>!0){if(!t)return null;let r=(e??[]).filter(a=>a&&n(a)),o=r.find(a=>a.workspace?.branch===t);if(o)return o;let s=r.find(a=>lT(t,a.id));if(s)return s;for(let a of r)if(!Le(a)&&(await ka(a)).includes(t))return a;return null}function nF(e,t,n){let r=e?.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}function Ad(e,{branch:t=null,repo:n=null,slug:r=null}={}){return lT(t,e?.id)?!0:nF(e,n,r)}var ZL,QL,iT,eF,cs=W(()=>{Zt();ZL=XL(YL),QL=5e3,iT=new Map;eF=/^track\/.+-([0-9a-f]{8})$/});import{execFile as rF}from"node:child_process";import{promisify as oF}from"node:util";function xa({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function Ed(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function Id({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?uF[r]:null;return a&&s.push(a),s.push(`${hT}: ${xa({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${wT}: ${String(o).trim()}`),s}function dT(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
|
|
190
|
+
`)){let r=n.trim(),o=/^([A-Za-z-]+):\s*(.+)$/.exec(r);if(!o)continue;let s=o[1].toLowerCase(),a=o[2].trim();if(s===hT.toLowerCase()&&!t.epoch)t.epoch=Ed(a);else if(s===wT.toLowerCase()&&!t.model)t.model=a;else if(s===gT.toLowerCase()&&!t.cause){let i=a.toLowerCase();mc.includes(i)&&(t.cause=i)}else if(s==="co-authored-by"||s==="made-with"){let i=a.toLowerCase();t.provider||(i.startsWith("claude")?t.provider="claude":i.startsWith("codex")?t.provider="codex":i.startsWith("cursor")&&(t.provider="cursor"))}}return t}function dF(e,t=lo){return e<=t?"rework":"drift"}function pF(e,{window:t=lo,end:n=nw}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function $d({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return fF.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${gT} trailer`}:hF.test(s)&&!pT.test(s)?{cause:"style",level:"C",basis:"subject"}:pT.test(s)?{cause:"defect",level:"C",basis:"subject"}:mF.test(s)?{cause:"design",level:"C",basis:"subject: refactor"}:n==="wrong-approach"?{cause:"design",level:"C",basis:"wall label: wrong-approach"}:r==="bug-fix"?{cause:"defect",level:"C",basis:"fixer prompt: bug-fix"}:null}function ow({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=wF.exec(a),c=i?i[1].toLowerCase():null;return e&&(e.level==="A"||e.level==="E")?{intent:"fix",basis:e.basis}:s&&/^bug/i.test(s)?{intent:"fix",basis:`linked ticket: ${s}`}:c&&gF.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&yF.has(c)?{intent:"planned",basis:`subject prefix: ${c}:`}:s&&/^(story|feature|task)/i.test(s)?{intent:"planned",basis:`linked ticket: ${s}`}:e?{intent:"likely-fix",basis:e.basis}:r==="followup-go"?{intent:"planned",basis:"operator-tapped follow-up"}:fT.test(String(n||""))||fT.test(a)?{intent:"planned",basis:"blueprint item"}:o&&bF.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function SF(e){let t=String(e||"");return kF.some(n=>n.test(t))?"excluded":xF.some(n=>n.test(t))?"docs":vF.some(n=>n.test(t))?"config":"code"}function AF(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
|
|
191
|
+
`)){if(o.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1,hunks:[]},r=null,t.push(n);continue}if(n)if(o.startsWith("--- ")&&!r){let s=o.slice(4).trim();n.oldPath=s==="/dev/null"?null:s.replace(/^a\//,"")}else if(o.startsWith("+++ ")&&!r){let s=o.slice(4).trim();n.newPath=s==="/dev/null"?null:s.replace(/^b\//,"")}else if(o.startsWith("Binary files"))n.binary=!0;else if(o.startsWith("@@")){let s=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(o);if(!s)continue;let a=Number(s[1]),i=s[2]==null?1:Number(s[2]),c=Number(s[3]),l=s[4]==null?1:Number(s[4]);i>0&&n.deleted.push([a,i]),n.added+=l,r={oldStart:a,oldCount:i,newStart:c,newCount:l,del:[],add:[]},n.hunks.push(r)}else r&&o.startsWith("-")?r.del.push(o.slice(1)):r&&o.startsWith("+")&&r.add.push(o.slice(1))}return t}function TF(e,t){let n=tw(e),r=tw(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Td&&(n=n.slice(0,Td)),r.length>Td&&(r=r.slice(0,Td));let o=new Array(r.length+1),s=new Array(r.length+1);for(let a=0;a<=r.length;a++)o[a]=a;for(let a=1;a<=n.length;a++){s[0]=a;let i=n.charCodeAt(a-1);for(let c=1;c<=r.length;c++){let l=i===r.charCodeAt(c-1)?0:1;s[c]=Math.min(o[c]+1,s[c-1]+1,o[c-1]+l)}[o,s]=[s,o]}return 1-o[r.length]/Math.max(n.length,r.length)}function EF(e,t=yT){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!tw(r[s]).length){n.add(a);continue}s<o.length&&TF(r[s],o[s])>=t&&n.add(a)}return n}function _F(e){let t=[...e].sort((r,o)=>r-o),n=[];for(let r of t){let o=n[n.length-1];o&&o[0]+o[1]===r?o[1]+=1:n.push([r,1])}return n}function IF(e){let t=new Map,n=null;for(let r of String(e||"").split(`
|
|
192
|
+
`)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function mT(e,t){let{stdout:n}=await ew(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
|
|
193
193
|
`);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
|
|
194
|
-
`)}}async function dT(e,t,{fixKey:n=null,window:r=io,resolveOrigin:o=null,context:s={}}={}){let a=await aT(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=rT(a.message),l=n?Sd(n):c.epoch,u=l?ka(l):null,{stdout:d}=await Ym(e,["diff","-U0","--no-color","-M","-C",i,t]),p=cF(d),f=0,w=0,h=0,g=0,y=0,k=0,b=0,I=new Map;for(let $ of p){if($.binary)continue;let F=$.oldPath||$.newPath||"",J=$.deleted.reduce((K,[,X])=>K+X,0),M=iF(F);if(M==="excluded"){h+=J;continue}if(M==="docs"){g+=J,y+=$.added;continue}if(M==="config"){k+=J;continue}f+=$.added;let S=new Set;for(let K of $.hunks||[])for(let X of uF(K))S.add(X);b+=S.size;let _=[];for(let[K,X]of $.deleted)for(let pe=K;pe<K+X;pe++)S.has(pe)||_.push(pe);if(w+=_.length,!$.oldPath||!_.length)continue;let H;try{let K=["blame","-w","-M","-C","--line-porcelain"];for(let[X,pe]of dF(_))K.push("-L",`${X},${X+pe-1}`);K.push(i,"--",$.oldPath),H=pF((await Ym(e,K)).stdout)}catch{continue}for(let{sha:K,time:X}of H.values()){let pe=I.get(K)??{lines:0,time:X};pe.lines+=1,I.set(K,pe)}}let R=[],N=0,D=new Map;for(let[$,{lines:F,time:J}]of I){let M=D.get($);if(!M){try{M=await aT(e,$)}catch{M=null}D.set($,M)}let S=M?rT(M.message):{epoch:null},_=S.epoch,H=S.provider,K=S.model;if(!_&&o){let Q=await o($,M);Q?.trackId&&Q?.boxId!=null&&(_={trackId:Q.trackId,boxId:Q.boxId,epoch:Q.epoch??0},H=H??Q.provider??null,K=K??Q.model??null)}if(!_){N+=F;continue}let X=Number.isFinite(J)?J:M?.ts??a.ts,pe=Math.max(0,(a.ts-X)/KL),Oe=ka(_),Me=Oe===u?"self":JL(pe,r);R.push({sha:$,key:Oe,trackId:_.trackId,boxId:_.boxId,epoch:_.epoch,provider:H??null,model:K??null,lines:F,ageDays:Math.round(pe*100)/100,class:Me,decay:Me==="rework"?1:Me==="drift"?Math.round(YL(pe,{window:r})*1e3)/1e3:0})}R.sort(($,F)=>F.lines-$.lines);let j=Ed({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),T=ew({heuristic:j,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:h,cosmeticDeleted:b,docsDeleted:g,docsAdded:y,configDeleted:k,codeDelta:f+w+b>0,origins:R,unattributedLines:N,ghost:w===0&&f>0,heuristic:j,intent:T}}function pT(e,{minLines:t=Qm}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return xa.has(n)?fc(e)>=t:!1}function fc(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function Jm(e){let t=e.genUsd;return{...e,genUsd:mn(t),reworkChargedUsd:mn(e.reworkChargedUsd),reworkPendingUsd:mn(e.reworkPendingUsd),trueUsd:mn(t+e.reworkChargedUsd),multiplier:t>0?mn((t+e.reworkChargedUsd)/t):null}}function fT(e,{window:t=io,boxMeta:n={}}={}){let r=e||[],o=r.filter(T=>T.type==="cost.recorded"),s=r.filter(T=>T.type==="code.committed"),a=r.filter(T=>T.type==="code.rework"),i=T=>Array.isArray(T?.shas)&&T.shas.length?T.shas:T?.sha?[T.sha]:[],c=new Map,l=new Set;for(let T of r)if(T.type==="rework.cause.offered")for(let $ of i(T.payload))l.add($);else if(T.type==="rework.cause.answered"&&T.payload?.cause)for(let $ of i(T.payload))c.set($,T.payload.cause);else if(T.type==="rework.cause.retracted")for(let $ of i(T.payload))c.delete($);let u={},d=(T,$,F)=>ka({trackId:T,boxId:$,epoch:F??0}),p=(T,$={})=>{if(!u[T]){let J=Sd(T)||{};u[T]={key:T,...J,provider:null,model:null,...zm()}}let F=u[T];return $.provider&&!F.provider&&(F.provider=$.provider),$.model&&!F.model&&(F.model=$.model),F};for(let T of o){if(!T.boxId)continue;let $=d(T.trackId,T.boxId,T.epoch),{usd:F,model:J}=Xt(T),M=p($,{provider:T.provider,model:J!=="unknown"?J:null});M.genUsd+=F}let f=new Map;for(let T of s){let $=`${T.trackId}/${T.boxId}`;(f.get($)??f.set($,[]).get($)).push({...T,ts:T.payload?.ts??T.ts})}for(let T of f.values())T.sort(($,F)=>$.ts-F.ts);let w=(T,$,F,J)=>{let M=f.get(`${T}/${$}`)||[],S=-1/0;for(let K of M)K.ts<J&&(S=K.ts);let _=0,H=0;for(let K of o)K.trackId!==T||K.boxId!==$||(K.epoch??0)===(F??0)&&(K.ts<=S||K.ts>J||(_+=Xt(K).usd,H++));return{usd:_,turns:H,from:Number.isFinite(S)?S:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},k=0,b=[],I=[],R={},N={},D=new Set;for(let T of a){let $=T.payload||{};if(!$.sha||D.has($.sha))continue;if(D.add($.sha),$.codeDelta===!1){k++;continue}let F=Sd($.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:J,turns:M}=w(F.trackId,F.boxId,F.epoch,$.ts??T.ts),S=VL.includes($.intent?.intent)?$.intent.intent:"unknown";y[S]+=1;let _=null;c.has($.sha)?_={cause:c.get($.sha),level:"B",basis:"operator"}:($.heuristic?.level&&$.heuristic.level!=="C"||$.heuristic)&&(_=$.heuristic);let H=_?.level??"none";g[H]=(g[H]||0)+1;let K=GL.has(H),X=Number($.deleted)||0,pe=Array.isArray($.origins)?$.origins:[],Oe=pe.filter(Q=>Q.class==="rework").reduce((Q,qe)=>Q+qe.lines,0),Me={sha:$.sha,subject:$.subject??"",ts:$.ts??T.ts,trackId:T.trackId,fixKey:$.fixKey??null,fixProvider:$.fixProvider??T.provider??null,fixUsd:mn(J),fixTurns:M,linesReworked:Oe,unattributedLines:Number($.unattributedLines)||0,ghost:$.ghost===!0,intent:{intent:S,basis:$.intent?.basis??null},verdict:_?{cause:_.cause,level:H,basis:_.basis??null}:null,charged:mn(0),origins:[]};if(S==="planned"||_?.cause===Ad){h.planned+=J;for(let Q of pe)Q.class==="rework"&&Me.origins.push({key:Q.key,provider:Q.provider??null,model:Q.model??null,lines:Q.lines,ageDays:Q.ageDays,class:Q.class,usd:0})}else if($.ghost||X===0)h.ghost+=J;else{let Q=0;for(let Ae of pe){let Z=Ae.lines/X,me=J*Z;if(Q+=me,Ae.class==="self"){h.self+=me;continue}let Te=Ae.class==="rework"?1:Number(Ae.decay)||0,z=me*Te;if(h.decayed+=me-z,z<=0)continue;let ge=p(Ae.key,{provider:Ae.provider,model:Ae.model});ge.fixes+=1,ge.linesReworked+=Ae.class==="rework"?Ae.lines:0;let Ge=_?.cause&&pc.includes(_.cause)?_.cause:"unclassified";ge.causes[Ge]+=1,K?(ge.reworkChargedUsd+=z,h.charged+=z,Me.charged=mn(Me.charged+z)):(ge.reworkPendingUsd+=z,h.pending+=z),Me.origins.push({key:Ae.key,provider:ge.provider,model:ge.model,lines:Ae.lines,ageDays:Ae.ageDays,class:Ae.class,usd:mn(z)})}let qe=Math.max(0,J-Q);h.unattributed+=qe}b.push(Me),!c.has($.sha)&&l.has($.sha)&&I.push($.sha)}for(let T of Object.values(u)){let $=T.provider||"unknown",F=T.model||"unknown",J=M=>{M.genUsd+=T.genUsd,M.reworkChargedUsd+=T.reworkChargedUsd,M.reworkPendingUsd+=T.reworkPendingUsd,M.linesReworked+=T.linesReworked,M.fixes+=T.fixes;for(let S of Object.keys(M.causes))M.causes[S]+=T.causes[S]};J(R[$]||=zm()),J(N[F]||=zm())}b.sort((T,$)=>$.ts-T.ts);let j=Object.values(u).map(T=>{let $=n[`${T.trackId}/${T.boxId}`]||{};return Jm({...T,trackName:$.trackName??null,label:$.label??null})}).sort((T,$)=>$.reworkChargedUsd+$.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||$.genUsd-T.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${uT} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:k,byEpoch:Object.fromEntries(j.map(T=>[T.key,T])),epochs:j,byProvider:Object.fromEntries(Object.entries(R).map(([T,$])=>[T,Jm($)])),byModel:Object.fromEntries(Object.entries(N).map(([T,$])=>[T,Jm($)])),buckets:Object.fromEntries(Object.entries(h).map(([T,$])=>[T,mn($)])),fixUsdTotal:mn(Object.values(h).reduce((T,$)=>T+$,0)),fixes:b,verdicts:g,pendingTaps:I,commits:s.length}}var WL,qL,Ym,iT,cT,lT,KL,io,Zm,Qm,pc,Ad,GL,VL,xa,uT,zL,XL,oT,ZL,QL,eF,tF,nF,sT,rF,oF,sF,aF,Xm,vd,mn,zm,_d=W(()=>{zr();WL=HL(UL),qL=64*1024*1024,Ym=(e,t)=>WL("git",["-C",e,...t],{maxBuffer:qL,timeout:6e4}),iT="Bostrat-Epoch",cT="Bostrat-Model",lT="Bostrat-Fix-Cause",KL=24*36e5,io=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Zm=90,Qm=3,pc=Object.freeze(["defect","design","requirements","style"]),Ad="not-a-fix",GL=new Set(["A","B","E"]),VL=Object.freeze(["fix","likely-fix","planned","unknown"]),xa=new Set(["fix","likely-fix"]),uT=.8;zL={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};XL=/^revert\b|^revert "/i,oT=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,ZL=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,QL=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;eF=/^([a-z]+)(\([^)]*\))?!?:\s/i,tF=new Set(["fix","hotfix","bugfix","revert"]),nF=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),sT=/\bBP-[A-Z]*\d+\b/i,rF=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);oF=[/(^|\/)\.bostrat\//,/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Gemfile\.lock|go\.sum|composer\.lock)$/,/\.min\.(js|css)$/,/\.map$/,/\.snap$/,/(^|\/)(node_modules|dist|build|vendor|\.next|target)\//],sF=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],aF=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];Xm=e=>String(e??"").replace(/\s+/g," ").trim(),vd=400;mn=e=>Math.round(e*1e4)/1e4,zm=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as fF}from"node:child_process";import{promisify as hF}from"node:util";function hT(e,t=Date.now()){return Pf(e,t)??0}function wF(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function mT(e,t,{now:n=Date.now()}={}){let r=hT(t,n),o=await q(e);return Td({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:wF(o,t.name,r)})}function gF(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function yF(e,t,n,r){let o=Array.isArray(t?.epochs)?t.epochs:[],s=r>0?o[r-1]:null,a=s?.endReason?.code??(typeof s?.endReason=="string"?s.endReason:null),i=gF(n,t.name),c=i?or(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function bF(e,t){try{let{stdout:n}=await tw(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function kF(e){try{let{stdout:t}=await tw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function wT(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await q(e);if(a.some(w=>w.type==="code.committed"&&w.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:w}=await tw(r,["show","-s","--format=%ct",n]),h=Number(w.trim())*1e3;Number.isFinite(h)&&h>0&&(i=h)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=hT(t,i),l=await bF(r,n),u=await kF(r),d=await C(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:u,...l,ts:i}}),p=null,f=!1;try{let w=await dT(r,n,{fixKey:ka({trackId:e.id,boxId:t.name,epoch:c}),window:io,context:{...yF(e,t,a,c),ref:u,provider:t.agent??null}});if(w&&(p=await C(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:d.id,payload:w}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&pT(w))){let g=fc(w),y=w.origins.filter(k=>k.class==="rework").slice(0,3);await C(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:{sha:n,subject:w.subject,linesReworked:g,origins:y.map(k=>({key:k.key,provider:k.provider,model:k.model,lines:k.lines,ageDays:k.ageDays})),heuristic:w.heuristic,intent:w.intent,ts:i}}),f=!0}}catch(w){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${w?.message||w}`)}return{recorded:!0,event:d,rework:p,offered:f}}function gT(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function yT(e,t,n){if(!pc.includes(n)&&n!==Ad)throw new Error(`bad cause "${n}" (${pc.join("|")}|${Ad})`);let r=await q(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(gT(r,t))throw new Error("already answered");return C(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function bT(e,t){let n=await q(e);if(!gT(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return C(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function Id(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await q(e);if(c.some(k=>k.type==="rework.cause.offered"&&k.payload?.pr?.number===n&&(t==null||k.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let k of c)if(k.type==="rework.cause.offered")for(let b of Array.isArray(k.payload?.shas)?k.payload.shas:[k.payload?.sha])b&&l.add(b);let u=new Map;for(let k of c)k.type==="code.committed"&&k.payload?.sha&&u.set(k.payload.sha,k.payload.ref??null);let d=ew({heuristic:Ed({subject:r}),subject:r,ref:o}),p=[];for(let k of c){if(k.type!=="code.rework")continue;let b=k.payload||{};if(!b.sha||l.has(b.sha)||b.codeDelta===!1||o&&u.has(b.sha)&&u.get(b.sha)!==o)continue;let I=b.intent?.intent??"unknown";(xa.has(I)||I==="unknown"&&xa.has(d.intent))&&fc(b)!==0&&p.push(b)}let f=p.reduce((k,b)=>k+fc(b),0);if(f<Qm)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let k of p)for(let b of k.origins??[]){if(b.class!=="rework")continue;let I=w.get(b.key)??{key:b.key,provider:b.provider??null,model:b.model??null,lines:0,ageDays:b.ageDays};I.lines+=b.lines,I.ageDays=Math.min(I.ageDays,b.ageDays),w.set(b.key,I)}let h=p.map(k=>k.sha),g=p.map(k=>k.heuristic).find(k=>k&&k.level!=="C")??Ed({subject:r})??p.map(k=>k.heuristic).find(Boolean)??null,y=xa.has(d.intent)?d:p.find(k=>xa.has(k.intent?.intent))?.intent??d;return await C(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:h[h.length-1],shas:h,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((k,b)=>b.lines-k.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:h}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var mF,tw,$d=W(()=>{fe();Au();_d();mF=hF(fF),tw=(e,t)=>mF("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as xF}from"node:child_process";import{promisify as vF}from"node:util";async function nw(e,t,{midTurn:n=as,pollMs:r=SF,capMs:o=AF}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function TT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){kT.lastIndex=n;let o=kT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
|
|
195
|
-
`,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+OF(a)+"[ \\t]*$","m").exec(t.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;t=t.slice(0,i)+t.slice(u)}return t}function rw(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function _T(e){let t=TT(e),n=t.match(IF);if(!n)return null;let r=rw(t,n.index);return RF.test(r)?null:{repo:r.match(ET)?.[1]??null,head:r.match(MF)?.[1]??null}}function IT(e){let t=TT(e),n=t.match($F);if(!n)return null;let r=rw(t,n.index),o=rw(t,n.index+n[0].length),s=null,a=o.trim().split(/\s+/).filter(Boolean);for(let i=0;i<a.length;i++){let c=a[i];if(c.startsWith("-")){NF.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(ET)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function DF(e,t,{exclude:n=()=>!1}={}){let r=async i=>{ur("observer");let{stdout:c}=await xT("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",PF],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw oo(l)&&so(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-TF&&!n(c)),s=await En({slug:e}),a=o(await r(s));return!a.length&&s.GH_TOKEN&&(a=o(await r({}).catch(()=>[]))),a.sort((i,c)=>Date.parse(c.createdAt)-Date.parse(i.createdAt))}async function BF(e,t){if(t)return[t];let n=[];for(let r of $T(e)){let o=await $e(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await er().catch(()=>[])){let o=await $e(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function $T(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function jF(e,t,n){let r=await ba(e).catch(()=>[e.workspace?.branch].filter(Boolean)),o=t?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||CF(c.headRefName,e.id),i=[];for(let c of await BF(e,t?.repo??null)){let l;try{l=await DF(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await pt(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===e.id&&d.announced)return{settled:!0};if(d&&d.trackId!==e.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==e.id||d.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function RT(e){if(!e)return 0;let t=0;for(let n of pr)n.startsWith(`${e}|`)&&t++;return t}function OT(){for(let e of[...ow])e()}function MT(e,t,{delays:n=vT,turnEnd:r}={}){let o=_T(t.command);if(!o)return null;let s=!!IT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(pr.has(a))return null;pr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(h=>{let g=()=>{clearTimeout(y),ow.delete(g),h()},y=setTimeout(g,l);ow.add(g)});let u=await jF(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Ut({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!w&&!(f?.trackId===e.id&&await cr(d,p.number))?null:(await nw(t.box,t.agent,r),await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),p)}return null}finally{pr.delete(a)}})();return c.catch(()=>pr.delete(a)),c}function CT(e,t,{delays:n=vT,turnEnd:r,openedWait:o}={}){let s=IT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(pr.has(a))return null;pr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let d=[];if(c)d=[c];else{let w=$T(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let h of w){let g=await $e(h).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await ba(e).catch(()=>[])).filter(w=>w!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(w,h)=>{let g=await pt(c,w.number);return g&&g.trackId!==e.id?null:(g||await Ut({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await rc(c,w.number),h&&((await q(e).catch(()=>[])).some(b=>b.type==="pr.state.changed"&&(b.payload?.change==="auto-armed"||b.payload?.change==="merged")&&b.payload?.number===w.number)||(await nw(t.box,t.agent,r),await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:w.number,url:w.url,title:w.title,branch:w.headRefName,repo:c}}))),w)},f=null;for(let w of n){await new Promise(N=>setTimeout(N,w));let h=[];for(let N of d)try{ur("observer");let{stdout:D}=await xT("gh",["pr","view",String(l),"--repo",N,"--json",LF],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await En({slug:N})}}),j=JSON.parse(D||"null");j?.number&&h.push({slug:N,pr:j})}catch(D){oo(D)&&so(D)}let g=h.find(N=>N.pr.state==="MERGED")??(h.length===1?h[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(f=y,s.auto)return p(y,!0);continue}let k=await pt(c,y.number);if(k&&k.trackId!==e.id)return null;k||await Ut({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await nw(t.box,t.agent,r);let b=await q(e).catch(()=>[]);if(b.some(N=>N.type==="pr.state.changed"&&N.payload?.change==="merged"&&N.payload?.number===y.number))return null;let I=N=>N.some(D=>D.type==="pr.state.changed"&&D.payload?.change==="opened"&&D.payload?.number===y.number),R=0;if(!I(b)){if(_T(t.command)&&await cr(c,y.number)){let N=Date.now();R=N+1,await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:N,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await pt(c,y.number))?.announced){let N=o?.capMs??EF,D=o?.pollMs??_F,j=Date.now()+N;for(;Date.now()<j&&(await new Promise(T=>setTimeout(T,D)),!I(await q(e).catch(()=>[]))););}}return await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),R),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await Id(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await hr(c,y.number).catch(()=>{}),await fr(c,y.number).catch(()=>{}),await no(c,y.number,"merged"),y}return f?p(f,!1):null}finally{pr.delete(a)}})();return i.catch(()=>pr.delete(a)),i}var xT,vT,SF,AF,TF,EF,_F,ST,AT,IF,$F,RF,kT,OF,ET,MF,CF,NF,PF,pr,ow,LF,Rd=W(()=>{fe();Cr();yt();sc();Dn();mr();dc();is();$d();xT=vF(xF),vT=[4e3,15e3,45e3],SF=2500,AF=5*6e4;TF=15e3,EF=9e4,_F=2e3,ST=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,AT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,IF=new RegExp(`${ST}${AT}create\\b`),$F=new RegExp(`${ST}${AT}merge\\b`),RF=/\s--web\b/,kT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,OF=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");ET=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,MF=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,CF=nT;NF=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);PF="number,url,title,headRefName,createdAt";pr=new Set;ow=new Set;LF="number,url,title,headRefName,state"});import FF from"node:fs/promises";import aw from"node:path";import UF from"node:os";function sw(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function Od(e){let t=HF.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=sw(n,"from"),s=o?o.replace(/^uds:/,""):null,a=NT(s);return{socket:s,pid:a,name:sw(n,"from-name"),mode:sw(n,"from-mode"),text:r.trim()}}function NT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function WF(){return process.env.CLAUDE_CONFIG_DIR?aw.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):aw.join(UF.homedir(),".claude","sessions")}async function qF(e){let t=NT(e);if(!t)return null;try{let n=await FF.readFile(aw.join(WF(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function PT(e,t){let n=await qF(e?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof t=="function")try{o=await t(n?.sessionId??null,r)??null}catch{o=null}return{socket:e?.socket??null,pid:n?.pid??e?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??e?.name??null,mode:e?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var HF,iw=W(()=>{HF=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function DT(e=process.env){return!!(Ce(e)&&e.BOSTRAT_PLANE_TOKEN)}async function BT(e,t,n=cw){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await GF(`${Ce(t)}${e}`,{headers:VF(t),signal:r.signal})}finally{clearTimeout(o)}}async function hc({env:e=process.env,force:t=!1,timeoutMs:n=cw}={}){if(!DT(e))return{followups:[],source:"unconfigured"};if(!t&&cs&&Date.now()-cs.at<KF)return{followups:cs.followups,source:"cache"};try{let r=await BT("/v1/followups?deleted=1",e,n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.followups)?o.followups:[];return cs={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return cs?{followups:cs.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function jT(e,{env:t=process.env,timeoutMs:n=cw}={}){if(!e)return{followup:null,source:"unconfigured"};if(!DT(t))return{followup:null,source:"unconfigured"};try{let r=await BT(`/v1/followups/${encodeURIComponent(e)}`,t,n);if(r.status===404)return{followup:null,source:"gone"};if(!r.ok)throw new Error(`plane ${r.status}`);return{followup:(await r.json())?.followup??null,source:"plane"}}catch(r){let o=cs?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var KF,cw,cs,GF,VF,LT=W(()=>{yt();KF=6e4,cw=5e3,cs=null,GF=(...e)=>fetch(...e);VF=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function co(e,t){if(lw.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}lw.add(e);try{return await t()}finally{lw.delete(e)}}var lw,mc=W(()=>{lw=new Set});import{randomUUID as Sa,createHash as zF}from"node:crypto";function WT(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function QF(e){for(let[t,n]of ZF)if(t.test(String(e||"")))return`a standing prompt must not embed this Track's specifics (${n}) \u2014 the card supplies them at fire time; arm a one-shot with \`offer\` instead`;return null}function qT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=va(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>FT)throw new Error(`label must be \u2264${FT} characters`);let o=va(n.trigger)||(n.ship?"now":""),s=t?YF:HT.filter(u=>u!=="track.opened");if(!s.includes(o))throw new Error(`trigger must be one of ${s.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let a=n.ship&&o==="now"?tU(n.ship):null,i=va(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>UT)throw new Error(`prompt must be \u2264${UT} bytes`);if(t){let u=QF(i);if(u)throw new Error(u)}let c=va(n.why).slice(0,JF)||null,l=t?eU(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function eU(e){if(e==null||e===""||e==="*")return null;let t=String(e).trim();if(!/^[\w.-]+\/[\w.-]+$/.test(t))throw new Error(`repo must be a forge slug like owner/name, got "${e}"`);return t}function tU(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):uw.slice();for(let i of n)if(!uw.includes(i))throw new Error(`ship.actions may only contain ${uw.join(" | ")}, got "${i}"`);if(!n.length)throw new Error("ship.actions must name at least one of commit | push | pr");let r=t.rebase==null?"none":String(t.rebase).trim();if(!["offered","none"].includes(r))throw new Error(`ship.rebase must be "offered" or "none", got "${t.rebase}"`);let o=null;if(t.toPr!=null&&t.toPr!==""){let i=Number(t.toPr);if(!Number.isInteger(i)||i<=0)throw new Error(`ship.toPr must be a PR number, got "${t.toPr}"`);o=i}let s=va(t.base)||null,a=null;if(t.repos!=null){if(!Array.isArray(t.repos))throw new Error("ship.repos must be an array of checkout names");a=t.repos.map(i=>va(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function Md(e,{trigger:t=null}={}){let n=new Map;for(let r of e){let o=r.payload||{};if(r.type==="followup.armed"&&o.armId)o.replaces&&n.delete(o.replaces),n.set(o.armId,{...o,ts:o.ts??r.ts,boxId:r.boxId??null,provider:r.provider??null});else if(r.type==="followup.armed.cancelled"&&o.armId)n.delete(o.armId);else if(r.type==="followup.offered")for(let s of o.rows||[])s.armId&&n.delete(s.armId)}return[...n.values()].filter(r=>!t||r.trigger===t)}async function KT(e,t,{pull:n=hc,ship:r={}}={}){if(fw(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead");let o=qT(t);if(o.ship)return{kind:"ship",...await sU(e,o,r)};let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null};if(o.trigger==="now"){let g=Sa(),y=Sa();return await C(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:g,trigger:"now",label:o.label,prompt:o.prompt,why:o.why}}),await C(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:y,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:dw(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:y,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=WT(o.label),d=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(d)return{kind:"covered",covered:{id:d.id,label:d.label},...o};let p=await q(s),f=Md(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,h=Sa();return await C(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:h,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...w?{replaces:w}:{}}}),{kind:"armed",armId:h,replaces:w,...o}}async function GT(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await q(n);if(!Md(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await C(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function VT(e,t,{pull:n=hc}={}){if(fw(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=qT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await q(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=WT(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),f=d.find(g=>g.status!=="deleted");if(f)throw new Error(`"${f.label}" (${pw[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let w=Sa(),h=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await C(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:h?.agent??null,payload:{ts:Date.now(),proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function zT(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await q(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("followupId required \u2014 the follow-up is created on the plane before the card is answered");let i=a.payload;return await C(o,{type:"followup.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,followupId:String(r),label:i.label,trigger:i.trigger,repo:i.repo??null}}),await C(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",followupId:String(r)}}),{proposalId:t,action:"created",followupId:String(r)}}async function wc(e,t,n={},{pull:r=hc}={}){if(!e||fw(e))return null;let o={id:e.id,cwd:e.cwd},s=await q(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=h=>{let g=(h?.prs||[]).filter(y=>Number.isFinite(Number(y?.number))).map(y=>`${y?.repo??h?.repo??""}#${Number(y.number)}`);return Number.isFinite(Number(h?.prNumber))&&g.push(`${h?.repo??""}#${Number(h.prNumber)}`),g},f=new Set(p(n));if(s.some(h=>h.type==="followup.offered"&&h.payload?.trigger==="pr.merged"&&p(h.payload?.context).some(g=>f.has(g))))return null}let i=Md(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:dw(p.prompt),origin:"agent",why:p.why??null})),c=[];if(t!=="now"){let{followups:p}=await r().catch(()=>({followups:[]}));c=p.filter(f=>f.status==="active"&&f.mode!=="off"&&f.trigger===t&&(f.repo==null||f.repo===a)).sort((f,w)=>{let h=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return h(w)-h(f)||(f.origin==="operator"?-1:0)-(w.origin==="operator"?-1:0)||(w.createdAt||0)-(f.createdAt||0)}).map(f=>({followupId:f.id,label:f.label,promptPreview:nU(f.prompt),promptHash:dw(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,XF);if(!l.length)return null;let u=Sa(),d={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await C(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:d}),d}function rU(e){let t=e?.context||{},n=Array.isArray(t.prs)&&t.prs.length?t.prs:t.prNumber?[{number:t.prNumber,title:t.prTitle,url:t.prUrl,repo:t.repo}]:[],r=o=>`PR #${o.number}${o.title?` "${o.title}"`:""}${o.url?` (${o.url})`:""}${o.repo?` on ${o.repo}`:""}`;switch(e?.trigger){case"pr.merged":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} merged:`:"Follow-up the operator tapped after this Track's PR merged:";case"pr.opened":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} opened:`:"Follow-up the operator tapped after this Track's PR opened:";case"checks.green":return n.length?`Follow-up the operator tapped after CI went green on ${n.map(r).join(" and ")}:`:"Follow-up the operator tapped after CI went green:";case"ship.done":return"Follow-up the operator tapped after the ship you just ran completed:";default:return"Follow-up the operator tapped:"}}async function JT(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return co(`fu:${e.id}:${t}`,()=>oU(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function oU(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=jT}=s,l={id:e.id,cwd:e.cwd},u=await q(l),d=u.find(b=>b.type==="followup.offered"&&b.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(b=>b.type==="followup.answered"&&b.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=b=>C(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...b}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(b=>b.followupId).filter(Boolean),armIds:p.map(b=>b.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,h=null;if(n){if(!p.some(R=>R.followupId===n))throw new Error("that follow-up is not on this card");let{followup:b,source:I}=await c(n);if(I==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!b||b.status!=="active"){await f({action:"removed",followupId:n});let R=new Error("removed in Settings since it was offered");throw R.code="removed",R}w=b.prompt,h=b.label}else{let b=p.find(R=>R.armId===r);if(!b)throw new Error("that arm is not on this card");if(w=u.find(R=>R.type==="followup.armed"&&R.payload?.armId===r)?.payload?.prompt??b.prompt,h=b.label,!w)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let y=`${rU(d.payload)}
|
|
194
|
+
`)}}async function bT(e,t,{fixKey:n=null,window:r=lo,resolveOrigin:o=null,context:s={}}={}){let a=await mT(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=dT(a.message),l=n?Ed(n):c.epoch,u=l?xa(l):null,{stdout:d}=await ew(e,["diff","-U0","--no-color","-M","-C",i,t]),p=AF(d),f=0,w=0,m=0,g=0,y=0,x=0,b=0,I=new Map;for(let _ of p){if(_.binary)continue;let U=_.oldPath||_.newPath||"",J=_.deleted.reduce((K,[,Y])=>K+Y,0),R=SF(U);if(R==="excluded"){m+=J;continue}if(R==="docs"){g+=J,y+=_.added;continue}if(R==="config"){x+=J;continue}f+=_.added;let A=new Set;for(let K of _.hunks||[])for(let Y of EF(K))A.add(Y);b+=A.size;let M=[];for(let[K,Y]of _.deleted)for(let fe=K;fe<K+Y;fe++)A.has(fe)||M.push(fe);if(w+=M.length,!_.oldPath||!M.length)continue;let N;try{let K=["blame","-w","-M","-C","--line-porcelain"];for(let[Y,fe]of _F(M))K.push("-L",`${Y},${Y+fe-1}`);K.push(i,"--",_.oldPath),N=IF((await ew(e,K)).stdout)}catch{continue}for(let{sha:K,time:Y}of N.values()){let fe=I.get(K)??{lines:0,time:Y};fe.lines+=1,I.set(K,fe)}}let $=[],P=0,F=new Map;for(let[_,{lines:U,time:J}]of I){let R=F.get(_);if(!R){try{R=await mT(e,_)}catch{R=null}F.set(_,R)}let A=R?dT(R.message):{epoch:null},M=A.epoch,N=A.provider,K=A.model;if(!M&&o){let X=await o(_,R);X?.trackId&&X?.boxId!=null&&(M={trackId:X.trackId,boxId:X.boxId,epoch:X.epoch??0},N=N??X.provider??null,K=K??X.model??null)}if(!M){P+=U;continue}let Y=Number.isFinite(J)?J:R?.ts??a.ts,fe=Math.max(0,(a.ts-Y)/iF),Ie=xa(M),Ce=Ie===u?"self":dF(fe,r);$.push({sha:_,key:Ie,trackId:M.trackId,boxId:M.boxId,epoch:M.epoch,provider:N??null,model:K??null,lines:U,ageDays:Math.round(fe*100)/100,class:Ce,decay:Ce==="rework"?1:Ce==="drift"?Math.round(pF(fe,{window:r})*1e3)/1e3:0})}$.sort((_,U)=>U.lines-_.lines);let B=$d({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),T=ow({heuristic:B,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:m,cosmeticDeleted:b,docsDeleted:g,docsAdded:y,configDeleted:x,codeDelta:f+w+b>0,origins:$,unattributedLines:P,ghost:w===0&&f>0,heuristic:B,intent:T}}function kT(e,{minLines:t=rw}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return va.has(n)?hc(e)>=t:!1}function hc(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function Qh(e){let t=e.genUsd;return{...e,genUsd:hn(t),reworkChargedUsd:hn(e.reworkChargedUsd),reworkPendingUsd:hn(e.reworkPendingUsd),trueUsd:hn(t+e.reworkChargedUsd),multiplier:t>0?hn((t+e.reworkChargedUsd)/t):null}}function xT(e,{window:t=lo,boxMeta:n={}}={}){let r=e||[],o=r.filter(T=>T.type==="cost.recorded"),s=r.filter(T=>T.type==="code.committed"),a=r.filter(T=>T.type==="code.rework"),i=T=>Array.isArray(T?.shas)&&T.shas.length?T.shas:T?.sha?[T.sha]:[],c=new Map,l=new Set;for(let T of r)if(T.type==="rework.cause.offered")for(let _ of i(T.payload))l.add(_);else if(T.type==="rework.cause.answered"&&T.payload?.cause)for(let _ of i(T.payload))c.set(_,T.payload.cause);else if(T.type==="rework.cause.retracted")for(let _ of i(T.payload))c.delete(_);let u={},d=(T,_,U)=>xa({trackId:T,boxId:_,epoch:U??0}),p=(T,_={})=>{if(!u[T]){let J=Ed(T)||{};u[T]={key:T,...J,provider:null,model:null,...Zh()}}let U=u[T];return _.provider&&!U.provider&&(U.provider=_.provider),_.model&&!U.model&&(U.model=_.model),U};for(let T of o){if(!T.boxId)continue;let _=d(T.trackId,T.boxId,T.epoch),{usd:U,model:J}=Xt(T),R=p(_,{provider:T.provider,model:J!=="unknown"?J:null});R.genUsd+=U}let f=new Map;for(let T of s){let _=`${T.trackId}/${T.boxId}`;(f.get(_)??f.set(_,[]).get(_)).push({...T,ts:T.payload?.ts??T.ts})}for(let T of f.values())T.sort((_,U)=>_.ts-U.ts);let w=(T,_,U,J)=>{let R=f.get(`${T}/${_}`)||[],A=-1/0;for(let K of R)K.ts<J&&(A=K.ts);let M=0,N=0;for(let K of o)K.trackId!==T||K.boxId!==_||(K.epoch??0)===(U??0)&&(K.ts<=A||K.ts>J||(M+=Xt(K).usd,N++));return{usd:M,turns:N,from:Number.isFinite(A)?A:null}},m={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},x=0,b=[],I=[],$={},P={},F=new Set;for(let T of a){let _=T.payload||{};if(!_.sha||F.has(_.sha))continue;if(F.add(_.sha),_.codeDelta===!1){x++;continue}let U=Ed(_.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:J,turns:R}=w(U.trackId,U.boxId,U.epoch,_.ts??T.ts),A=lF.includes(_.intent?.intent)?_.intent.intent:"unknown";y[A]+=1;let M=null;c.has(_.sha)?M={cause:c.get(_.sha),level:"B",basis:"operator"}:(_.heuristic?.level&&_.heuristic.level!=="C"||_.heuristic)&&(M=_.heuristic);let N=M?.level??"none";g[N]=(g[N]||0)+1;let K=cF.has(N),Y=Number(_.deleted)||0,fe=Array.isArray(_.origins)?_.origins:[],Ie=fe.filter(X=>X.class==="rework").reduce((X,et)=>X+et.lines,0),Ce={sha:_.sha,subject:_.subject??"",ts:_.ts??T.ts,trackId:T.trackId,fixKey:_.fixKey??null,fixProvider:_.fixProvider??T.provider??null,fixUsd:hn(J),fixTurns:R,linesReworked:Ie,unattributedLines:Number(_.unattributedLines)||0,ghost:_.ghost===!0,intent:{intent:A,basis:_.intent?.basis??null},verdict:M?{cause:M.cause,level:N,basis:M.basis??null}:null,charged:hn(0),origins:[]};if(A==="planned"||M?.cause===_d){m.planned+=J;for(let X of fe)X.class==="rework"&&Ce.origins.push({key:X.key,provider:X.provider??null,model:X.model??null,lines:X.lines,ageDays:X.ageDays,class:X.class,usd:0})}else if(_.ghost||Y===0)m.ghost+=J;else{let X=0;for(let Ee of fe){let se=Ee.lines/Y,ee=J*se;if(X+=ee,Ee.class==="self"){m.self+=ee;continue}let Oe=Ee.class==="rework"?1:Number(Ee.decay)||0,z=ee*Oe;if(m.decayed+=ee-z,z<=0)continue;let we=p(Ee.key,{provider:Ee.provider,model:Ee.model});we.fixes+=1,we.linesReworked+=Ee.class==="rework"?Ee.lines:0;let Fe=M?.cause&&mc.includes(M.cause)?M.cause:"unclassified";we.causes[Fe]+=1,K?(we.reworkChargedUsd+=z,m.charged+=z,Ce.charged=hn(Ce.charged+z)):(we.reworkPendingUsd+=z,m.pending+=z),Ce.origins.push({key:Ee.key,provider:we.provider,model:we.model,lines:Ee.lines,ageDays:Ee.ageDays,class:Ee.class,usd:hn(z)})}let et=Math.max(0,J-X);m.unattributed+=et}b.push(Ce),!c.has(_.sha)&&l.has(_.sha)&&I.push(_.sha)}for(let T of Object.values(u)){let _=T.provider||"unknown",U=T.model||"unknown",J=R=>{R.genUsd+=T.genUsd,R.reworkChargedUsd+=T.reworkChargedUsd,R.reworkPendingUsd+=T.reworkPendingUsd,R.linesReworked+=T.linesReworked,R.fixes+=T.fixes;for(let A of Object.keys(R.causes))R.causes[A]+=T.causes[A]};J($[_]||=Zh()),J(P[U]||=Zh())}b.sort((T,_)=>_.ts-T.ts);let B=Object.values(u).map(T=>{let _=n[`${T.trackId}/${T.boxId}`]||{};return Qh({...T,trackName:_.trackName??null,label:_.label??null})}).sort((T,_)=>_.reworkChargedUsd+_.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||_.genUsd-T.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${yT} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:x,byEpoch:Object.fromEntries(B.map(T=>[T.key,T])),epochs:B,byProvider:Object.fromEntries(Object.entries($).map(([T,_])=>[T,Qh(_)])),byModel:Object.fromEntries(Object.entries(P).map(([T,_])=>[T,Qh(_)])),buckets:Object.fromEntries(Object.entries(m).map(([T,_])=>[T,hn(_)])),fixUsdTotal:hn(Object.values(m).reduce((T,_)=>T+_,0)),fixes:b,verdicts:g,pendingTaps:I,commits:s.length}}var sF,aF,ew,hT,wT,gT,iF,lo,nw,rw,mc,_d,cF,lF,va,yT,uF,fF,pT,mF,hF,wF,gF,yF,fT,bF,kF,xF,vF,tw,Td,hn,Zh,Rd=W(()=>{Yr();sF=oF(rF),aF=64*1024*1024,ew=(e,t)=>sF("git",["-C",e,...t],{maxBuffer:aF,timeout:6e4}),hT="Bostrat-Epoch",wT="Bostrat-Model",gT="Bostrat-Fix-Cause",iF=24*36e5,lo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,nw=90,rw=3,mc=Object.freeze(["defect","design","requirements","style"]),_d="not-a-fix",cF=new Set(["A","B","E"]),lF=Object.freeze(["fix","likely-fix","planned","unknown"]),va=new Set(["fix","likely-fix"]),yT=.8;uF={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};fF=/^revert\b|^revert "/i,pT=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,mF=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,hF=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;wF=/^([a-z]+)(\([^)]*\))?!?:\s/i,gF=new Set(["fix","hotfix","bugfix","revert"]),yF=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),fT=/\bBP-[A-Z]*\d+\b/i,bF=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);kF=[/(^|\/)\.bostrat\//,/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Gemfile\.lock|go\.sum|composer\.lock)$/,/\.min\.(js|css)$/,/\.map$/,/\.snap$/,/(^|\/)(node_modules|dist|build|vendor|\.next|target)\//],xF=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],vF=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];tw=e=>String(e??"").replace(/\s+/g," ").trim(),Td=400;hn=e=>Math.round(e*1e4)/1e4,Zh=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as $F}from"node:child_process";import{promisify as RF}from"node:util";function vT(e,t=Date.now()){return Lf(e,t)??0}function MF(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function ST(e,t,{now:n=Date.now()}={}){let r=vT(t,n),o=await q(e);return Id({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:MF(o,t.name,r)})}function CF(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function NF(e,t,n,r){let o=Array.isArray(t?.epochs)?t.epochs:[],s=r>0?o[r-1]:null,a=s?.endReason?.code??(typeof s?.endReason=="string"?s.endReason:null),i=CF(n,t.name),c=i?ar(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function PF(e,t){try{let{stdout:n}=await sw(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function DF(e){try{let{stdout:t}=await sw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function AT(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await q(e);if(a.some(w=>w.type==="code.committed"&&w.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:w}=await sw(r,["show","-s","--format=%ct",n]),m=Number(w.trim())*1e3;Number.isFinite(m)&&m>0&&(i=m)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=vT(t,i),l=await PF(r,n),u=await DF(r),d=await C(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:u,...l,ts:i}}),p=null,f=!1;try{let w=await bT(r,n,{fixKey:xa({trackId:e.id,boxId:t.name,epoch:c}),window:lo,context:{...NF(e,t,a,c),ref:u,provider:t.agent??null}});if(w&&(p=await C(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:d.id,payload:w}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&kT(w))){let g=hc(w),y=w.origins.filter(x=>x.class==="rework").slice(0,3);await C(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:{sha:n,subject:w.subject,linesReworked:g,origins:y.map(x=>({key:x.key,provider:x.provider,model:x.model,lines:x.lines,ageDays:x.ageDays})),heuristic:w.heuristic,intent:w.intent,ts:i}}),f=!0}}catch(w){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${w?.message||w}`)}return{recorded:!0,event:d,rework:p,offered:f}}function TT(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function ET(e,t,n){if(!mc.includes(n)&&n!==_d)throw new Error(`bad cause "${n}" (${mc.join("|")}|${_d})`);let r=await q(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(TT(r,t))throw new Error("already answered");return C(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function _T(e,t){let n=await q(e);if(!TT(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return C(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function Od(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await q(e);if(c.some(x=>x.type==="rework.cause.offered"&&x.payload?.pr?.number===n&&(t==null||x.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let x of c)if(x.type==="rework.cause.offered")for(let b of Array.isArray(x.payload?.shas)?x.payload.shas:[x.payload?.sha])b&&l.add(b);let u=new Map;for(let x of c)x.type==="code.committed"&&x.payload?.sha&&u.set(x.payload.sha,x.payload.ref??null);let d=ow({heuristic:$d({subject:r}),subject:r,ref:o}),p=[];for(let x of c){if(x.type!=="code.rework")continue;let b=x.payload||{};if(!b.sha||l.has(b.sha)||b.codeDelta===!1||o&&u.has(b.sha)&&u.get(b.sha)!==o)continue;let I=b.intent?.intent??"unknown";(va.has(I)||I==="unknown"&&va.has(d.intent))&&hc(b)!==0&&p.push(b)}let f=p.reduce((x,b)=>x+hc(b),0);if(f<rw)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let x of p)for(let b of x.origins??[]){if(b.class!=="rework")continue;let I=w.get(b.key)??{key:b.key,provider:b.provider??null,model:b.model??null,lines:0,ageDays:b.ageDays};I.lines+=b.lines,I.ageDays=Math.min(I.ageDays,b.ageDays),w.set(b.key,I)}let m=p.map(x=>x.sha),g=p.map(x=>x.heuristic).find(x=>x&&x.level!=="C")??$d({subject:r})??p.map(x=>x.heuristic).find(Boolean)??null,y=va.has(d.intent)?d:p.find(x=>va.has(x.intent?.intent))?.intent??d;return await C(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:m[m.length-1],shas:m,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((x,b)=>b.lines-x.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:m}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var OF,sw,Md=W(()=>{me();_u();Rd();OF=RF($F),sw=(e,t)=>OF("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as BF}from"node:child_process";import{promisify as jF}from"node:util";async function aw(e,t,{midTurn:n=is,pollMs:r=LF,capMs:o=FF}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function CT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){IT.lastIndex=n;let o=IT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
|
|
195
|
+
`,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+VF(a)+"[ \\t]*$","m").exec(t.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;t=t.slice(0,i)+t.slice(u)}return t}function iw(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function PT(e){let t=CT(e),n=t.match(qF);if(!n)return null;let r=iw(t,n.index);return GF.test(r)?null:{repo:r.match(NT)?.[1]??null,head:r.match(zF)?.[1]??null}}function DT(e){let t=CT(e),n=t.match(KF);if(!n)return null;let r=iw(t,n.index),o=iw(t,n.index+n[0].length),s=null,a=o.trim().split(/\s+/).filter(Boolean);for(let i=0;i<a.length;i++){let c=a[i];if(c.startsWith("-")){YF.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(NT)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function ZF(e,t,{exclude:n=()=>!1}={}){let r=async i=>{pr("observer");let{stdout:c}=await $T("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",XF],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw ao(l)&&io(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-UF&&!n(c)),s=await En({slug:e}),a=o(await r(s));return!a.length&&s.GH_TOKEN&&(a=o(await r({}).catch(()=>[]))),a.sort((i,c)=>Date.parse(c.createdAt)-Date.parse(i.createdAt))}async function QF(e,t){if(t)return[t];let n=[];for(let r of BT(e)){let o=await Re(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await nr().catch(()=>[])){let o=await Re(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function BT(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function eU(e,t,n){let r=await ka(e).catch(()=>[e.workspace?.branch].filter(Boolean)),o=t?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||JF(c.headRefName,e.id),i=[];for(let c of await QF(e,t?.repo??null)){let l;try{l=await ZF(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await ut(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===e.id&&d.announced)return{settled:!0};if(d&&d.trackId!==e.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==e.id||d.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function jT(e){if(!e)return 0;let t=0;for(let n of mr)n.startsWith(`${e}|`)&&t++;return t}function LT(){for(let e of[...cw])e()}function FT(e,t,{delays:n=RT,turnEnd:r}={}){let o=PT(t.command);if(!o)return null;let s=!!DT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(mr.has(a))return null;mr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(m=>{let g=()=>{clearTimeout(y),cw.delete(g),m()},y=setTimeout(g,l);cw.add(g)});let u=await eU(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Ut({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!w&&!(f?.trackId===e.id&&await ur(d,p.number))?null:(await aw(t.box,t.agent,r),await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),p)}return null}finally{mr.delete(a)}})();return c.catch(()=>mr.delete(a)),c}function UT(e,t,{delays:n=RT,turnEnd:r,openedWait:o}={}){let s=DT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(mr.has(a))return null;mr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let d=[];if(c)d=[c];else{let w=BT(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let m of w){let g=await Re(m).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await ka(e).catch(()=>[])).filter(w=>w!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(w,m)=>{let g=await ut(c,w.number);return g&&g.trackId!==e.id?null:(g||await Ut({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await sc(c,w.number),m&&((await q(e).catch(()=>[])).some(b=>b.type==="pr.state.changed"&&(b.payload?.change==="auto-armed"||b.payload?.change==="merged")&&b.payload?.number===w.number)||(await aw(t.box,t.agent,r),await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:w.number,url:w.url,title:w.title,branch:w.headRefName,repo:c}}))),w)},f=null;for(let w of n){await new Promise(P=>setTimeout(P,w));let m=[];for(let P of d)try{pr("observer");let{stdout:F}=await $T("gh",["pr","view",String(l),"--repo",P,"--json",tU],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await En({slug:P})}}),B=JSON.parse(F||"null");B?.number&&m.push({slug:P,pr:B})}catch(F){ao(F)&&io(F)}let g=m.find(P=>P.pr.state==="MERGED")??(m.length===1?m[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(f=y,s.auto)return p(y,!0);continue}let x=await ut(c,y.number);if(x&&x.trackId!==e.id)return null;x||await Ut({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await aw(t.box,t.agent,r);let b=await q(e).catch(()=>[]);if(b.some(P=>P.type==="pr.state.changed"&&P.payload?.change==="merged"&&P.payload?.number===y.number))return null;let I=P=>P.some(F=>F.type==="pr.state.changed"&&F.payload?.change==="opened"&&F.payload?.number===y.number),$=0;if(!I(b)){if(PT(t.command)&&await ur(c,y.number)){let P=Date.now();$=P+1,await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:P,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await ut(c,y.number))?.announced){let P=o?.capMs??HF,F=o?.pollMs??WF,B=Date.now()+P;for(;Date.now()<B&&(await new Promise(T=>setTimeout(T,F)),!I(await q(e).catch(()=>[]))););}}return await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),$),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await Od(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await wr(c,y.number).catch(()=>{}),await hr(c,y.number).catch(()=>{}),await oo(c,y.number,"merged"),y}return f?p(f,!1):null}finally{mr.delete(a)}})();return i.catch(()=>mr.delete(a)),i}var $T,RT,LF,FF,UF,HF,WF,OT,MT,qF,KF,GF,IT,VF,NT,zF,JF,YF,XF,mr,cw,tU,Cd=W(()=>{me();Pr();gt();ic();Dn();gr();fc();cs();Md();$T=jF(BF),RT=[4e3,15e3,45e3],LF=2500,FF=5*6e4;UF=15e3,HF=9e4,WF=2e3,OT=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,MT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,qF=new RegExp(`${OT}${MT}create\\b`),KF=new RegExp(`${OT}${MT}merge\\b`),GF=/\s--web\b/,IT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,VF=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");NT=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,zF=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,JF=uT;YF=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);XF="number,url,title,headRefName,createdAt";mr=new Set;cw=new Set;tU="number,url,title,headRefName,state"});import nU from"node:fs/promises";import uw from"node:path";import rU from"node:os";function lw(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function Nd(e){let t=oU.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=lw(n,"from"),s=o?o.replace(/^uds:/,""):null,a=HT(s);return{socket:s,pid:a,name:lw(n,"from-name"),mode:lw(n,"from-mode"),text:r.trim()}}function HT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function sU(){return process.env.CLAUDE_CONFIG_DIR?uw.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):uw.join(rU.homedir(),".claude","sessions")}async function aU(e){let t=HT(e);if(!t)return null;try{let n=await nU.readFile(uw.join(sU(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function WT(e,t){let n=await aU(e?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof t=="function")try{o=await t(n?.sessionId??null,r)??null}catch{o=null}return{socket:e?.socket??null,pid:n?.pid??e?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??e?.name??null,mode:e?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var oU,dw=W(()=>{oU=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function qT(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}async function KT(e,t,n=pw){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await cU(`${Ne(t)}${e}`,{headers:lU(t),signal:r.signal})}finally{clearTimeout(o)}}async function wc({env:e=process.env,force:t=!1,timeoutMs:n=pw}={}){if(!qT(e))return{followups:[],source:"unconfigured"};if(!t&&ls&&Date.now()-ls.at<iU)return{followups:ls.followups,source:"cache"};try{let r=await KT("/v1/followups?deleted=1",e,n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.followups)?o.followups:[];return ls={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return ls?{followups:ls.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function GT(e,{env:t=process.env,timeoutMs:n=pw}={}){if(!e)return{followup:null,source:"unconfigured"};if(!qT(t))return{followup:null,source:"unconfigured"};try{let r=await KT(`/v1/followups/${encodeURIComponent(e)}`,t,n);if(r.status===404)return{followup:null,source:"gone"};if(!r.ok)throw new Error(`plane ${r.status}`);return{followup:(await r.json())?.followup??null,source:"plane"}}catch(r){let o=ls?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var iU,pw,ls,cU,lU,VT=W(()=>{gt();iU=6e4,pw=5e3,ls=null,cU=(...e)=>fetch(...e);lU=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function uo(e,t){if(fw.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}fw.add(e);try{return await t()}finally{fw.delete(e)}}var fw,gc=W(()=>{fw=new Set});import{randomUUID as Aa,createHash as uU}from"node:crypto";function XT(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function hU(e){for(let[t,n]of mU)if(t.test(String(e||"")))return`a standing prompt must not embed this Track's specifics (${n}) \u2014 the card supplies them at fire time; arm a one-shot with \`offer\` instead`;return null}function ZT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=Sa(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>zT)throw new Error(`label must be \u2264${zT} characters`);let o=Sa(n.trigger)||(n.ship?"now":""),s=t?pU:YT.filter(u=>u!=="track.opened");if(!s.includes(o))throw new Error(`trigger must be one of ${s.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let a=n.ship&&o==="now"?gU(n.ship):null,i=Sa(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>JT)throw new Error(`prompt must be \u2264${JT} bytes`);if(t){let u=hU(i);if(u)throw new Error(u)}let c=Sa(n.why).slice(0,dU)||null,l=t?wU(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function wU(e){if(e==null||e===""||e==="*")return null;let t=String(e).trim();if(!/^[\w.-]+\/[\w.-]+$/.test(t))throw new Error(`repo must be a forge slug like owner/name, got "${e}"`);return t}function gU(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):mw.slice();for(let i of n)if(!mw.includes(i))throw new Error(`ship.actions may only contain ${mw.join(" | ")}, got "${i}"`);if(!n.length)throw new Error("ship.actions must name at least one of commit | push | pr");let r=t.rebase==null?"none":String(t.rebase).trim();if(!["offered","none"].includes(r))throw new Error(`ship.rebase must be "offered" or "none", got "${t.rebase}"`);let o=null;if(t.toPr!=null&&t.toPr!==""){let i=Number(t.toPr);if(!Number.isInteger(i)||i<=0)throw new Error(`ship.toPr must be a PR number, got "${t.toPr}"`);o=i}let s=Sa(t.base)||null,a=null;if(t.repos!=null){if(!Array.isArray(t.repos))throw new Error("ship.repos must be an array of checkout names");a=t.repos.map(i=>Sa(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function Pd(e,{trigger:t=null}={}){let n=new Map;for(let r of e){let o=r.payload||{};if(r.type==="followup.armed"&&o.armId)o.replaces&&n.delete(o.replaces),n.set(o.armId,{...o,ts:o.ts??r.ts,boxId:r.boxId??null,provider:r.provider??null});else if(r.type==="followup.armed.cancelled"&&o.armId)n.delete(o.armId);else if(r.type==="followup.offered")for(let s of o.rows||[])s.armId&&n.delete(s.armId)}return[...n.values()].filter(r=>!t||r.trigger===t)}async function QT(e,t,{pull:n=wc,ship:r={}}={}){if(gw(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead");let o=ZT(t);if(o.ship)return{kind:"ship",...await xU(e,o,r)};let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null};if(o.trigger==="now"){let g=Aa(),y=Aa();return await C(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:g,trigger:"now",label:o.label,prompt:o.prompt,why:o.why}}),await C(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:y,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:hw(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:y,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=XT(o.label),d=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(d)return{kind:"covered",covered:{id:d.id,label:d.label},...o};let p=await q(s),f=Pd(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,m=Aa();return await C(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:m,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...w?{replaces:w}:{}}}),{kind:"armed",armId:m,replaces:w,...o}}async function eE(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await q(n);if(!Pd(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await C(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function tE(e,t,{pull:n=wc}={}){if(gw(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=ZT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await q(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=XT(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),f=d.find(g=>g.status!=="deleted");if(f)throw new Error(`"${f.label}" (${ww[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let w=Aa(),m=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await C(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:m?.agent??null,payload:{ts:Date.now(),proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function nE(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await q(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("followupId required \u2014 the follow-up is created on the plane before the card is answered");let i=a.payload;return await C(o,{type:"followup.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,followupId:String(r),label:i.label,trigger:i.trigger,repo:i.repo??null}}),await C(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",followupId:String(r)}}),{proposalId:t,action:"created",followupId:String(r)}}async function yc(e,t,n={},{pull:r=wc}={}){if(!e||gw(e))return null;let o={id:e.id,cwd:e.cwd},s=await q(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=m=>{let g=(m?.prs||[]).filter(y=>Number.isFinite(Number(y?.number))).map(y=>`${y?.repo??m?.repo??""}#${Number(y.number)}`);return Number.isFinite(Number(m?.prNumber))&&g.push(`${m?.repo??""}#${Number(m.prNumber)}`),g},f=new Set(p(n));if(s.some(m=>m.type==="followup.offered"&&m.payload?.trigger==="pr.merged"&&p(m.payload?.context).some(g=>f.has(g))))return null}let i=Pd(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:hw(p.prompt),origin:"agent",why:p.why??null})),c=[];if(t!=="now"){let{followups:p}=await r().catch(()=>({followups:[]}));c=p.filter(f=>f.status==="active"&&f.mode!=="off"&&f.trigger===t&&(f.repo==null||f.repo===a)).sort((f,w)=>{let m=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return m(w)-m(f)||(f.origin==="operator"?-1:0)-(w.origin==="operator"?-1:0)||(w.createdAt||0)-(f.createdAt||0)}).map(f=>({followupId:f.id,label:f.label,promptPreview:yU(f.prompt),promptHash:hw(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,fU);if(!l.length)return null;let u=Aa(),d={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await C(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:d}),d}function bU(e){let t=e?.context||{},n=Array.isArray(t.prs)&&t.prs.length?t.prs:t.prNumber?[{number:t.prNumber,title:t.prTitle,url:t.prUrl,repo:t.repo}]:[],r=o=>`PR #${o.number}${o.title?` "${o.title}"`:""}${o.url?` (${o.url})`:""}${o.repo?` on ${o.repo}`:""}`;switch(e?.trigger){case"pr.merged":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} merged:`:"Follow-up the operator tapped after this Track's PR merged:";case"pr.opened":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} opened:`:"Follow-up the operator tapped after this Track's PR opened:";case"checks.green":return n.length?`Follow-up the operator tapped after CI went green on ${n.map(r).join(" and ")}:`:"Follow-up the operator tapped after CI went green:";case"ship.done":return"Follow-up the operator tapped after the ship you just ran completed:";default:return"Follow-up the operator tapped:"}}async function rE(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return uo(`fu:${e.id}:${t}`,()=>kU(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function kU(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=GT}=s,l={id:e.id,cwd:e.cwd},u=await q(l),d=u.find(b=>b.type==="followup.offered"&&b.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(b=>b.type==="followup.answered"&&b.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=b=>C(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...b}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(b=>b.followupId).filter(Boolean),armIds:p.map(b=>b.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,m=null;if(n){if(!p.some($=>$.followupId===n))throw new Error("that follow-up is not on this card");let{followup:b,source:I}=await c(n);if(I==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!b||b.status!=="active"){await f({action:"removed",followupId:n});let $=new Error("removed in Settings since it was offered");throw $.code="removed",$}w=b.prompt,m=b.label}else{let b=p.find($=>$.armId===r);if(!b)throw new Error("that arm is not on this card");if(w=u.find($=>$.type==="followup.armed"&&$.payload?.armId===r)?.payload?.prompt??b.prompt,m=b.label,!w)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let y=`${bU(d.payload)}
|
|
196
196
|
|
|
197
|
-
${w}`,
|
|
197
|
+
${w}`,x=await a(e.id,y,{kind:"followup-go"});return await f({action:"sent",...n?{followupId:n}:{armId:r},label:m,...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:!!x?.queued}}async function xU(e,t,{changedRepos:n=null,probe:r=xd,branchOf:o=co}={}){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(()=>[]),y=s.repos?g.filter(x=>s.repos.includes(x.name)):g;l=y.length?y.map(x=>({name:x.name,slug:x.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,d=s.rebase==="offered",p=await r(e,{branch:u,rebase:d}).catch(()=>null),f=[...d?["rebase"]:[],...s.actions].filter(g=>ro.includes(g));if(p&&p.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:p};let w=Aa(),m=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await C(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:w,ts:Date.now(),excerpt:m,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:p?.available,defaults:p?p.defaults.filter(g=>f.includes(g)||g==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?f.filter(g=>p.available.includes(g)):f,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:w,branch:u,offered:f,available:p?.available??null,prState:p?.prState??null}}function oE(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 sE(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 aE(e,{pull:t=wc}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await q({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?Pd(s):[]}}var zT,JT,dU,YT,pU,ww,fU,mw,hw,Sa,mU,gw,yU,Dd=W(()=>{me();ts();Yh();cs();VT();gc();zT=60,JT=8*1024,dU=200,YT=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],pU=YT.filter(e=>e!=="now"&&e!=="track.opened"),ww={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"},fU=3,mw=["commit","push","pr"];hw=e=>uU("sha256").update(String(e)).digest("hex").slice(0,16),Sa=e=>typeof e=="string"?e.trim():"",mU=[[/(^|[^\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"]];gw=e=>String(e?.name||"").startsWith("\u21BB");yU=e=>String(e||"").split(`
|
|
198
198
|
`).slice(0,3).join(`
|
|
199
|
-
`).slice(0,400)});import{randomUUID as
|
|
200
|
-
`)){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 cU(e,t){let n=`${e.id}:${t.name}`;if(!ww.has(n)){let r=await q(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);ww.set(n,o)}return ww.get(n)}async function sE(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Lo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await cU(e,t),o=iU(await Ct(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 C(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:Cn(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 C(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 ww,aE=W(()=>{fe();Uo();dn();sr();ww=new Map});import Pd from"node:fs";import yw from"node:path";import lU from"node:os";async function pU({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(dU,{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:iE})});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<iE)break}return r}function fU(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 lE(){try{return JSON.parse(Pd.readFileSync(Dd(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function mU(e){try{Pd.mkdirSync(yw.dirname(Dd()),{recursive:!0});let t=Dd()+".tmp";Pd.writeFileSync(t,JSON.stringify(e)),Pd.renameSync(t,Dd())}catch{}}async function gU({fetchImpl:e,now:t=Date.now()}={}){if(lo.rows&&t-lo.at<hU)return lo.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=lE(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await pU({sinceMs:o,cookie:n,fetchImpl:e});lo={at:t,rows:s.map(fU).filter(Boolean),error:null}}catch(s){lo={at:t,rows:null,error:String(s?.message||s)}}return lo.rows}async function yU(e,t){let n=`${e.id}:${t.name}`;if(!gw.has(n)){let r=await q(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);gw.set(n,o)}return gw.get(n)}async function uE(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!cE())return;let r=await gU({fetchImpl:n});if(!r||!r.length)return;let o=await Jv(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await yU(e,t),a=lE(),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",d=l.tokens||null,p=l.vendorCents!=null?l.vendorCents/100:0;!p&&d&&(p=Cn(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await C(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:p,model:u,...d?{tokens:d}:{},...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}})}mU({sinceMs:c,seen:[...i].slice(-wU)})}catch{}}var uU,cE,dU,iE,hU,lo,Dd,wU,bw,gw,kw=W(()=>{fe();Qh();sr();uU=process.env.BOSTRAT_STATE_DIR||yw.join(process.env.HOME||lU.tmpdir(),".bostrat"),cE=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,dU="https://cursor.com/api/dashboard/get-filtered-usage-events",iE=100;hU=5*6e4,lo={at:0,rows:null,error:null},Dd=()=>yw.join(uU,"cursor-usage.json");wU=5e3;bw=()=>({enabled:cE(),lastPollAt:lo.at||null,error:lo.error}),gw=new Map});import{randomUUID as bU,createHmac as kU}from"node:crypto";function pE(e){vw=typeof e=="string"&&e?e:null}function xU(e){if(!vw)return null;let t=Ue(e);return t?kU("sha256",Buffer.from(vw,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function mE(){let e={};for(let t of hE)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function dE(e,t){let n=Math.max(0,Number(t)||0);for(let r of hE)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function wE(){let e={};for(let t of fE)e[t]=0;return e}function SU(){Ln={total:new Map,holds:wE(),queueWaitMs:mE(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function gE({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=Ln;return{total:[...n.total].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,producer:a,outcome:i,n:o}}),holds:{...n.holds},queueWaitMs:{buckets:{...n.queueWaitMs.buckets},sumMs:n.queueWaitMs.sumMs,count:n.queueWaitMs.count},readyWaitMs:[...n.readyWaitMs].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,outcome:a,buckets:{...o.buckets},sumMs:o.sumMs,count:o.count}}),verify:[...n.verify].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,verdict:a,cliVersion:i||null,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function bc({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:vU.has(t)?t:"composer"}function kc({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:bU(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:xU(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:wE(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function xc(e,t,{position:n=null,reason:r="busy"}={}){!t||!e||(t.queuedAt=Date.now(),await C(e,{type:"delivery.queued",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:{ts:t.queuedAt,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},reason:r,position:n,textBytes:t.textBytes,textHmac16:t.textHmac16,requeued:t.requeued}}).catch(()=>{}))}function yE(e,t){fE.includes(t)&&(e?.holds&&(e.holds[t]+=1),Ln.holds[t]+=1)}function vc(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}function AU(e){let t=e?.boxes?.find?.(n=>n.name===e.leadBox);return typeof t?.cliVersion=="string"&&t.cliVersion?t.cliVersion:null}async function wn(e,t,n,{now:r=Date.now}={}){if(!t||t.settled)return null;t.settled=!0,t.outcome=n;let o=r(),s=t.provider||"unknown",a=t.queuedAt!=null,i=a?Math.max(0,(t.dequeuedAt??o)-t.queuedAt):null;if(xw(Ln.total,`${s}|${t.producer}|${n}`),a&&dE(Ln.queueWaitMs,i),t.readyWaitMs!=null){let u=`${s}|${t.readyOutcome||"unknown"}`;Ln.readyWaitMs.has(u)||Ln.readyWaitMs.set(u,mE()),dE(Ln.readyWaitMs.get(u),t.readyWaitMs)}let c=AU(e);t.verify?.verdict&&(xw(Ln.verify,`${s}|${t.verify.verdict}|${c||""}`),t.verify.retries&&xw(Ln.retries,s,t.verify.retries));let l={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:c,textBytes:t.textBytes,textHmac16:t.textHmac16,paste:t.paste,attachments:t.attachments,outcome:n,queued:a,queueWaitMs:i,queueHolds:{...t.holds},requeued:t.requeued,readyWaitMs:t.readyWaitMs,readyOutcome:t.readyOutcome,verify:t.verify?{...t.verify}:null,receiptMs:null,totalMs:Math.max(0,o-t.t0)};return e&&await C(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:l}).catch(()=>{}),l}function Aa(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var vw,fE,hE,vU,Ln,xw,Sw=W(()=>{fe();Wi();vw=null;fE=["busy","prompt","handoff","noSession","cap","grace"],hE=[500,2e3,1e4,6e4,6e5],vU=new Set(["composer","voice","loop"]);Ln=null;SU();xw=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import Tc from"node:fs/promises";import Nt from"node:path";import TU from"node:os";import EU from"node:net";import{randomUUID as _U}from"node:crypto";import{execFile as IU}from"node:child_process";import{promisify as $U}from"node:util";function DU(e){for(let t of Rw(e))if(!AE.test(t))return t;return null}function TE(e){let t=Rw(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function BU(e,t){let n=TE(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Nt.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Nt.resolve(e,n[r+1])}return e}function LU(e){let t=!1,n=!1;for(let r of Rw(e)){if(!t){if(AE.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Aw(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Aw(r))return`serves the filesystem root ("${r}")`;continue}if(Aw(r))return`serves the filesystem root ("${r}")`;if(jU(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function UU(e,t){if(Nt.resolve(e)===Nt.resolve(t))return!0;let[n,r]=await Promise.all([Bd(e),Bd(t)]);return n===r}async function HU(e){let n=(await Tc.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 EE(Nt.join(e,o.name,_w))?`./${o.name}`:null))).filter(Boolean)}async function WU(e,t){let[n,r]=await Promise.all([Bd(e),Bd(t)]),o=Nt.relative(n,r);if(o&&(o.startsWith("..")||Nt.isAbsolute(o)))throw Sc(`serve directory escapes the Track workspace: ${t}`)}async function qU(e,t){let n=LU(t);if(n)throw Sc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await FU(e))throw Sc(`serve directory does not exist: ${e}`);let r=DU(t);if(!r)return;if(!r.includes("/")&&!await h0(r,{loginShell:!0,failOpen:!0}))throw Sc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(CU.test(t)||NU.has(r)||!MU.has(r)||!TE(t).includes("run")||PU.test(t))return;let o=BU(e,t);if(await EE(Nt.join(o,_w)))return;let s=await HU(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Sc(`no ${_w} in ${o}${a}`)}async function yr(){return Fn||(Tw||=(async()=>{try{Fn=JSON.parse(await Tc.readFile(SE,"utf8"))}catch{Fn={views:[],adoptWatermarks:{}}}finally{Tw=null}return Fn.views||=[],Fn.adoptWatermarks||={},Fn})(),Tw)}async function Hn(){await Ot(SE,Fn)}function gr(e,t,n={}){return C({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 Mw(e){return Ac.get(e)||null}function IE(e,{name:t,box:n}={}){let r=Ac.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 Ac.set(e,o),o}function Iw(e,t){let n=Ac.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function jd(e,{error:t=null}={}){let n=Ac.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function $E(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 $w(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function KU(e,t){let n=$w(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!xE.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!xE.has(s))return s}}function Ec(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=EU.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 Cw(e){if(process.platform!=="darwin"){await Un("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Un("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 RE(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function GU(e,t){let n=new Set(e.views.map(o=>o.port)),r=RE();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=bE;o<=kE;o++)if(!(n.has(o)||r.has(o))&&!await Ec(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${bE}-${kE}`)}async function VU(e){try{let{stdout:t}=await Un(ne,re("list-sessions","-F","#{session_name}"));return t.split(`
|
|
201
|
-
`).some(n=>n.trim()===
|
|
199
|
+
`).slice(0,400)});import{randomUUID as vU}from"node:crypto";function bc(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function iE(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function cE(e){return`job|${e.box}|id:${e.id}`}async function bw(e){return yw.has(e.id)?yw.get(e.id):(Bd.has(e.id)||Bd.set(e.id,q(e).then(t=>{let n={keys:new Set,cmdN:new Map};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(bc({role:o,sourceId:r.payload.sourceId})),n.keys.add(bc({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(bc({role:"user",sourceId:r.payload.sourceId})),n.keys.add(bc({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(iE({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>(n.cmdN.get(r.boxId)??0)&&n.cmdN.set(r.boxId,Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(cE({id:r.payload.id,box:r.boxId}));return yw.set(e.id,n),n}).finally(()=>Bd.delete(e.id))),Bd.get(e.id))}async function lE(e,t){let n=new Set;try{let r=(await bw(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=bc(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?Nd(o.text):null;if(a){await C(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 WT(a,kc),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Y0(o);if(i){await C(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}}),Qi(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 C(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=cA(o.text);if(c&&oE(await q(e).catch(()=>[])))continue;if(c){let l=dA(c),u;if(e.workspace?.kind==="multi"){let w=await us(e).catch(()=>[]);u=w.length?w.map(m=>({name:m.name,slug:m.repo??null})):void 0}let d=(e.workspace?.kind==="multi"?null:await co(e.cwd).catch(()=>null))||e.workspace.branch,p=await xd(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:uA(c);if(p&&p.available.length===0)continue;await C(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:vU(),ts:o.ts,excerpt:c,branch:d,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:p?.available,defaults:p?.defaults,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||u,offered:p?.defaults||f?.offered||void 0,toPr:f?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function uE(e,t){try{let n=await bw(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=iE(o);if(n.keys.has(s))continue;n.keys.add(s);let a=(n.cmdN.get(o.box)??0)+1;n.cmdN.set(o.box,a),await C(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:a}}),FT(e,o),UT(e,o)}}catch{}}async function dE(e,t){try{let n=await bw(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=cE(o);n.keys.has(s)||(n.keys.add(s),await C(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 yw,Bd,pE=W(()=>{me();ts();Yh();Cd();cs();dw();gr();ku();Wu();Dd();yw=new Map,Bd=new Map});function SU(e){let t=[],n=null;for(let r of String(e||"").split(`
|
|
200
|
+
`)){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 AU(e,t){let n=`${e.id}:${t.name}`;if(!kw.has(n)){let r=await q(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);kw.set(n,o)}return kw.get(n)}async function fE(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Fo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await AU(e,t),o=SU(await Nt(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 C(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:Cn(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 C(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 kw,mE=W(()=>{me();Ho();dn();ir();kw=new Map});import jd from"node:fs";import vw from"node:path";import TU from"node:os";async function IU({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(_U,{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:hE})});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<hE)break}return r}function $U(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 gE(){try{return JSON.parse(jd.readFileSync(Ld(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function OU(e){try{jd.mkdirSync(vw.dirname(Ld()),{recursive:!0});let t=Ld()+".tmp";jd.writeFileSync(t,JSON.stringify(e)),jd.renameSync(t,Ld())}catch{}}async function CU({fetchImpl:e,now:t=Date.now()}={}){if(po.rows&&t-po.at<RU)return po.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=gE(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await IU({sinceMs:o,cookie:n,fetchImpl:e});po={at:t,rows:s.map($U).filter(Boolean),error:null}}catch(s){po={at:t,rows:null,error:String(s?.message||s)}}return po.rows}async function NU(e,t){let n=`${e.id}:${t.name}`;if(!xw.has(n)){let r=await q(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);xw.set(n,o)}return xw.get(n)}async function yE(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!wE())return;let r=await CU({fetchImpl:n});if(!r||!r.length)return;let o=await rS(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await NU(e,t),a=gE(),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",d=l.tokens||null,p=l.vendorCents!=null?l.vendorCents/100:0;!p&&d&&(p=Cn(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await C(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:p,model:u,...d?{tokens:d}:{},...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}})}OU({sinceMs:c,seen:[...i].slice(-MU)})}catch{}}var EU,wE,_U,hE,RU,po,Ld,MU,Sw,xw,Aw=W(()=>{me();rh();ir();EU=process.env.BOSTRAT_STATE_DIR||vw.join(process.env.HOME||TU.tmpdir(),".bostrat"),wE=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,_U="https://cursor.com/api/dashboard/get-filtered-usage-events",hE=100;RU=5*6e4,po={at:0,rows:null,error:null},Ld=()=>vw.join(EU,"cursor-usage.json");MU=5e3;Sw=()=>({enabled:wE(),lastPollAt:po.at||null,error:po.error}),xw=new Map});import{randomUUID as PU,createHmac as DU}from"node:crypto";function kE(e){Ew=typeof e=="string"&&e?e:null}function BU(e){if(!Ew)return null;let t=Ue(e);return t?DU("sha256",Buffer.from(Ew,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function SE(){let e={};for(let t of vE)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function bE(e,t){let n=Math.max(0,Number(t)||0);for(let r of vE)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function AE(){let e={};for(let t of xE)e[t]=0;return e}function LU(){Ln={total:new Map,holds:AE(),queueWaitMs:SE(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function TE({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=Ln;return{total:[...n.total].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,producer:a,outcome:i,n:o}}),holds:{...n.holds},queueWaitMs:{buckets:{...n.queueWaitMs.buckets},sumMs:n.queueWaitMs.sumMs,count:n.queueWaitMs.count},readyWaitMs:[...n.readyWaitMs].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,outcome:a,buckets:{...o.buckets},sumMs:o.sumMs,count:o.count}}),verify:[...n.verify].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,verdict:a,cliVersion:i||null,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function xc({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:jU.has(t)?t:"composer"}function vc({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:PU(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:BU(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:AE(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function Sc(e,t,{position:n=null,reason:r="busy"}={}){!t||!e||(t.queuedAt=Date.now(),await C(e,{type:"delivery.queued",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:{ts:t.queuedAt,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},reason:r,position:n,textBytes:t.textBytes,textHmac16:t.textHmac16,requeued:t.requeued}}).catch(()=>{}))}function EE(e,t){xE.includes(t)&&(e?.holds&&(e.holds[t]+=1),Ln.holds[t]+=1)}function Ac(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}function FU(e){let t=e?.boxes?.find?.(n=>n.name===e.leadBox);return typeof t?.cliVersion=="string"&&t.cliVersion?t.cliVersion:null}async function wn(e,t,n,{now:r=Date.now}={}){if(!t||t.settled)return null;t.settled=!0,t.outcome=n;let o=r(),s=t.provider||"unknown",a=t.queuedAt!=null,i=a?Math.max(0,(t.dequeuedAt??o)-t.queuedAt):null;if(Tw(Ln.total,`${s}|${t.producer}|${n}`),a&&bE(Ln.queueWaitMs,i),t.readyWaitMs!=null){let u=`${s}|${t.readyOutcome||"unknown"}`;Ln.readyWaitMs.has(u)||Ln.readyWaitMs.set(u,SE()),bE(Ln.readyWaitMs.get(u),t.readyWaitMs)}let c=FU(e);t.verify?.verdict&&(Tw(Ln.verify,`${s}|${t.verify.verdict}|${c||""}`),t.verify.retries&&Tw(Ln.retries,s,t.verify.retries));let l={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:c,textBytes:t.textBytes,textHmac16:t.textHmac16,paste:t.paste,attachments:t.attachments,outcome:n,queued:a,queueWaitMs:i,queueHolds:{...t.holds},requeued:t.requeued,readyWaitMs:t.readyWaitMs,readyOutcome:t.readyOutcome,verify:t.verify?{...t.verify}:null,receiptMs:null,totalMs:Math.max(0,o-t.t0)};return e&&await C(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:l}).catch(()=>{}),l}function Ta(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var Ew,xE,vE,jU,Ln,Tw,_w=W(()=>{me();Ki();Ew=null;xE=["busy","prompt","handoff","noSession","cap","grace"],vE=[500,2e3,1e4,6e4,6e5],jU=new Set(["composer","voice","loop"]);Ln=null;LU();Tw=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import _c from"node:fs/promises";import Pt from"node:path";import UU from"node:os";import HU from"node:net";import{randomUUID as WU}from"node:crypto";import{execFile as qU}from"node:child_process";import{promisify as KU}from"node:util";function ZU(e){for(let t of Nw(e))if(!ME.test(t))return t;return null}function CE(e){let t=Nw(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function QU(e,t){let n=CE(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Pt.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Pt.resolve(e,n[r+1])}return e}function t4(e){let t=!1,n=!1;for(let r of Nw(e)){if(!t){if(ME.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Iw(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Iw(r))return`serves the filesystem root ("${r}")`;continue}if(Iw(r))return`serves the filesystem root ("${r}")`;if(e4(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function r4(e,t){if(Pt.resolve(e)===Pt.resolve(t))return!0;let[n,r]=await Promise.all([Fd(e),Fd(t)]);return n===r}async function o4(e){let n=(await _c.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 NE(Pt.join(e,o.name,Ow))?`./${o.name}`:null))).filter(Boolean)}async function s4(e,t){let[n,r]=await Promise.all([Fd(e),Fd(t)]),o=Pt.relative(n,r);if(o&&(o.startsWith("..")||Pt.isAbsolute(o)))throw Tc(`serve directory escapes the Track workspace: ${t}`)}async function a4(e,t){let n=t4(t);if(n)throw Tc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await n4(e))throw Tc(`serve directory does not exist: ${e}`);let r=ZU(t);if(!r)return;if(!r.includes("/")&&!await v0(r,{loginShell:!0,failOpen:!0}))throw Tc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(JU.test(t)||YU.has(r)||!zU.has(r)||!CE(t).includes("run")||XU.test(t))return;let o=QU(e,t);if(await NE(Pt.join(o,Ow)))return;let s=await o4(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Tc(`no ${Ow} in ${o}${a}`)}async function kr(){return Fn||($w||=(async()=>{try{Fn=JSON.parse(await _c.readFile(OE,"utf8"))}catch{Fn={views:[],adoptWatermarks:{}}}finally{$w=null}return Fn.views||=[],Fn.adoptWatermarks||={},Fn})(),$w)}async function Hn(){await Mt(OE,Fn)}function br(e,t,n={}){return C({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 Dw(e){return Ec.get(e)||null}function DE(e,{name:t,box:n}={}){let r=Ec.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 Ec.set(e,o),o}function Mw(e,t){let n=Ec.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function Ud(e,{error:t=null}={}){let n=Ec.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function BE(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 Cw(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function i4(e,t){let n=Cw(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!$E.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!$E.has(s))return s}}function Ic(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=HU.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 Bw(e){if(process.platform!=="darwin"){await Un("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Un("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 jE(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function c4(e,t){let n=new Set(e.views.map(o=>o.port)),r=jE();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=_E;o<=IE;o++)if(!(n.has(o)||r.has(o))&&!await Ic(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${_E}-${IE}`)}async function l4(e){try{let{stdout:t}=await Un(ne,oe("list-sessions","-F","#{session_name}"));return t.split(`
|
|
201
|
+
`).some(n=>n.trim()===Ea(e))}catch{return!1}}async function $c(e){try{await Un(ne,oe("kill-session","-t",Ea(e)))}catch{}}async function jw(e){if(!await Mi())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=Ea(e.slug),n=e.serveCwd??e.cwd,r=Pt.dirname(process.execPath);await Un(ne,oe("new-session","-d","-s",t,"-c",n)),await Un(ne,oe("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Un(ne,oe("send-keys","-t",t,"Enter")),await Un(ne,oe("send-keys","-t",t,"-l",e.cmd)),await Un(ne,oe("send-keys","-t",t,"Enter"))}async function RE(e,t=12){try{let{stdout:n}=await Un(ne,oe("capture-pane","-t",Ea(e),"-p"));return String(n||"").trimEnd().split(`
|
|
202
202
|
`).filter(Boolean).slice(-t).join(`
|
|
203
|
-
`)}catch{return""}}async function JU(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await VU(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await vE(e.slug)||"server exited before listening"),wr.delete(e.id),await gr(e,e.state,e.error?{error:e.error}:{}),!0}if(await Ec(e.port))return wr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await gr(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>zU?(e.state="error",e.error=await vE(e.slug)||"never started listening",await gr(e,"error",{error:e.error}),!0):!1;let o=(wr.get(e.id)||0)+1;return wr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function Ld(){if(!Ew){Ew=!0;try{let e=await yr(),t=!1;for(let n of e.views)await JU(n)&&(t=!0);t&&await Hn()}finally{Ew=!1}}}async function Pw({trackId:e}={}){await Ld();let t=await yr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function OE(e){let n=(await yr()).views.find(r=>r.id===e);return n?{...n}:null}function Dw(e){return Fn&&Fn.views.find(t=>t.slug===e)||null}async function Bw({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=Nt.resolve(r,o??"."),d=i==="detected"?null:async()=>{await WU(r,u),await qU(u,n)},p=await yr();if(i!=="detected"){let h=$w(t),g=String(n).trim(),y=p.views.find(k=>k.trackId===e&&(k.slug===h||$w(k.name)===h||k.cmd===g&&Nt.resolve(k.serveCwd??k.cwd)===u));if(y)return YU(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(h=>h.state==="live"||h.state==="starting").length>=uo)throw new Error(`view cap reached (${uo} live) \u2014 stop one first`);let w={id:_U().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:KU(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await GU(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Nw(w),p.views.push(w),await Hn(),await gr(w,"created",{origin:i}),Iw(e,w.id),i==="detected"&&await Ec(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Hn(),await gr(w,"live")),{...w}}async function YU(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 UU(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Ec(t.port))return await Hn(),Iw(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(d=>d.id!==t.id&&(d.state==="live"||d.state==="starting")).length>=uo)throw new Error(`view cap reached (${uo} live) \u2014 stop one first`);return t.origin==="detected"?(await Cw(t.port),t.origin="agent"):await _c(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),wr.delete(t.id),await Nw(t),await Hn(),await gr(t,"created",{restarted:!0,reused:!0}),Iw(t.trackId,t.id),{...t,reused:!0}}async function ME(e){let n=(await yr()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Cw(n.port):await _c(n.slug),n.state!=="stopped"&&(n.state="stopped",wr.delete(n.id),await Hn(),await gr(n,"stopped")),{...n}}async function CE(e){let t=await yr(),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>=uo)throw new Error(`view cap reached (${uo} live) \u2014 stop one first`);return await _c(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),wr.delete(n.id),await Nw(n),await Hn(),await gr(n,"created",{restarted:!0}),{...n}}async function NE(e){let t=await yr(),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 Cw(r.port):await _c(r.slug),t.views.splice(n,1),wr.delete(r.id),await Hn(),await gr(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function jw(e){let t=await yr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await _c(r.slug),wr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Hn()),n.length}async function PE(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await yr(),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 Hn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(XU)){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(!RE().has(c)&&!n.views.some(l=>l.port===c)&&await Ec(c))try{i.push(await Bw({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 Un,RU,SE,bE,kE,uo,OU,Ta,xE,Sc,MU,_w,CU,NU,PU,Rw,AE,Aw,jU,FU,EE,Bd,Fn,Tw,Ac,Ow,_E,wr,zU,Ew,XU,Fd=W(()=>{ht();fe();Dr();Un=$U(IU),RU=process.env.BOSTRAT_STATE_DIR||Nt.join(process.env.HOME||TU.tmpdir(),".bostrat"),SE=Nt.join(RU,"views.json"),[bE,kE]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),uo=Number(process.env.BOSTRAT_VIEW_MAX)||3,OU="bostrat-view-",Ta=e=>`${OU}${e}`,xE=new Set(["bostrat","www","api","views","app"]),Sc=e=>Object.assign(new Error(e),{status:400}),MU=new Set(["npm","pnpm","yarn","bun"]),_w="package.json",CU=/[|;&`]|\$\(/,NU=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),PU=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Rw=e=>String(e).trim().split(/\s+/).filter(Boolean),AE=/^[A-Za-z_][A-Za-z0-9_]*=/;Aw=e=>e==="/",jU=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");FU=e=>Tc.stat(e).then(t=>t.isDirectory(),()=>!1),EE=e=>Tc.stat(e).then(t=>t.isFile(),()=>!1),Bd=e=>Tc.realpath(e).catch(()=>Nt.resolve(e));Fn=null,Tw=null;Ac=new Map,Ow=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,_E=12e3;wr=new Map,zU=12e4;Ew=!1;XU=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function Ea(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>Fw?null:n}function QU(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function Ud(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await q(e)}catch{return}let o=Ea(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await as(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(Lw.get(e.id)||0)<ZU)return;Lw.set(e.id,a);let i;try{i=await Bn(e.cwd,{caller:"reconcile"})}catch{return}let c=await ba(e).catch(()=>[n]),l=(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await $e(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Ut({repo:u,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!p&&!(d?.trackId===e.id&&await cr(u,l.number))){if(!QU(d,o))return;let f=await q(e).catch(()=>null);if(f&&Ea(f)==null)return;await C(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 C(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(()=>{}),Lw.delete(e.id)}var ZU,Lw,Fw,Ic=W(()=>{fe();ss();Cr();Dn();dc();is();ZU=6e3,Lw=new Map,Fw=30*6e4});import Uw from"node:os";import{execFile as e4}from"node:child_process";import{promisify as t4}from"node:util";async function Hd(){if(process.platform!=="darwin")return Uw.freemem();try{let{stdout:e}=await n4("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:Uw.freemem()}catch{return Uw.freemem()}}var n4,Hw=W(()=>{n4=t4(e4)});import nt from"node:fs/promises";import ot from"node:path";import LE from"node:os";import{randomUUID as r4}from"node:crypto";import{execFile as o4}from"node:child_process";import{promisify as s4}from"node:util";import{chromium as a4}from"playwright-core";async function Kn(){return us||(Ww||=(async()=>{try{us=JSON.parse(await nt.readFile(UE,"utf8"))}catch{us={mocks:[]}}finally{Ww=null}return us.mocks||=[],us})(),Ww)}async function tn(){await Ot(UE,us)}function KE(e,t){qn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&qn(e,t.v,"png")}function Et(e,t,n={}){return C({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 nn(e,t){let n=Rc(e.cwd);return{html:ot.join(n,`${e.id}.v${t}.html`),png:ot.join(n,`${e.id}.v${t}.png`)}}function $c(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?ot.join(e.cwd,r):null}function gn(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 Gw(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Wd(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(f4)}function h4(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 m4(e){let t=Buffer.alloc(24),n=await nt.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function w4({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 g4(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((w,h)=>{r.onload=w,r.onerror=()=>h(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,d=s,p=-1,f=-1;for(let w=0;w<s;w++)for(let h=w*o*4,g=0;g<o;g++,h+=4)Math.abs(c[h]-l[0])+Math.abs(c[h+1]-l[1])+Math.abs(c[h+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),w<d&&(d=w),f=w);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:f}}},t.toString("base64"))}async function y4(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((d,p)=>{c.onload=d,c.onerror=()=>p(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 b4({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await a4.launch({executablePath:HE,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Ht("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:_a})).newPage();a.setDefaultTimeout(Ia),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Ia}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Ia});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await g4(a,i),u=l&&w4({...l,pad:l4*_a,align:_a});u&&(i=await y4(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<WE)throw new Ht(`capture produced a ${i.length}-byte image`);let c=Gw(i);if(!c)throw new Ht("output is not a PNG");return await nt.writeFile(t,i),{width:Math.round(c.width/_a),height:Math.round(c.height/_a),dpr:_a,renderMs:Date.now()-r}}catch(s){throw s instanceof Ht?s:new Ht(/timeout/i.test(s?.message||"")?`render timed out after ${Ia}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function jE({htmlPath:e,outPath:t,width:n}){let r=await nt.mkdtemp(ot.join(LE.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Kw(DE,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Ia,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ht(`firefox not found (${DE})`,""):new Ht(c?.killed?`render timed out after ${Ia}ms`:"firefox exited non-zero",s)}let a=await nt.stat(t).catch(()=>null);if(!a||a.size<WE)throw new Ht(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Gw(await m4(t));if(!i)throw new Ht("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await nt.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function k4(e){if(i4==="firefox")return jE(e);try{return await b4(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await jE(e)}catch(n){throw/not found/.test(n?.message||"")?new Ht(`no browser installed \u2014 chromium missing at ${HE} 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 GE(e){return qw=qw.then(e,e),qw}async function VE(e,t){let n=await Kn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await tn(),await Et(r,"rendering",{version:t});try{let o=await Hd();if(o<u4)throw new Ht(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=nn(r,t),a=await x4({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await nt.rm(s.png,{force:!0}).catch(()=>{});return}Vw(r,{v:t,source:"html",htmlRel:ot.relative(r.cwd,s.html),pngRel:ot.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await tn(),await Et(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Wn(r),qn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await tn(),await Et(r,"error",{version:t,error:r.error}),Wn(r)}}}function Vw(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 v4({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?c4:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Oc({trackId:e,group:t}={}){let n=await Kn(),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 br(e){let n=(await Kn()).mocks.find(r=>r.id===e);return n?{...n}:null}function zE({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&&!Wd(t))throw new Error("image must be a PNG");if(n){let o=h4(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>BE)throw new Error(`video must be ${BE/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function JE({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=v4({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=zE({html:n,image:r,video:o}),w=await Kn(),h={id:r4().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:d,height:null,dpr:null,state:"queued",source:p?"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 nt.mkdir(Rc(s),{recursive:!0}),w.mocks.push(h),p?(await nt.writeFile(nn(h,1).html,n),await tn(),await Et(h,"created"),Wn(h),qn(h,1,"html"),GE(()=>VE(h.id,1))):o?(await XE(h,1,o,f),await tn(),await Et(h,"created"),await Et(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr,durationS:h.versions[0]?.durationS??null}),Wn(h),KE(h,h.versions[0])):(await ZE(h,1,r),await tn(),await Et(h,"created"),await Et(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr}),Wn(h),qn(h,1,"png")),{...h}}async function YE(e,{html:t,image:n,video:r,width:o}={}){let a=(await Kn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=zE({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 nt.mkdir(Rc(a.cwd),{recursive:!0}),i?(a.state="queued",await nt.writeFile(nn(a,l).html,t),await tn(),await Et(a,"updated",{version:l}),Wn(a),qn(a,l,"html"),GE(()=>VE(a.id,l))):r?(await XE(a,l,r,c),await tn(),await Et(a,"updated",{version:l}),await Et(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:gn(a)?.durationS??null}),Wn(a),KE(a,a.versions.find(u=>u.v===l))):(await ZE(a,l,n),await tn(),await Et(a,"updated",{version:l}),await Et(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Wn(a),qn(a,l,"png")),{...a}}async function S4(e){try{let{stdout:t}=await Kw(d4,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:qE,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 A4(e,t){try{await Kw(p4,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:qE,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await nt.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function XE(e,t,n,r){let o=Rc(e.cwd),s=ot.join(o,`${e.id}.v${t}.${r.ext}`),a=ot.join(o,`${e.id}.v${t}.poster.png`);await nt.writeFile(s,n);let i=await S4(s),c=await A4(s,a);Vw(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:ot.relative(e.cwd,s),posterRel:c?ot.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 ZE(e,t,n){let r=Gw(n);if(!r)throw new Error("image must be a PNG");let o=nn(e,t);await nt.writeFile(o.png,n),Vw(e,{v:t,source:"image",htmlRel:null,pngRel:ot.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function QE(e){let t=await Kn(),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 Et(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function e_(e){let t=await Kn(),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=nn(r,o);await nt.rm(s.html,{force:!0}).catch(()=>{}),await nt.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await nt.rm(ot.join(r.cwd,s),{force:!0}).catch(()=>{});return await tn(),await Et(r,"deleted"),an("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function t_(e){let n=(await Kn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=ot.join(FE,"mock-archive",e.id),o=Rc(e.cwd),s=ot.join(r,".bostrat","mocks");await nt.mkdir(s,{recursive:!0});let a=await nt.readdir(o).catch(()=>[]);for(let i of a)await nt.copyFile(ot.join(o,i),ot.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 nt.stat(ot.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(),Wn(i)}return await tn(),n.length}async function n_(e){let t=await Kn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await tn();for(let r of n)an("mocks",r.id).catch(()=>{})}return n.length}async function r_(){if(!Ke())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await dt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Kn();for(let r of n.mocks){await Wn(r);for(let o of r.versions||[])o.htmlRel&&await qn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await qn(r,o.v,"png"),o.videoRel&&await qn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Kw,FE,UE,i4,HE,DE,c4,_a,l4,WE,Ia,u4,BE,d4,p4,qE,Ht,us,Ww,Wn,qn,Rc,f4,x4,qw,$a=W(()=>{fe();Dr();Hw();jr();Kw=s4(o4),FE=process.env.BOSTRAT_STATE_DIR||ot.join(process.env.HOME||LE.tmpdir(),".bostrat"),UE=ot.join(FE,"mocks.json"),i4=process.env.BOSTRAT_MOCK_ENGINE||"chromium",HE=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",DE=process.env.BOSTRAT_FIREFOX_BIN||"firefox",c4=1300,_a=2,l4=32,WE=1500,Ia=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,u4=700*1024*1024,BE=100*1024*1024,d4=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",p4=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",qE=2e4,Ht=class extends Error{constructor(t,n=""){super(n?`${t}
|
|
203
|
+
`)}catch{return""}}async function d4(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await l4(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await RE(e.slug)||"server exited before listening"),yr.delete(e.id),await br(e,e.state,e.error?{error:e.error}:{}),!0}if(await Ic(e.port))return yr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await br(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>u4?(e.state="error",e.error=await RE(e.slug)||"never started listening",await br(e,"error",{error:e.error}),!0):!1;let o=(yr.get(e.id)||0)+1;return yr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function Hd(){if(!Rw){Rw=!0;try{let e=await kr(),t=!1;for(let n of e.views)await d4(n)&&(t=!0);t&&await Hn()}finally{Rw=!1}}}async function Lw({trackId:e}={}){await Hd();let t=await kr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function LE(e){let n=(await kr()).views.find(r=>r.id===e);return n?{...n}:null}function Fw(e){return Fn&&Fn.views.find(t=>t.slug===e)||null}async function Uw({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=Pt.resolve(r,o??"."),d=i==="detected"?null:async()=>{await s4(r,u),await a4(u,n)},p=await kr();if(i!=="detected"){let m=Cw(t),g=String(n).trim(),y=p.views.find(x=>x.trackId===e&&(x.slug===m||Cw(x.name)===m||x.cmd===g&&Pt.resolve(x.serveCwd??x.cwd)===u));if(y)return p4(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(m=>m.state==="live"||m.state==="starting").length>=fo)throw new Error(`view cap reached (${fo} live) \u2014 stop one first`);let w={id:WU().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:i4(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await c4(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await jw(w),p.views.push(w),await Hn(),await br(w,"created",{origin:i}),Mw(e,w.id),i==="detected"&&await Ic(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Hn(),await br(w,"live")),{...w}}async function p4(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 r4(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Ic(t.port))return await Hn(),Mw(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(d=>d.id!==t.id&&(d.state==="live"||d.state==="starting")).length>=fo)throw new Error(`view cap reached (${fo} live) \u2014 stop one first`);return t.origin==="detected"?(await Bw(t.port),t.origin="agent"):await $c(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),yr.delete(t.id),await jw(t),await Hn(),await br(t,"created",{restarted:!0,reused:!0}),Mw(t.trackId,t.id),{...t,reused:!0}}async function FE(e){let n=(await kr()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Bw(n.port):await $c(n.slug),n.state!=="stopped"&&(n.state="stopped",yr.delete(n.id),await Hn(),await br(n,"stopped")),{...n}}async function UE(e){let t=await kr(),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>=fo)throw new Error(`view cap reached (${fo} live) \u2014 stop one first`);return await $c(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),yr.delete(n.id),await jw(n),await Hn(),await br(n,"created",{restarted:!0}),{...n}}async function HE(e){let t=await kr(),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 Bw(r.port):await $c(r.slug),t.views.splice(n,1),yr.delete(r.id),await Hn(),await br(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function Hw(e){let t=await kr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await $c(r.slug),yr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Hn()),n.length}async function WE(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await kr(),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 Hn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(f4)){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(!jE().has(c)&&!n.views.some(l=>l.port===c)&&await Ic(c))try{i.push(await Uw({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 Un,GU,OE,_E,IE,fo,VU,Ea,$E,Tc,zU,Ow,JU,YU,XU,Nw,ME,Iw,e4,n4,NE,Fd,Fn,$w,Ec,Pw,PE,yr,u4,Rw,f4,Wd=W(()=>{ft();me();jr();Un=KU(qU),GU=process.env.BOSTRAT_STATE_DIR||Pt.join(process.env.HOME||UU.tmpdir(),".bostrat"),OE=Pt.join(GU,"views.json"),[_E,IE]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),fo=Number(process.env.BOSTRAT_VIEW_MAX)||3,VU="bostrat-view-",Ea=e=>`${VU}${e}`,$E=new Set(["bostrat","www","api","views","app"]),Tc=e=>Object.assign(new Error(e),{status:400}),zU=new Set(["npm","pnpm","yarn","bun"]),Ow="package.json",JU=/[|;&`]|\$\(/,YU=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),XU=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Nw=e=>String(e).trim().split(/\s+/).filter(Boolean),ME=/^[A-Za-z_][A-Za-z0-9_]*=/;Iw=e=>e==="/",e4=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");n4=e=>_c.stat(e).then(t=>t.isDirectory(),()=>!1),NE=e=>_c.stat(e).then(t=>t.isFile(),()=>!1),Fd=e=>_c.realpath(e).catch(()=>Pt.resolve(e));Fn=null,$w=null;Ec=new Map,Pw=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,PE=12e3;yr=new Map,u4=12e4;Rw=!1;f4=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function _a(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>qw?null:n}function h4(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function qd(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await q(e)}catch{return}let o=_a(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await is(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(Ww.get(e.id)||0)<m4)return;Ww.set(e.id,a);let i;try{i=await Bn(e.cwd,{caller:"reconcile"})}catch{return}let c=await ka(e).catch(()=>[n]),l=(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await Re(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Ut({repo:u,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!p&&!(d?.trackId===e.id&&await ur(u,l.number))){if(!h4(d,o))return;let f=await q(e).catch(()=>null);if(f&&_a(f)==null)return;await C(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 C(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(()=>{}),Ww.delete(e.id)}var m4,Ww,qw,Rc=W(()=>{me();as();Pr();Dn();fc();cs();m4=6e3,Ww=new Map,qw=30*6e4});import Kw from"node:os";import{execFile as w4}from"node:child_process";import{promisify as g4}from"node:util";async function Kd(){if(process.platform!=="darwin")return Kw.freemem();try{let{stdout:e}=await y4("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:Kw.freemem()}catch{return Kw.freemem()}}var y4,Gw=W(()=>{y4=g4(w4)});import Qe from"node:fs/promises";import nt from"node:path";import VE from"node:os";import{randomUUID as b4}from"node:crypto";import{execFile as k4}from"node:child_process";import{promisify as x4}from"node:util";import{chromium as v4}from"playwright-core";async function Kn(){return ds||(Vw||=(async()=>{try{ds=JSON.parse(await Qe.readFile(JE,"utf8"))}catch{ds={mocks:[]}}finally{Vw=null}return ds.mocks||=[],ds})(),Vw)}async function tn(){await Mt(JE,ds)}function QE(e,t){qn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&qn(e,t.v,"png")}function _t(e,t,n={}){return C({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 nn(e,t){let n=Mc(e.cwd);return{html:nt.join(n,`${e.id}.v${t}.html`),png:nt.join(n,`${e.id}.v${t}.png`)}}function Oc(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?nt.join(e.cwd,r):null}function gn(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 Yw(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Gd(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals($4)}function R4(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 O4(e){let t=Buffer.alloc(24),n=await Qe.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function M4({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 C4(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((w,m)=>{r.onload=w,r.onerror=()=>m(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,d=s,p=-1,f=-1;for(let w=0;w<s;w++)for(let m=w*o*4,g=0;g<o;g++,m+=4)Math.abs(c[m]-l[0])+Math.abs(c[m+1]-l[1])+Math.abs(c[m+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),w<d&&(d=w),f=w);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:f}}},t.toString("base64"))}async function N4(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((d,p)=>{c.onload=d,c.onerror=()=>p(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 P4({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await v4.launch({executablePath:YE,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Ht("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Ia})).newPage();a.setDefaultTimeout($a),await a.goto(`file://${e}`,{waitUntil:"load",timeout:$a}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:$a});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await C4(a,i),u=l&&M4({...l,pad:T4*Ia,align:Ia});u&&(i=await N4(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<XE)throw new Ht(`capture produced a ${i.length}-byte image`);let c=Yw(i);if(!c)throw new Ht("output is not a PNG");return await Qe.writeFile(t,i),{width:Math.round(c.width/Ia),height:Math.round(c.height/Ia),dpr:Ia,renderMs:Date.now()-r}}catch(s){throw s instanceof Ht?s:new Ht(/timeout/i.test(s?.message||"")?`render timed out after ${$a}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function GE({htmlPath:e,outPath:t,width:n}){let r=await Qe.mkdtemp(nt.join(VE.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Jw(qE,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:$a,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ht(`firefox not found (${qE})`,""):new Ht(c?.killed?`render timed out after ${$a}ms`:"firefox exited non-zero",s)}let a=await Qe.stat(t).catch(()=>null);if(!a||a.size<XE)throw new Ht(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Yw(await O4(t));if(!i)throw new Ht("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Qe.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function D4(e){if(S4==="firefox")return GE(e);try{return await P4(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await GE(e)}catch(n){throw/not found/.test(n?.message||"")?new Ht(`no browser installed \u2014 chromium missing at ${YE} 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 e_(e){return zw=zw.then(e,e),zw}async function t_(e,t){let n=await Kn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await tn(),await _t(r,"rendering",{version:t});try{let o=await Kd();if(o<E4)throw new Ht(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=nn(r,t),a=await B4({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Qe.rm(s.png,{force:!0}).catch(()=>{});return}Xw(r,{v:t,source:"html",htmlRel:nt.relative(r.cwd,s.html),pngRel:nt.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await tn(),await _t(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Wn(r),qn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await tn(),await _t(r,"error",{version:t,error:r.error}),Wn(r)}}}function Xw(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 j4({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?A4:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Cc({trackId:e,group:t}={}){let n=await Kn(),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 xr(e){let n=(await Kn()).mocks.find(r=>r.id===e);return n?{...n}:null}function n_({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&&!Gd(t))throw new Error("image must be a PNG");if(n){let o=R4(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>KE)throw new Error(`video must be ${KE/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function r_({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=j4({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=n_({html:n,image:r,video:o}),w=await Kn(),m={id:b4().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:d,height:null,dpr:null,state:"queued",source:p?"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 Qe.mkdir(Mc(s),{recursive:!0}),w.mocks.push(m),p?(await Qe.writeFile(nn(m,1).html,n),await tn(),await _t(m,"created"),Wn(m),qn(m,1,"html"),e_(()=>t_(m.id,1))):o?(await s_(m,1,o,f),await tn(),await _t(m,"created"),await _t(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr,durationS:m.versions[0]?.durationS??null}),Wn(m),QE(m,m.versions[0])):(await a_(m,1,r),await tn(),await _t(m,"created"),await _t(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr}),Wn(m),qn(m,1,"png")),{...m}}async function o_(e,{html:t,image:n,video:r,width:o}={}){let a=(await Kn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=n_({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 Qe.mkdir(Mc(a.cwd),{recursive:!0}),i?(a.state="queued",await Qe.writeFile(nn(a,l).html,t),await tn(),await _t(a,"updated",{version:l}),Wn(a),qn(a,l,"html"),e_(()=>t_(a.id,l))):r?(await s_(a,l,r,c),await tn(),await _t(a,"updated",{version:l}),await _t(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:gn(a)?.durationS??null}),Wn(a),QE(a,a.versions.find(u=>u.v===l))):(await a_(a,l,n),await tn(),await _t(a,"updated",{version:l}),await _t(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Wn(a),qn(a,l,"png")),{...a}}async function L4(e){try{let{stdout:t}=await Jw(_4,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:ZE,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 F4(e,t){try{await Jw(I4,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:ZE,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Qe.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function s_(e,t,n,r){let o=Mc(e.cwd),s=nt.join(o,`${e.id}.v${t}.${r.ext}`),a=nt.join(o,`${e.id}.v${t}.poster.png`);await Qe.writeFile(s,n);let i=await L4(s),c=await F4(s,a);Xw(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:nt.relative(e.cwd,s),posterRel:c?nt.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 a_(e,t,n){let r=Yw(n);if(!r)throw new Error("image must be a PNG");let o=nn(e,t);await Qe.writeFile(o.png,n),Xw(e,{v:t,source:"image",htmlRel:null,pngRel:nt.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function i_(e){let t=await Kn(),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 _t(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function c_(e){let t=await Kn(),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=nn(r,o);await Qe.rm(s.html,{force:!0}).catch(()=>{}),await Qe.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Qe.rm(nt.join(r.cwd,s),{force:!0}).catch(()=>{});return await tn(),await _t(r,"deleted"),an("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function l_(e){let n=(await Kn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=nt.join(zE,"mock-archive",e.id),o=Mc(e.cwd),s=nt.join(r,".bostrat","mocks");await Qe.mkdir(s,{recursive:!0});let a=await Qe.readdir(o).catch(()=>[]);for(let i of a)await Qe.copyFile(nt.join(o,i),nt.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 Qe.stat(nt.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(),Wn(i)}return await tn(),n.length}async function u_(e){let t=await Kn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await tn();for(let r of n)an("mocks",r.id).catch(()=>{})}return n.length}async function d_(){if(!qe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await lt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Kn();for(let r of n.mocks){await Wn(r);for(let o of r.versions||[])o.htmlRel&&await qn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await qn(r,o.v,"png"),o.videoRel&&await qn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Jw,zE,JE,S4,YE,qE,A4,Ia,T4,XE,$a,E4,KE,_4,I4,ZE,Ht,ds,Vw,Wn,qn,Mc,$4,B4,zw,Ra=W(()=>{me();jr();Gw();Fr();Jw=x4(k4),zE=process.env.BOSTRAT_STATE_DIR||nt.join(process.env.HOME||VE.tmpdir(),".bostrat"),JE=nt.join(zE,"mocks.json"),S4=process.env.BOSTRAT_MOCK_ENGINE||"chromium",YE=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",qE=process.env.BOSTRAT_FIREFOX_BIN||"firefox",A4=1300,Ia=2,T4=32,XE=1500,$a=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,E4=700*1024*1024,KE=100*1024*1024,_4=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",I4=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",ZE=2e4,Ht=class extends Error{constructor(t,n=""){super(n?`${t}
|
|
204
204
|
${n.trim().split(`
|
|
205
205
|
`).slice(-6).join(`
|
|
206
|
-
`)}`:t),this.name="MockRenderError"}},us=null,Ww=null;Wn=e=>At("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),qn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?$c(e,r,"video"):r&&$c(e,r,n)||(n==="html"?nn(e,t).html:null);return o?Br("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Rc=e=>ot.join(e,".bostrat","mocks");f4=Buffer.from([137,80,78,71,13,10,26,10]);x4=k4,qw=Promise.resolve()});import T4 from"node:fs/promises";import c_ from"node:path";import E4 from"node:os";import{randomUUID as l_}from"node:crypto";async function xr(){return kr||(zw||=(async()=>{let e=!0;try{kr=JSON.parse(await T4.readFile(u_,"utf8"))}catch{kr={flows:[]},e=!1}finally{zw=null}if(kr.flows||=[],!e&&Ke()){let{records:t,source:n}=await dt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&kr.flows.push(r.data);kr.flows.length&&await Ra().catch(()=>{})}}return kr})(),zw)}async function Ra(){await Ot(u_,kr)}function Jw(e,t,n={}){return C({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function d_({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>o_)throw new Error(`steps must be an array of 1-${o_}`);let r=await Oc({trackId:e}),o=[...n],s=[];for(let i=0;i<t.length;i++){let c=t[i]||{},l=`step ${i+1}`,u=typeof c.caption=="string"?c.caption.trim():"";if(!u)throw new Error(`${l}: caption (string) required`);if(u.length>a_)throw new Error(`${l}: caption over ${a_} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>i_)throw new Error(`${l}: title over ${i_} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(k=>k.id===p);if(f.length||(f=r.filter(k=>k.name.toLowerCase()===p.toLowerCase())),!f.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(f.length>1)throw new Error(`${l}: "${p}" is ambiguous (${f.map(k=>`mock:${k.id}`).join(", ")}) \u2014 use the id`);let w=f[0],h=null;if(c.v!=null&&(h=Number(c.v),!Number.isInteger(h)||!(w.versions||[]).some(k=>k.v===h)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let g=o.findIndex(k=>k.mockId===w.id),y=g>=0?o.splice(g,1)[0].id:l_().slice(0,8);s.push({id:y,mockId:w.id,caption:u,title:d,v:h})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function I4(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>s_)throw new Error(`name over ${s_} chars`);return e.trim()}async function p_({trackId:e}={}){let t=await xr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function $4(e){let n=(await xr()).flows.find(r=>r.id===e);return n?{...n}:null}async function f_(e){let t=await $4(e);if(!t)return null;let n=new Map((await Oc({trackId:t.trackId})).map(r=>[r.id,r]));return t.steps=t.steps.map(r=>{let o=n.get(r.mockId);if(!o)return{...r,missing:!0,mockName:null,mockState:null,servedV:null,width:null,height:null};let s=gn(o,r.v);return{...r,missing:!1,mockName:o.name,mockState:o.state,servedV:s?.v??null,width:s?.width??null,height:s?.height??null}}),t}async function h_({trackId:e,name:t,steps:n,cwd:r,box:o,agent:s}){if(!e)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=I4(t),i=await xr(),c=i.flows.find(f=>f.trackId===e&&f.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await d_({trackId:e,steps:n}),d=Date.now(),p={id:l_().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:d}],steps:l,createdAt:d,updatedAt:d};return i.flows.push(p),await Ra(),await Jw(p,"created"),qd(p),{...p}}async function m_(e,{steps:t,note:n}={}){let o=(await xr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await d_({trackId:o.trackId,steps:t,prevSteps:o.steps});return o.version+=1,o.versions.push({v:o.version,steps:s,resolved:a,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),o.steps=s,o.updatedAt=Date.now(),await Ra(),await Jw(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),qd(o),{...o}}async function w_(e){let t=await xr(),n=t.flows.findIndex(o=>o.id===e);if(n===-1)throw new Error("flow not found");let r=t.flows[n];return t.flows.splice(n,1),await Ra(),await Jw(r,"deleted"),an("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function g_(e){return(await xr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function y_(e){let n=(await xr()).flows.filter(r=>r.trackId===e.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=e.name||e.id,r.updatedAt=Date.now(),qd(r);return n.length&&await Ra(),n.length}async function b_(e){let t=await xr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await Ra();for(let r of n)an("flows",r.id).catch(()=>{})}return n.length}async function k_(){if(!Ke())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await dt("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await xr();for(let r of n.flows)await qd(r);return{pushed:n.flows.length,source:"plane"}}var _4,u_,o_,s_,a_,i_,kr,zw,qd,Yw=W(()=>{fe();Dr();$a();jr();_4=process.env.BOSTRAT_STATE_DIR||c_.join(process.env.HOME||E4.tmpdir(),".bostrat"),u_=c_.join(_4,"flows.json"),o_=20,s_=80,a_=500,i_=80,kr=null,zw=null;qd=e=>At("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import Ar from"node:fs/promises";import Tr from"node:path";import R4 from"node:os";import{randomUUID as O4}from"node:crypto";function Mc(e){return M4.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Gn(){return vr||(Xw||=(async()=>{let e=!0;try{vr=JSON.parse(await Ar.readFile(v_,"utf8"))}catch{vr={runbooks:[]},e=!1}finally{Xw=null}return vr.runbooks||=[],!e&&Ke()&&await C4().catch(()=>{}),vr})(),Xw)}async function ps(){await Ot(v_,vr)}function Gd(e){return Cc(At("runbooks",{...e},{trackId:e.trackId}))}async function C4(){let{records:e,source:t}=await dt("runbooks");if(!(t!=="plane"||!e.length)){await Ar.mkdir(Kd,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await Si("runbooks",r.id,o.v,"md");typeof s=="string"&&await Ar.writeFile(Sr(r,o.v),s).catch(()=>{})}vr.runbooks.push(r)}vr.runbooks.length&&await ps()}}function Oa(e,t,n={}){return C({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function Sr(e,t){return Tr.join(Kd,`${e.id}.v${t}.md`)}function S_(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 A_(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>x_)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${x_/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Mc(e);if(n.length)throw new Error(`runbook appears to contain a secret VALUE (${n.join(", ")}) \u2014 runbooks ship off-box; name the secret and where it goes, never its value. Replace it with a placeholder like <your key> and retry.`);return t}function N4(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function P4({trackId:e,status:t}={}){let n=await Gn(),r=e?n.runbooks.filter(o=>o.trackId===e):n.runbooks;return t&&(r=r.filter(o=>o.status===t)),r.map(o=>({...o}))}async function T_({trackId:e,status:t}={}){let n=await Gn(),r=await P4({trackId:e,status:t});if(!Ke())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await dt("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function Zw(e){let t=await D4(e);if(t)return t;if(!Ke())return null;let{records:n,source:r}=await dt("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function E_(e,t){let n=await Si("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function D4(e){let n=(await Gn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function __({trackId:e,trackName:t,name:n,md:r,cwd:o,box:s,agent:a}){if(!e)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=A_(r),c=await Gn(),l={id:O4().slice(0,8),trackId:e,trackName:t||e,box:s||null,agent:a||null,name:n.trim(),status:"open",version:1,versions:[],trackDeletedAt:null,cwd:o||null,createdAt:Date.now(),updatedAt:Date.now()};return await Ar.mkdir(Kd,{recursive:!0}),await Ar.writeFile(Sr(l,1),r),l.versions.push({v:1,mdRel:Tr.relative(ds,Sr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await ps(),await Oa(l,"created",{version:1}),Gd(l),Cc(Br("runbooks",l.id,1,"md",Sr(l,1))),{...l}}async function I_(e,{md:t,note:n}={}){let o=(await Gn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");N4(o,"update");let s=A_(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await Ar.mkdir(Kd,{recursive:!0}),await Ar.writeFile(Sr(o,a),t),o.versions.push({v:a,mdRel:Tr.relative(ds,Sr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await ps(),await Oa(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Gd(o),Cc(Br("runbooks",o.id,a,"md",Sr(o,a))),{...o}}async function $_(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Gn()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await ps(),await Oa(r,t==="done"?"done":"reopened"),Gd(r),{...r})}async function R_(e){let t=await Gn(),n=t.runbooks.findIndex(o=>o.id===e);if(n===-1)throw new Error("runbook not found");let r=t.runbooks[n];t.runbooks.splice(n,1);for(let o of r.versions||[])await Ar.rm(Tr.join(ds,o.mdRel),{force:!0}).catch(()=>{});return await ps(),r.trackDeletedAt||await Oa(r,"deleted"),Cc(an("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function O_(e){let n=(await Gn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Oa(r,"orphaned"),r.cwd=null,Gd(r);return n.length&&await ps(),n.length}async function M_(e){let t=await Gn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Oa(r,"deleted");for(let o of r.versions||[])await Ar.rm(Tr.join(ds,o.mdRel),{force:!0}).catch(()=>{});Cc(an("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await ps()),n.length}async function C_(){if(!Ke())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await dt("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Gn();for(let r of n.runbooks){await At("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Br("runbooks",r.id,o.v,"md",Tr.join(ds,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var ds,v_,Kd,x_,M4,vr,Xw,Cc,Vd=W(()=>{Dr();fe();jr();ds=process.env.BOSTRAT_STATE_DIR||Tr.join(process.env.HOME||R4.tmpdir(),".bostrat"),v_=Tr.join(ds,"runbooks.json"),Kd=Tr.join(ds,"runbooks"),x_=256*1024,M4=[{label:"Anthropic API key",re:/\bsk-ant-[A-Za-z0-9_-]{20,}/},{label:"OpenAI-style API key",re:/\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{32,}\b/},{label:"Stripe secret key",re:/\bsk_(?:live|test)_[A-Za-z0-9]{16,}/},{label:"GitHub token",re:/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}|\bgithub_pat_[A-Za-z0-9_]{22,}/},{label:"AWS access key id",re:/\bAKIA[0-9A-Z]{16}\b/},{label:"Slack token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}/},{label:"private key block",re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/},{label:"JWT",re:/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/}];vr=null,Xw=null;Cc=e=>Promise.resolve(e).catch(()=>{})});import Qw from"node:fs/promises";import Nc from"node:path";import{randomUUID as B4}from"node:crypto";function tg(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return j4.has(t)?"image":L4.has(t)?"doc":null}function F4(e){let r=Nc.basename(String(e||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function D_(e,{filename:t,buffer:n}){if(!e)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>N_)throw new Error(`file too large \u2014 max ${Math.floor(N_/(1024*1024))} MB`);let r=F4(t),o=Nc.extname(r).slice(1),s=tg(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=B4().slice(0,8),i=eg(e);await Qw.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Qw.writeFile(Nc.join(i,c),n,{mode:384}),await Qw.chmod(Nc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${P_}/${c}`,kind:s,size:n.length}}function B_(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function ng(e){return e.role==="user"&&U4.test((e.text||"").trim())}var P_,eg,N_,j4,L4,U4,rg=W(()=>{P_=".bostrat/uploads",eg=e=>Nc.join(e,P_),N_=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,j4=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),L4=new Set(["pdf","doc","docx","xls","xlsx","ppt","pptx","odt","ods","odp","rtf","txt","md","markdown","rst","csv","tsv","json","jsonl","yaml","yml","xml","html","htm","log","ini","toml","conf","env","js","jsx","ts","tsx","py","rb","go","rs","java","kt","c","h","cpp","cc","cs","php","swift","sh","bash","zsh","sql","css","scss"]);U4=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function fs(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}function og(){let e=Number(process.env.BOSTRAT_LOOP_QUEUE_HOLD_MS);return Number.isFinite(e)&&e>0?e:H4}function q4(e,t,n=Date.now()){return e?((e.heldReason!==t||e.heldSince==null)&&(e.heldReason=t,e.heldSince=n),Math.max(0,n-e.heldSince)):0}function j_(e,t,{capMs:n=og(),now:r=Date.now()}={}){if(!e)return!1;let o=q4(e,t,r);return e.delivery?.producer!=="loop"||!W4.has(t)?!1:o>=n}var H4,W4,L_=W(()=>{H4=5*6e4,W4=new Set(["busy","noSession"])});import{execFile as K4}from"node:child_process";import{promisify as G4}from"node:util";function sg(e){return`refs/bostrat/wip/${e}`}function J4(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function H_(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function Y4(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:z4}function W_(e){let t=e?.workspace;return t?.kind==="multi"?(Array.isArray(t.repos)?t.repos:[]).filter(n=>n?.dir).map(n=>({dir:n.dir,name:n.name??null,repo:n.repo??null})):e?.cwd?[{dir:e.cwd,name:null,repo:t?.repo??null}]:[]}async function X4(e,{log:t=console,force:n=!1,checkout:r=null}={}){let o=e?.id,s=r?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=r?.name?`${o}/${r.name}`:o;try{await po(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await po(s,["remote","get-url","origin"])}catch{return F_.has(s)||(F_.add(s),t.log?.(`[wip-sync] ${a}: no origin remote \u2014 durable code fidelity is chat/memory-only for this checkout`)),{pushed:!1,reason:"no-origin"}}try{let i=await ua(s,"bostrat: wip snapshot"),{stdout:c}=await po(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&zd.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=sg(o);return await po(s,["push","--force","origin",`${i}:${u}`],U_),zd.set(s,l),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...q_(r),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: pushed ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: push failed (will retry): ${String(i?.message||i).split(`
|
|
207
|
-
`)[0]}`),{pushed:!1,reason:"push-failed"}}}async function
|
|
208
|
-
`)[0]}`),{pushed:!1,reason:"push-failed"}}}async function
|
|
206
|
+
`)}`:t),this.name="MockRenderError"}},ds=null,Vw=null;Wn=e=>Tt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),qn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Oc(e,r,"video"):r&&Oc(e,r,n)||(n==="html"?nn(e,t).html:null);return o?Lr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Mc=e=>nt.join(e,".bostrat","mocks");$4=Buffer.from([137,80,78,71,13,10,26,10]);B4=D4,zw=Promise.resolve()});import U4 from"node:fs/promises";import w_ from"node:path";import H4 from"node:os";import{randomUUID as g_}from"node:crypto";async function Sr(){return vr||(Zw||=(async()=>{let e=!0;try{vr=JSON.parse(await U4.readFile(y_,"utf8"))}catch{vr={flows:[]},e=!1}finally{Zw=null}if(vr.flows||=[],!e&&qe()){let{records:t,source:n}=await lt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&vr.flows.push(r.data);vr.flows.length&&await Oa().catch(()=>{})}}return vr})(),Zw)}async function Oa(){await Mt(y_,vr)}function Qw(e,t,n={}){return C({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function b_({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>p_)throw new Error(`steps must be an array of 1-${p_}`);let r=await Cc({trackId:e}),o=[...n],s=[];for(let i=0;i<t.length;i++){let c=t[i]||{},l=`step ${i+1}`,u=typeof c.caption=="string"?c.caption.trim():"";if(!u)throw new Error(`${l}: caption (string) required`);if(u.length>m_)throw new Error(`${l}: caption over ${m_} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>h_)throw new Error(`${l}: title over ${h_} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(x=>x.id===p);if(f.length||(f=r.filter(x=>x.name.toLowerCase()===p.toLowerCase())),!f.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(f.length>1)throw new Error(`${l}: "${p}" is ambiguous (${f.map(x=>`mock:${x.id}`).join(", ")}) \u2014 use the id`);let w=f[0],m=null;if(c.v!=null&&(m=Number(c.v),!Number.isInteger(m)||!(w.versions||[]).some(x=>x.v===m)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let g=o.findIndex(x=>x.mockId===w.id),y=g>=0?o.splice(g,1)[0].id:g_().slice(0,8);s.push({id:y,mockId:w.id,caption:u,title:d,v:m})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function q4(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>f_)throw new Error(`name over ${f_} chars`);return e.trim()}async function k_({trackId:e}={}){let t=await Sr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function K4(e){let n=(await Sr()).flows.find(r=>r.id===e);return n?{...n}:null}async function x_(e){let t=await K4(e);if(!t)return null;let n=new Map((await Cc({trackId:t.trackId})).map(r=>[r.id,r]));return t.steps=t.steps.map(r=>{let o=n.get(r.mockId);if(!o)return{...r,missing:!0,mockName:null,mockState:null,servedV:null,width:null,height:null};let s=gn(o,r.v);return{...r,missing:!1,mockName:o.name,mockState:o.state,servedV:s?.v??null,width:s?.width??null,height:s?.height??null}}),t}async function v_({trackId:e,name:t,steps:n,cwd:r,box:o,agent:s}){if(!e)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=q4(t),i=await Sr(),c=i.flows.find(f=>f.trackId===e&&f.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await b_({trackId:e,steps:n}),d=Date.now(),p={id:g_().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:d}],steps:l,createdAt:d,updatedAt:d};return i.flows.push(p),await Oa(),await Qw(p,"created"),Vd(p),{...p}}async function S_(e,{steps:t,note:n}={}){let o=(await Sr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await b_({trackId:o.trackId,steps:t,prevSteps:o.steps});return o.version+=1,o.versions.push({v:o.version,steps:s,resolved:a,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),o.steps=s,o.updatedAt=Date.now(),await Oa(),await Qw(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Vd(o),{...o}}async function A_(e){let t=await Sr(),n=t.flows.findIndex(o=>o.id===e);if(n===-1)throw new Error("flow not found");let r=t.flows[n];return t.flows.splice(n,1),await Oa(),await Qw(r,"deleted"),an("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function T_(e){return(await Sr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function E_(e){let n=(await Sr()).flows.filter(r=>r.trackId===e.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=e.name||e.id,r.updatedAt=Date.now(),Vd(r);return n.length&&await Oa(),n.length}async function __(e){let t=await Sr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await Oa();for(let r of n)an("flows",r.id).catch(()=>{})}return n.length}async function I_(){if(!qe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await lt("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Sr();for(let r of n.flows)await Vd(r);return{pushed:n.flows.length,source:"plane"}}var W4,y_,p_,f_,m_,h_,vr,Zw,Vd,eg=W(()=>{me();jr();Ra();Fr();W4=process.env.BOSTRAT_STATE_DIR||w_.join(process.env.HOME||H4.tmpdir(),".bostrat"),y_=w_.join(W4,"flows.json"),p_=20,f_=80,m_=500,h_=80,vr=null,Zw=null;Vd=e=>Tt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import Er from"node:fs/promises";import _r from"node:path";import G4 from"node:os";import{randomUUID as V4}from"node:crypto";function Nc(e){return z4.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Gn(){return Ar||(tg||=(async()=>{let e=!0;try{Ar=JSON.parse(await Er.readFile(R_,"utf8"))}catch{Ar={runbooks:[]},e=!1}finally{tg=null}return Ar.runbooks||=[],!e&&qe()&&await J4().catch(()=>{}),Ar})(),tg)}async function fs(){await Mt(R_,Ar)}function Jd(e){return Pc(Tt("runbooks",{...e},{trackId:e.trackId}))}async function J4(){let{records:e,source:t}=await lt("runbooks");if(!(t!=="plane"||!e.length)){await Er.mkdir(zd,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await Ti("runbooks",r.id,o.v,"md");typeof s=="string"&&await Er.writeFile(Tr(r,o.v),s).catch(()=>{})}Ar.runbooks.push(r)}Ar.runbooks.length&&await fs()}}function Ma(e,t,n={}){return C({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function Tr(e,t){return _r.join(zd,`${e.id}.v${t}.md`)}function O_(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 M_(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>$_)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${$_/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Nc(e);if(n.length)throw new Error(`runbook appears to contain a secret VALUE (${n.join(", ")}) \u2014 runbooks ship off-box; name the secret and where it goes, never its value. Replace it with a placeholder like <your key> and retry.`);return t}function Y4(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function X4({trackId:e,status:t}={}){let n=await Gn(),r=e?n.runbooks.filter(o=>o.trackId===e):n.runbooks;return t&&(r=r.filter(o=>o.status===t)),r.map(o=>({...o}))}async function C_({trackId:e,status:t}={}){let n=await Gn(),r=await X4({trackId:e,status:t});if(!qe())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await lt("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function ng(e){let t=await Z4(e);if(t)return t;if(!qe())return null;let{records:n,source:r}=await lt("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function N_(e,t){let n=await Ti("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function Z4(e){let n=(await Gn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function P_({trackId:e,trackName:t,name:n,md:r,cwd:o,box:s,agent:a}){if(!e)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=M_(r),c=await Gn(),l={id:V4().slice(0,8),trackId:e,trackName:t||e,box:s||null,agent:a||null,name:n.trim(),status:"open",version:1,versions:[],trackDeletedAt:null,cwd:o||null,createdAt:Date.now(),updatedAt:Date.now()};return await Er.mkdir(zd,{recursive:!0}),await Er.writeFile(Tr(l,1),r),l.versions.push({v:1,mdRel:_r.relative(ps,Tr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await fs(),await Ma(l,"created",{version:1}),Jd(l),Pc(Lr("runbooks",l.id,1,"md",Tr(l,1))),{...l}}async function D_(e,{md:t,note:n}={}){let o=(await Gn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");Y4(o,"update");let s=M_(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await Er.mkdir(zd,{recursive:!0}),await Er.writeFile(Tr(o,a),t),o.versions.push({v:a,mdRel:_r.relative(ps,Tr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await fs(),await Ma(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Jd(o),Pc(Lr("runbooks",o.id,a,"md",Tr(o,a))),{...o}}async function B_(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Gn()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await fs(),await Ma(r,t==="done"?"done":"reopened"),Jd(r),{...r})}async function j_(e){let t=await Gn(),n=t.runbooks.findIndex(o=>o.id===e);if(n===-1)throw new Error("runbook not found");let r=t.runbooks[n];t.runbooks.splice(n,1);for(let o of r.versions||[])await Er.rm(_r.join(ps,o.mdRel),{force:!0}).catch(()=>{});return await fs(),r.trackDeletedAt||await Ma(r,"deleted"),Pc(an("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function L_(e){let n=(await Gn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Ma(r,"orphaned"),r.cwd=null,Jd(r);return n.length&&await fs(),n.length}async function F_(e){let t=await Gn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Ma(r,"deleted");for(let o of r.versions||[])await Er.rm(_r.join(ps,o.mdRel),{force:!0}).catch(()=>{});Pc(an("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await fs()),n.length}async function U_(){if(!qe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await lt("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Gn();for(let r of n.runbooks){await Tt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Lr("runbooks",r.id,o.v,"md",_r.join(ps,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var ps,R_,zd,$_,z4,Ar,tg,Pc,Yd=W(()=>{jr();me();Fr();ps=process.env.BOSTRAT_STATE_DIR||_r.join(process.env.HOME||G4.tmpdir(),".bostrat"),R_=_r.join(ps,"runbooks.json"),zd=_r.join(ps,"runbooks"),$_=256*1024,z4=[{label:"Anthropic API key",re:/\bsk-ant-[A-Za-z0-9_-]{20,}/},{label:"OpenAI-style API key",re:/\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{32,}\b/},{label:"Stripe secret key",re:/\bsk_(?:live|test)_[A-Za-z0-9]{16,}/},{label:"GitHub token",re:/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}|\bgithub_pat_[A-Za-z0-9_]{22,}/},{label:"AWS access key id",re:/\bAKIA[0-9A-Z]{16}\b/},{label:"Slack token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}/},{label:"private key block",re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/},{label:"JWT",re:/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/}];Ar=null,tg=null;Pc=e=>Promise.resolve(e).catch(()=>{})});import rg from"node:fs/promises";import Dc from"node:path";import{randomUUID as Q4}from"node:crypto";function sg(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return e2.has(t)?"image":t2.has(t)?"doc":null}function n2(e){let r=Dc.basename(String(e||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function q_(e,{filename:t,buffer:n}){if(!e)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>H_)throw new Error(`file too large \u2014 max ${Math.floor(H_/(1024*1024))} MB`);let r=n2(t),o=Dc.extname(r).slice(1),s=sg(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=Q4().slice(0,8),i=og(e);await rg.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await rg.writeFile(Dc.join(i,c),n,{mode:384}),await rg.chmod(Dc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${W_}/${c}`,kind:s,size:n.length}}function K_(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function ag(e){return e.role==="user"&&r2.test((e.text||"").trim())}var W_,og,H_,e2,t2,r2,ig=W(()=>{W_=".bostrat/uploads",og=e=>Dc.join(e,W_),H_=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,e2=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),t2=new Set(["pdf","doc","docx","xls","xlsx","ppt","pptx","odt","ods","odp","rtf","txt","md","markdown","rst","csv","tsv","json","jsonl","yaml","yml","xml","html","htm","log","ini","toml","conf","env","js","jsx","ts","tsx","py","rb","go","rs","java","kt","c","h","cpp","cc","cs","php","swift","sh","bash","zsh","sql","css","scss"]);r2=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function ms(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}function cg(){let e=Number(process.env.BOSTRAT_LOOP_QUEUE_HOLD_MS);return Number.isFinite(e)&&e>0?e:o2}function a2(e,t,n=Date.now()){return e?((e.heldReason!==t||e.heldSince==null)&&(e.heldReason=t,e.heldSince=n),Math.max(0,n-e.heldSince)):0}function G_(e,t,{capMs:n=cg(),now:r=Date.now()}={}){if(!e)return!1;let o=a2(e,t,r);return e.delivery?.producer!=="loop"||!s2.has(t)?!1:o>=n}var o2,s2,V_=W(()=>{o2=5*6e4,s2=new Set(["busy","noSession"])});import{execFile as i2}from"node:child_process";import{promisify as c2}from"node:util";function lg(e){return`refs/bostrat/wip/${e}`}function d2(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function Y_(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function p2(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:u2}function X_(e){let t=e?.workspace;return t?.kind==="multi"?(Array.isArray(t.repos)?t.repos:[]).filter(n=>n?.dir).map(n=>({dir:n.dir,name:n.name??null,repo:n.repo??null})):e?.cwd?[{dir:e.cwd,name:null,repo:t?.repo??null}]:[]}async function f2(e,{log:t=console,force:n=!1,checkout:r=null}={}){let o=e?.id,s=r?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=r?.name?`${o}/${r.name}`:o;try{await mo(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await mo(s,["remote","get-url","origin"])}catch{return z_.has(s)||(z_.add(s),t.log?.(`[wip-sync] ${a}: no origin remote \u2014 durable code fidelity is chat/memory-only for this checkout`)),{pushed:!1,reason:"no-origin"}}try{let i=await da(s,"bostrat: wip snapshot"),{stdout:c}=await mo(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&Xd.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=lg(o);return await mo(s,["push","--force","origin",`${i}:${u}`],J_),Xd.set(s,l),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...Z_(r),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: pushed ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: push failed (will retry): ${String(i?.message||i).split(`
|
|
207
|
+
`)[0]}`),{pushed:!1,reason:"push-failed"}}}async function ug(e,{log:t=console,force:n=!1}={}){let r=[],o=[];for(let s of X_(e)){let a=await f2(e,{log:t,force:n,checkout:s});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}async function m2(e,{log:t=console,checkout:n=null,ts:r=Date.now()}={}){let o=e?.id,s=n?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=n?.name?`${o}/${n.name}`:o;try{await mo(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await mo(s,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let i=await da(s,"bostrat: transfer rescue snapshot"),{stdout:c}=await mo(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(Xd.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=d2(o,r);return await mo(s,["push","origin",`${i}:${u}`],J_),Xd.set(s,l),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,rescue:!0,...Z_(n),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: rescued stranded work ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: rescue push failed: ${String(i?.message||i).split(`
|
|
208
|
+
`)[0]}`),{pushed:!1,reason:"push-failed"}}}async function dg(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of X_(e)){let a=await m2(e,{log:t,checkout:s,ts:n});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}function Q_({listTracks:e,sweepMs:t=p2(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Le(i)||i?.kind==="setup"||await ug(i,{log:n})}catch(a){n.log?.(`[wip-sync] sweep failed: ${a?.message||a}`)}finally{r=!1}}},s=setInterval(o,t);return s.unref?.(),o(),{stop:()=>clearInterval(s),cycle:o}}var l2,u2,J_,mo,Xd,z_,Z_,pg=W(()=>{Yu();me();Zt();l2=c2(i2),u2=12e4,J_=6e4;mo=(e,t,n=15e3)=>l2("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Xd=new Map,z_=new Set,Z_=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import h2 from"node:fs";import fg from"node:fs/promises";import w2 from"node:path";function k2(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}async function eI(e,{env:t=process.env,fetchImpl:n=(...o)=>fetch(...o),log:r=console}={}){let o=e?.id;if(!o)return{restored:!1,reason:"no track id"};if(!k2(t))return{restored:!1,reason:"plane not configured"};let s=Fs(e),a=w2.join(s,`${o}.ndjson`);try{if(h2.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Ne(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),b2),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${g2}`,{headers:c,signal:p.signal})}finally{clearTimeout(f)}if(w.status===404)return{restored:!1,reason:"unknown to plane"};if(!w.ok)return{restored:!1,reason:`plane ${w.status}`};let m=await w.json();for(let g of m.events||[])l.push(JSON.stringify(g));if(l.length>y2)return{restored:!1,reason:"event count over safety cap"};if(m.next==null)break;u=m.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await fg.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await fg.writeFile(d,l.join(`
|
|
209
209
|
`)+`
|
|
210
|
-
`),await
|
|
210
|
+
`),await fg.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var g2,y2,b2,tI=W(()=>{gt();me();g2=1e3,y2=5e5,b2=3e4});function nI(e,t=Date.now()){let n=e.find(s=>s.reconcile||s.ciFix);if(n?.reconcile)return{status:"working",since:n.reconcile.delegatedAt,summary:"reconciling the branch"};if(n?.ciFix)return{status:"working",since:n.ciFix.delegatedAt,summary:"repairing failed checks"};let r=e.find(s=>s.reconcileAwait||s.ciFixAwait);if(r?.reconcileAwait)return{status:"waiting",since:r.reconcileAwait.since,summary:"fix pushed \u2014 waiting for mergeability"};if(r?.ciFixAwait)return{status:"waiting",since:r.ciFixAwait.since,summary:"fix pushed \u2014 waiting for CI"};let o=e.filter(s=>s.autoMerge||s.armedAt);return o.length?{status:"waiting",since:Math.min(...o.map(s=>s.autoMerge?.armedAt||s.armedAt||t)),count:o.length,summary:o.length===1?"auto-merge armed \u2014 lands when checks pass":`auto-merge armed on ${o.length} PRs`}:null}function rI(e){let t=(e||[]).filter(n=>!x2.has(n.state)&&!n.ciFix&&!n.reconcile&&!n.ciFixAwait&&!n.reconcileAwait&&!n.autoMerge&&!n.armedAt);return t.length?{count:t.length,since:Math.min(...t.map(n=>n.announcedAt||n.firstSeen||Date.now())),summary:t.length===1?`PR #${t[0].number} is open \u2014 review, merge or arm it`:`${t.length} open PRs waiting on you`}:null}function oI({archivedAt:e=null,archiving:t=!1,prompted:n=!1,openActions:r=0,openActionSince:o=null,loopAttention:s=!1,prDecisions:a=null,operation:i=null,phase:c=null,working:l=!1,workingSince:u=null,pending:d=null,completedTurnAt:p=null,live:f=!1,now:w=Date.now()}={}){return e&&!t?yn("archived","lifecycle",e):n||r>0||s?yn("needs-you",n?"pane":s?"loop":"obligations",o||w,{count:r||(n||s?1:null)}):t?yn("archiving","lifecycle",e||w):a?.count?yn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="working"?yn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?yn("working","agent-phase",c.at,{summary:c.summary??null}):l?yn("working","pane",u||w):i?.status==="waiting"?yn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?yn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?yn("settled","obligations",p,{summary:"no open actions"}):yn("idle","fallback",p||w)}var yn,x2,sI=W(()=>{yn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});x2=new Set(["merged","closed","lost"])});function v2(e,t){let n=0;for(let o of e||[]){if(o?.type!=="track.obligations.changed")continue;let s=Number(o.payload?.open);n=Number.isFinite(s)&&s>0?Math.floor(s):0}let r=Number(t?.openActions)||0;return r===n?null:{open:r,since:r?t.openActionSince??null:null}}async function S2(e,t,n){let r=v2(t,n);return r?C(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}async function mg(e){if(Zd.has(e.id))return Zd.get(e.id);let t=await q(e).catch(()=>[]),n=[];try{n=Mn(t)}catch{}let r=Cu(n),o=n.filter(f=>f?.kind==="followup-offer"&&f.status==="open"),s=new Set(t.filter(f=>f.type==="prompt.answered").map(f=>f.payload?.promptId)),a=t.filter(f=>f.type==="prompt.raised"&&f.payload?.promptId&&!s.has(f.payload.promptId)),i=[...r,...o,...a.map(f=>({ts:f.payload?.ts??f.ts}))],c=null;for(let f of t){if(f.type!=="track.phase.changed")continue;let w=f.payload||{};c=w.phase?{phase:w.phase,summary:w.summary??null,scope:w.scope??null,phaseId:w.phaseId??null,at:w.ts??f.ts}:null}let l=n.flatMap(f=>f?.kind==="job-dock"?f.jobs||[]:[]).filter(f=>f?.status==="running"),u=t.reduce((f,w)=>w.type==="turn.agent"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,d=t.reduce((f,w)=>w.type==="turn.user"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,p={openActions:i.length,openActionSince:i.length?Math.min(...i.map(f=>f.ts||Date.now())):null,phase:c,completedTurnAt:u,currentTurnAt:d,runningJobs:l.length,runningJobsSince:l.length?Math.min(...l.map(f=>f.startedTs||Date.now())):null};return Zd.set(e.id,p),!Le(e)&&e.kind!=="setup"&&S2(e,t,p),p}function aI({trackOf:e,debounceMs:t=A2,log:n=console}={}){if(typeof e!="function")throw new Error("watchObligations: trackOf(id) is required");let r=o=>{let s=o?.trackId;if(!s)return;clearTimeout(Bc.get(s));let a=setTimeout(()=>{Bc.delete(s),Promise.resolve(e(s)).then(i=>i&&!Le(i)&&i.kind!=="setup"?mg(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),Bc.set(s,a)};return Je.on("event",r),()=>{Je.off("event",r);for(let o of Bc.values())clearTimeout(o);Bc.clear()}}var Zd,A2,Bc,hg=W(()=>{me();Nu();Zt();Zd=new Map;Je.on("event",e=>{e?.trackId&&Zd.delete(e.trackId)});A2=750,Bc=new Map});import{randomUUID as T2}from"node:crypto";async function ep(e,t,n={}){let r={operationId:T2(),kind:t,startedAt:Date.now(),...n};return Qd.set(e.id,r),await C(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function wg(e,t,n="completed",r=null){Qd.get(e.id)?.operationId===t?.operationId&&Qd.delete(e.id),await C(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:Date.now(),state:"finished",operationId:t?.operationId,kind:t?.kind,outcome:n,...r?{error:String(r)}:{}}}).catch(()=>{})}var Qd,iI,gg=W(()=>{me();Qd=new Map;iI=e=>Qd.get(e)||null});var FI={};Tf(FI,{HANDOFF_LATEST_REL:()=>go,KNOWN_AGENTS:()=>Jc,TRACK_NAME_MAX:()=>$g,addTrackRepo:()=>wp,adoptTrack:()=>dy,agentAvailability:()=>dp,announceNodeUpdate:()=>zn,answerFullscreenOffer:()=>oy,answerPrompt:()=>fp,archiveTrack:()=>ys,archiveTrackForMergedPr:()=>hr,augmentFirstPromptAfterHandoff:()=>gI,buildAgentCmd:()=>Rg,canResumeSubtask:()=>BI,cancelQueued:()=>Xc,cancelQueuedToDraft:()=>jg,cancelStopJob:()=>Ua,cancelSubtask:()=>_p,changedRepos:()=>us,commitTransferOut:()=>Ap,createSetupTrack:()=>Yg,createTrack:()=>yp,deleteTrack:()=>Zg,demoteTransferredTracks:()=>uy,ensureLeadEpochs:()=>wo,forceMergeSubtask:()=>my,getHandoffJob:()=>Wa,getReshapeJob:()=>Zc,getSubtaskJob:()=>jH,getTrack:()=>ue,getTransferOutJob:()=>cy,healDeadLead:()=>Vc,interruptLead:()=>hp,isArchiving:()=>AH,isHandoffNoteEcho:()=>Ag,isInterruptEcho:()=>Tg,isModelSwitchEcho:()=>Eg,leadCliDead:()=>ey,listSubtaskJobs:()=>ks,listTracks:()=>ye,matchTranscriptsToBoxes:()=>xI,mergeNotifyMessage:()=>CI,navigatePrompt:()=>Dg,notifyTrackForMergedPr:()=>wr,notifyTrackForResolvedPr:()=>bp,offerFollowupsForMergedPr:()=>bs,pendingOffers:()=>Ng,queueGauges:()=>Bg,queueShipCompleteNotify:()=>Fg,queuedMessages:()=>hs,rawTrack:()=>Cg,reapArchivedOrphans:()=>ry,reconcileDemotedTracks:()=>ny,reconcileHandoffOutcome:()=>NI,reconcileInterruptedHandoffs:()=>ay,reconcileInterruptedReshapes:()=>zg,reconcileInterruptedSubtasks:()=>py,reconcileNodeUpdateNotices:()=>Mg,reconcileSubtaskOutcome:()=>DI,refreshStandingInstructions:()=>Jg,refuseIfTransferred:()=>Sp,rehydrateLead:()=>Qc,removeTrackRepo:()=>gp,renameTrack:()=>ty,reposOf:()=>jt,reshapeTrack:()=>Vg,resolveTrackBox:()=>kc,resolveTrackBoxByHookToken:()=>Yc,restartLead:()=>xp,resumeAgentCmd:()=>up,sayToLead:()=>qt,sendOptionsForAgent:()=>On,setTrackDraft:()=>Wg,setTrackModel:()=>qg,startLeadHandoff:()=>vp,startSpinUpView:()=>Ug,startSubtask:()=>fy,startTransferOut:()=>ly,stopJobActive:()=>AI,subtaskMessages:()=>Pg,trackMessages:()=>pp,unarchiveTrack:()=>kp});import V from"node:fs/promises";import G from"node:path";import{randomUUID as ip}from"node:crypto";import{execFile as E2}from"node:child_process";import{promisify as _2}from"node:util";function Rg(e,{skipPermissions:t=!0,model:n=null}={}){let r=lp[e];if(!r)throw new Error(`unknown agent "${e}"`);let o=process.env[r.envVar];if(o)return o;let s=t&&r.skipFlag?`${r.base} ${r.skipFlag}`:r.base;if(n&&n!=="default"){let a=Ch(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function up(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=lp[e];if(!s)throw new Error(`unknown agent "${e}"`);let a=process.env[s.envVar];if(a)return a;let i=n&&s.skipFlag?` ${s.skipFlag}`:"";switch(e){case"claude":{if(!t)return`${s.base}${i}`;if(r&&!un(r,t)){let c=o&&Be(o)?` --name ${o}`:"";return`${s.base} --session-id ${t}${c}${i}`}return`${s.base} --resume ${t}${i}`}case"cursor":return`${s.base} --continue${i}`;case"codex":return`${s.base} resume --last${i}`;default:return`${s.base}${i}`}}function gs(e){let t=lp[e];if(t)return process.env[t.envVar]||t.base}async function dp({maxAgeMs:e=6e4}={}){if(ho.value&&Date.now()-ho.at<e)return ho.value;let t=ho.value,n=await Promise.all(Jc.map(async r=>{let o=await mu(gs(r),{retries:[]});return o===Gs?[r,t?.[r]??!0]:[r,o===fu]}));return ho.value=Object.fromEntries(n),ho.at=Date.now(),ho.value}async function Fa(e,t=!0,n=null){let r=Rg(e,{skipPermissions:t,model:n});if(await mu(r)===Ks){ho.at=0;let o=r.split(/\s+/)[0],s=process.env.FLY_APP_NAME?"This Fly node's image predates CLI parity \u2014 update the node image (Links page \u2192 Fly card \u2192 Update) or re-provision.":nm[o]?`Install it on this node: ${nm[o]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${o}). ${s}`)}return r}function gI(e,t=go){return`${e.trim()}
|
|
211
211
|
|
|
212
|
-
(Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function
|
|
213
|
-
`;return mg=mg.then(()=>V.mkdir(Vn,{recursive:!0})).then(()=>V.appendFile(p2,n)).catch(()=>{}),mg}async function uI(e,{box:t,agent:n,message:r}){let o=ue(await ee(),e);!o||o.archivedAt||(Se(o,"startup-gate",{box:t,agent:n??null,message:r}),await se(),Xi(o,{provider:n??null,cls:"startup-gate",note:r}).catch(()=>{}))}async function zn({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let d=null;try{d=JSON.parse(await V.readFile(wg,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await ee(),u=0;for(let d of l.tracks)je(d)||!d.leadBox||(Se(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await se().catch(()=>{}),s==="available")try{await V.mkdir(G.dirname(wg),{recursive:!0}),await V.writeFile(wg,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Ig({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await ee(),o=0,s=new Set;for(let a of r.tracks){if(a.archivedAt||a.transferredTo||!a.leadBox)continue;let i=new Map;for(let c of a.events||[])c.type==="node-update"&&c.latest&&i.set(c.latest,c);for(let[c,l]of i)["done","failed","rolled-back"].includes(l.status)||y2(e,c)||(Se(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await se().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function y2(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!0;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function dI(e){if(!e)return null;let t=typeof e=="string"?[e]:Array.isArray(e?.codes)&&e.codes.length?e.codes:e?.code?[e.code]:[],n=[...new Set(t.filter(s=>b2.has(s)))];if(!n.length)return null;let r=typeof e=="object"?e?.note:null,o=r&&String(r).slice(0,500).trim()||null;return{code:n[0],...n.length>1?{codes:n}:{},note:o}}async function pI(e,t,n,{kind:r}={}){let o=await ke(t);if(!o)throw new Error(`box "${t}" is not running`);let s=ws(o.agent),a=kc({text:n,producer:bc({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=ue(await ee(),e)||null,c=Date.now(),l=null;try{l=await rr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw vc(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await wn(i,a,Aa(g)),g}vc(a,{ms:Date.now()-c,outcome:l||"up"});let u=On(o.agent,n);a.paste=!!u.paste;try{await it(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await wn(i,a,Aa(g)),g}let d={},p=await Ki({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await wn(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await de({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await ee(),w=ue(f,e);if(!w)return;let h=w.boxes.find(g=>g.name===t);Se(w,"orchestration-prompt",{box:t,agent:h?.agent||o.agent,boxRole:h?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await se()}async function k2(e){let t=G.join(Ls(e),`${e.id}.ndjson`),n;try{n=await V.stat(t)}catch{return null}let r=eI.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await q(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return eI.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function x2(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Vm(n.name,n.agent)}async function Wt(e,t=null,n=null){let r=t??new Map((await cn()).map(b=>[b.name,b])),o=!!e.transferredTo,s=e.boxes.map(b=>{let I=o?null:r.get(b.name),R=Er.has(b.state)?b.state:I?b.role==="lead"?"live":b.state:"stopped";return{...b,state:R,cwd:I?.cwd||b.cwd,agent:I?.agent||b.agent,sessionId:I?.sessionId||b.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([k2(e),x2(e,s),ug(e),n??hn().catch(()=>[])]),d=qc.has(e.id),p=(u||[]).filter(b=>b.trackId===e.id&&!["merged","closed","lost"].includes(b.state)),f=Q_(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||z_(p),h=s.find(b=>b.name===e.leadBox)?.state==="live",g=h?hs(e.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"):[],y=h&&l.runningJobs?{source:"jobs",count:l.runningJobs,since:l.runningJobsSince,summary:l.runningJobs===1?"a background job is still running":`${l.runningJobs} background jobs are still running`}:g.length?{source:"queue",count:g.length,since:Math.min(...g.map(b=>b.ts||Date.now())),summary:"a queued message is about to send"}:null,k=Y_({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:J_(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:y,completedTurnAt:l.completedTurnAt||a,live:h});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:k}}function fI(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),d=l.createdAt-v2,p=r[u+1]?.createdAt??1/0,f=o.find(w=>!s.has(w.id)&&w.birthMs>=d&&w.birthMs<p);f&&(s.add(f.id),c.push({box:l.name,sessionId:f.id}))}return c}async function hI(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(p=>p.box.sessionId),a=I0(r),i=new Set(a.map(p=>p.id)),c=s.every(p=>p&&i.has(p)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(p=>p.box),d=fI(u,a,p=>i.has(p));for(let p of d){let f=u.find(w=>w.name===p.box);f&&(f.sessionId=p.sessionId),await g0(p.box,p.sessionId),n=!0}}return n}async function we(){let e=await ee();await hI(e)&&await se();let t=new Map((await cn()).map(r=>[r.name,r])),n=await hn().catch(()=>[]);return Promise.all(e.tracks.map(r=>Wt(r,t,n)))}async function yc(e,t){let n=await ee();if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===e);if(o)return{track:r,box:o}}if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===t);if(o)return{track:r,box:o}}return null}async function zc(e){let t=Ro(e);if(!t)return null;let n=await ee();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&ek(o.hookTokenHash,t))return{track:r,box:o};return null}async function $g(e){return ue(await ee(),e)??null}async function le(e){let t=await ee(),n=ue(t,e);return n?(await hI(t)&&await se(),Wt(n)):null}async function Rg(e){let t=await q(e).catch(()=>[]),n;try{n=Mn(t)}catch{return[]}let r=Ru(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=Wx(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function xg(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(S2[e.agent]||[]).some(n=>n.test(t))}function vg(e){let t=(e.text||"").trim();return t?A2.some(n=>n.test(t)):!1}async function lp(e,t={}){let n=await le(e);if(!n)return null;let r=new Set([...n.events.filter(O=>O.type==="orchestration-prompt"&&O.prompt).map(O=>String(O.prompt).trim()),...n.events.filter(O=>O.type==="said"&&O.text).map(O=>String(O.text).trim())]),o=Ha(n.id),s=!!(o&&!o.finishedAt&&o.step!=="done"&&!o.error),a=s&&o?.startedAt?[...o.fromBox?[{box:o.fromBox,from:o.startedAt,to:Date.now()+1e12}]:[],...o.toBox?[{box:o.toBox,from:o.startedAt,to:Date.now()+1e12}]:[]]:[],i=Mw(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...$E(n),...l],p={windows:[...pv(n),...fv(n,Nu),...a,...u]},w=(await Promise.all(n.boxes.map(O=>om(O,t)))).flat(),h=w.map(O=>{let Y={kind:"message",...O};if(Y.role==="assistant"&&(Y.text||"").trim()&&Y.tools?.length){let Le=Yr(Y.agent).cliTools,Qe=Y.tools.filter(oe=>!Le.has(oe));return{...Y,tools:Qe.length?Qe:void 0}}return Y}).map(O=>{if(O.role!=="user")return O;let Y=Ox(O);return Y?Y.kind==="suppress"?null:{...O,note:Y,text:Cx(Y)}:O}).filter(Boolean).filter(O=>!(O.role==="user"&&r.has((O.text||"").trim()))).filter(O=>!xg(O)).filter(O=>!vg(O)).filter(O=>!kg(O)).filter(O=>!ng(O)).filter(O=>O.role!=="assistant"||!!(O.text||"").trim()||!!O.images?.length).filter(O=>!hv(O,p)),g=h.filter(O=>O.failed&&O.text===Fo);if(g.length){let O=new Map;for(let Y of g){if(!O.has(Y.box)){let oe=[...(await Pe(Y.box,{lines:et}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(ye=>ye[1]);O.set(Y.box,oe.length?oe[oe.length-1]:null)}let Le=O.get(Y.box);Le&&(Y.text=`\u25A0 ${Le}`)}}let y=await Promise.all(n.boxes.map(O=>eS(O,t)));await rE(n,y.flat());let{agentTurnBoxes:k}=await tE(n,h);for(let O of n.boxes)k.has(O.name)&&O.cwd&&Zl(O.cwd);await GS(n),await PE(n,h).catch(()=>{});for(let O of n.boxes)O.agent==="codex"&&O.state==="live"&&await sE(n,O),O.agent==="cursor"&&O.state==="live"&&await uE(n,O);let b=await Promise.all(n.boxes.map(O=>Qv(O,t)));await nE(n,b.flat().filter(O=>!gg(O.box,O.ts,u)));let I=await q(n),R=c&&i.viewId?i.viewId:null,N=sA(I),D=Mn(I).filter(O=>!(O.kind==="message"&&(xg(O)||vg(O)||kg(O)||ng(O)))&&!(O.kind==="view-card"&&R&&O.viewId===R)),j=aA(D,N),T=D.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&!j.has(O)&&gg(O.box,O.ts,N))),$=Bh(I,T).map(O=>({kind:"command-batch",id:O.id,ts:O.pending?O.ts:(O.anchorTs??O.ts)-1,anchorTs:O.anchorTs,anchorBox:O.anchorBox,agent:O.agent,boxRole:O.boxRole,commands:O.commands,pending:O.pending})).filter(O=>!gg(O.anchorBox,O.anchorTs??O.ts,u)),F=Ux(Hx([...T,...$].filter(O=>O.ts!=null).sort((O,Y)=>O.ts-Y.ts))),J=E2(n),M=J.size?F.filter(O=>O.kind==="event"||!J.has(O.box??O.anchorBox)):F,S=n.boxes.find(O=>O.name===n.leadBox)||null,_=S?await Ci(S.cwd,S.sessionId,{fallbackNewest:!1}):null;if(!_&&S){let O=[...I].reverse().find(Y=>Y.type==="context.usage"&&Y.boxId===S.name);O?.payload?.window&&(_={pct:O.payload.pct??(O.payload.occupancy!=null?O.payload.occupancy/O.payload.window:null),occupancy:O.payload.occupancy??null,window:O.payload.window,windowKnown:!0,model:O.payload.model||null})}let H=[...w].reverse().find(O=>O.role==="assistant"&&O.model),K=H?.model||null,X=[...n.events||[]].reverse().find(O=>O.type==="model-change"),pe=_?.model||K;X&&(!H?.ts||X.at>=H.ts)&&(pe=X.to);let Oe=S?await Pe(S.name,{lines:et}).catch(()=>""):"",Me=S&&Qr(S.agent,Oe)?await ln(S.name).catch(()=>Oe):Oe,Q=S?Nn(S,Me):null;if(Q&&S){let O=Gu(S,Q,Me);if(O){let Y=mS(S.name,Q.promptId);Y.action!=="give-up"&&(Y.action==="send"&&(ze(S.name,O.keys,{kind:"auto-reject"}).catch(()=>{}),Y.first&&C(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:S.name,provider:S.agent,payload:{ts:Date.now(),promptId:Q.promptId,rule:O.id}}).catch(()=>{})),Q=null)}}!Q&&S&&!Qs(S.agent,Oe)&&!hs(n.id).length&&(Q=Nh(M,{leadBoxId:S.name,provider:S.agent,isAnswered:O=>I.some(Y=>Y.type==="prompt.answered"&&Y.payload?.promptId===O)})),Q&&VS(n,S,Q);let qe=M.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&O.ask&&!String(O.text||"").trim()&&!O.images?.length)),Z=!!S&&bd(S.name,S.agent,Oe)&&!Q;S&&!S.readyAt&&(Z||Q||Oe&&Ho(S.agent,Oe))&&(S.readyAt=Date.now(),await se());let me=!!S&&!S.readyAt&&Date.now()-(n.createdAt||0)<T2;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&S&&Ho(S.agent,Oe)&&!Q){let O=await ee(),Y=ue(O,n.id);Y?.setup&&!Y.setup.connectedAt&&(Y.setup.connectedAt=Date.now(),n.setup.connectedAt=Y.setup.connectedAt,await C(Y,{type:"provider.connected",actor:"system",source:"pane",boxId:S.name,provider:S.agent,payload:{provider:S.agent,ts:Y.setup.connectedAt}}).catch(()=>{}),await se())}let Te=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,z=Yc(n.id),ge=z&&!z.finishedAt?{running:!0,step:z.step||null,added:z.added||[],removed:z.removed||[]}:null,Ge=null;if(c){let O=Date.now()-i.startedAt;if(i.viewId&&!Z){let Y=jd(n.id);Y&&(Se(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:Y.finishedAt}),await se())}else if(Q||O>_E&&!Z&&!i.viewId||O>Ow){let Y=Q?"needs-input":O>Ow?"timeout":"no-view";jd(n.id,{error:Y})&&await C(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:S?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:Y}}).catch(()=>{})}else Ge={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:qe,context:_?{pct:_.pct,occupancy:_.occupancy,window:_.window,windowKnown:_.windowKnown,model:_.model}:null,models:{current:pe,options:$m(S?.agent)},pendingPrompt:Q,working:Z,stopping:wI(n.id),leadStarting:me,handoff:Te,reshape:ge,view:Ge,queued:hs(n.id).filter(O=>O.kind!=="ship-notify"&&O.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function E2(e){let t=new Set;for(let n of e.boxes||[])n.role==="subtask"&&n.name&&t.add(n.name);for(let n of Object.values(e.subtasks||{}))n?.box&&t.add(n.box);return t}async function Og(e,t){let n=await le(e);if(!n)return null;let r=bs(e).find(d=>d.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await q(n),a=Mn(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Bh(s.filter(d=>d.boxId===o),a.filter(d=>d.kind==="message")).map(d=>({kind:"command-batch",id:d.id,ts:d.pending?d.ts:(d.anchorTs??d.ts)-1,anchorTs:d.anchorTs,anchorBox:d.anchorBox,agent:d.agent,boxRole:d.boxRole,commands:d.commands,pending:d.pending})),c=[...a,...i].filter(d=>d.ts!=null).sort((d,p)=>d.ts-p.ts),l=n.boxes.find(d=>d.name===o)||null,u=!1;if(l&&l.state==="live"){let d=await Pe(o,{lines:et}).catch(()=>"");u=bd(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function _2(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>tI)throw new Error(`custom answer is too long (max ${tI} characters)`);return r})}function I2(e,t){let n=String(e||"").replace(/\s+/g," ").trim(),r=String(t||"").replace(/\s+/g," ").trim();return!n||!r?!1:n===r||r.startsWith(n)||n.startsWith(r.slice(0,24))}async function up(e,t={}){let n=Dc.get(e);n&&await n.catch(()=>{});let r=$2(e,t);Dc.set(e,r);try{return await r}finally{Dc.get(e)===r&&Dc.delete(e)}}async function $2(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=ue(await ee(),e);if(!s)throw new Error(`track "${e}" not found`);Fa(e,"prompt-answer");let a=s.boxes.find(y=>y.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await ke(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await pm(a);if(c||(c=await R2(s,a)),!c)throw new Error("no pending prompt to answer");if(t&&t!==c.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let l=_2(o,c.questions?.length??1);if(l.some(Boolean)&&!c.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let u=(n||[]).some(y=>Array.isArray(y)&&y.length>0);if(c.custom&&!u&&!l.some(Boolean)&&c.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");l.some(Boolean)&&(n=(c.questions||[]).map((y,k)=>l[k]&&!y.multiSelect?[]:Array.isArray(n?.[k])?n[k]:[]));let d;if(c.answerMode==="text"){let y=typeof r=="string"?r.trim():"";if(!y)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(y)||y.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await it(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(c.answerMode==="esc")await ze(s.leadBox,["Escape"],{kind:"answer-prompt"}),d={mode:"keys",value:"Escape",count:1};else if(c.answerMode==="say"){let y=Bx(c,n||[],typeof r=="string"?r:"",l);if(!y)throw new Error("no answer selected \u2014 pick an option or reply in chat");await qt(s.id,y,{kind:"prompt-answer"}),d={mode:"say",value:y,count:1}}else if(l[0]&&c.provider==="claude"){let y=dS(c,n||[],l[0]);await Qf(s.leadBox,[...y.pre,{text:y.text}],{kind:"answer-prompt"});let k=!1;for(let I of[150,300,600]){await _r(I);let R=await ln(s.leadBox).catch(()=>""),N=Nn(a,R);if(N?.customText&&I2(N.customText,y.text)){k=!0;break}}if(!k)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await Qf(s.leadBox,y.post,{kind:"answer-prompt"});let b=I=>I.map(R=>R.key).join(" ");d={mode:"keys+text",value:`${b(y.pre)} \u2039text\u203A ${b(y.post)}`.trim(),count:y.pre.length+1+y.post.length}}else if(c.provider==="claude"||c.answerMode==="keys"){let y=fm(c,n||[]);await ze(s.leadBox,y,{kind:"answer-prompt"}),d={mode:"keys",value:y.join(" "),count:y.length}}else{let y=nx(c,n||[]);await it(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text",value:y,count:1}}if(c.answerMode==="say"){let y=c.questions||[];for(let k=0;k<y.length;k++){let b=y[k],I=new Set(Array.isArray(n?.[k])?n[k]:[]),R=[...I].map(D=>b.options?.[D]).filter(Boolean).map(D=>({label:D.label,description:D.description||""}));l[k]&&R.push({label:l[k],description:"",custom:!0});let N=(b.options||[]).map((D,j)=>I.has(j)?null:D?.label).filter(Boolean);Rm(s,a,c,{...d,groupId:c.groupId||c.promptId,questionIndex:k,questionTotal:c.questionTotal??y.length,header:b.header||"",question:b.question||"",multiSelect:!!b.multiSelect,chosen:R,rejected:N})}return await de({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),{ok:!0,promptId:c.promptId,sent:d.count}}let p=c.questions?.[0]||{},f=new Set(Array.isArray(n?.[0])?n[0]:[]),w=[...f].map(y=>p.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));l[0]&&w.push({label:l[0],description:"",custom:!0});let h=(p.options||[]).map((y,k)=>f.has(k)?null:y?.label).filter(Boolean),g=c.review?"review":/^claude:model-confirm:/.test(c.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(c.promptId||"")?"resume-confirm":void 0;return d={...d,groupId:c.groupId||c.promptId,questionIndex:c.questionIndex??0,questionTotal:c.questionTotal??1,header:p.header||"",question:p.question||"",multiSelect:!!p.multiSelect,chosen:w,rejected:h,...g?{control:g}:{}},await de({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),Rm(s,a,c,d),{ok:!0,promptId:c.promptId,sent:d.count}}async function R2(e,t){if(!t)return null;let n=await q(e).catch(()=>[]);return Nh(Mn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Mg(e,{promptId:t,questionIndex:n}={}){let r=ue(await ee(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await ke(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await pm(o);if(!a)throw new Error("no pending prompt to navigate");if(a.provider!=="claude")throw new Error("prompt navigation not supported for this provider");if(a.review)throw new Error("cannot navigate on the review screen \u2014 answer or cancel");let i=a.questionTotal??1;if(i<2)throw new Error("not a multi-question prompt");if(!Number.isInteger(n)||n<0||n>=i)throw new Error("questionIndex out of range");if(t&&t!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=pS(a,n);return c.length?(await ze(r.leadBox,c,{kind:"navigate-prompt"}),await de({flow:"prompt",phase:"navigated",sessionName:r.leadBox,agent:o.agent,provider:a.provider,promptId:a.promptId,fromIndex:a.questionIndex??0,toIndex:n,mode:"keys",value:c.join(" "),count:c.length}).catch(()=>{}),{ok:!0,promptId:a.promptId,sent:c.length}):{ok:!0,promptId:a.promptId,sent:0}}function dp(e){let t=Da.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},Da.set(e,t)),t}function hs(e){return(Da.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Cg(e=Date.now()){let t=0,n=0;for(let r of Da.values())for(let o of r.items){t+=1;let s=e-(o.delivery?.queuedAt??o.ts??e);s>n&&(n=s)}return{queueDepth:t,queueOldestAgeMs:n}}function M2(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=ue(await ee(),e)||null;for(let s of r)await wn(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Jc(e,t="cancel"){let n=Da.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),M2(e,r,t),r}async function Ng(e){let t=Jc(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=ue(await ee(),e);if(o)return r=Ba(o,n),await se(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Pg(e){let t=dp(e);t.timer||(t.timer=setInterval(()=>C2(e).catch(()=>{}),O2))}async function C2(e){let t=Da.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=ue(await ee(),e);if(!n||n.archivedAt){Jc(e,"archived");return}let r=async(l,u="")=>{let d=[];for(let g of t.items)yE(g.delivery,l),j_(g,l)&&d.push(g);if(!d.length)return;t.items=t.items.filter(g=>!d.includes(g));let p=Date.now()-Math.min(...d.map(g=>g.heldSince||Date.now())),f=Math.max(1,Math.round(og()/6e4)),w=String(u||"").split(`
|
|
212
|
+
(Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function Ag(e){return e.role==="user"&&R2.test((e.text||"").trim())}async function Z(){return Dt||(yg||=(async()=>{try{Dt=JSON.parse(await V.readFile(wI,"utf8"))}catch{Dt={tracks:[]}}finally{yg=null}return Dt})(),yg)}async function ae(){await Mt(wI,Dt)}function C2(e,t){let n=JSON.stringify({trackId:e,...t})+`
|
|
213
|
+
`;return bg=bg.then(()=>V.mkdir(Vn,{recursive:!0})).then(()=>V.appendFile(I2,n)).catch(()=>{}),bg}async function yI(e,{box:t,agent:n,message:r}){let o=de(await Z(),e);!o||o.archivedAt||(Ae(o,"startup-gate",{box:t,agent:n??null,message:r}),await ae(),Qi(o,{provider:n??null,cls:"startup-gate",note:r}).catch(()=>{}))}async function zn({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let d=null;try{d=JSON.parse(await V.readFile(kg,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await Z(),u=0;for(let d of l.tracks)Le(d)||!d.leadBox||(Ae(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ae().catch(()=>{}),s==="available")try{await V.mkdir(G.dirname(kg),{recursive:!0}),await V.writeFile(kg,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Mg({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await Z(),o=0,s=new Set;for(let a of r.tracks){if(a.archivedAt||a.transferredTo||!a.leadBox)continue;let i=new Map;for(let c of a.events||[])c.type==="node-update"&&c.latest&&i.set(c.latest,c);for(let[c,l]of i)["done","failed","rolled-back"].includes(l.status)||N2(e,c)||(Ae(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await ae().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function N2(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!0;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function bI(e){if(!e)return null;let t=typeof e=="string"?[e]:Array.isArray(e?.codes)&&e.codes.length?e.codes:e?.code?[e.code]:[],n=[...new Set(t.filter(s=>P2.has(s)))];if(!n.length)return null;let r=typeof e=="object"?e?.note:null,o=r&&String(r).slice(0,500).trim()||null;return{code:n[0],...n.length>1?{codes:n}:{},note:o}}async function kI(e,t,n,{kind:r}={}){let o=await be(t);if(!o)throw new Error(`box "${t}" is not running`);let s=gs(o.agent),a=vc({text:n,producer:xc({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=de(await Z(),e)||null,c=Date.now(),l=null;try{l=await sr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw Ac(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await wn(i,a,Ta(g)),g}Ac(a,{ms:Date.now()-c,outcome:l||"up"});let u=On(o.agent,n);a.paste=!!u.paste;try{await at(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await wn(i,a,Ta(g)),g}let d={},p=await Vi({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await wn(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await pe({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await Z(),w=de(f,e);if(!w)return;let m=w.boxes.find(g=>g.name===t);Ae(w,"orchestration-prompt",{box:t,agent:m?.agent||o.agent,boxRole:m?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await ae()}async function D2(e){let t=G.join(Fs(e),`${e.id}.ndjson`),n;try{n=await V.stat(t)}catch{return null}let r=cI.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await q(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return cI.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function B2(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Xh(n.name,n.agent)}async function Wt(e,t=null,n=null){let r=t??new Map((await cn()).map(b=>[b.name,b])),o=!!e.transferredTo,s=e.boxes.map(b=>{let I=o?null:r.get(b.name),$=Ir.has(b.state)?b.state:I?b.role==="lead"?"live":b.state:"stopped";return{...b,state:$,cwd:I?.cwd||b.cwd,agent:I?.agent||b.agent,sessionId:I?.sessionId||b.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([D2(e),B2(e,s),mg(e),n??mn().catch(()=>[])]),d=Gc.has(e.id),p=(u||[]).filter(b=>b.trackId===e.id&&!["merged","closed","lost"].includes(b.state)),f=iI(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||nI(p),m=s.find(b=>b.name===e.leadBox)?.state==="live",g=m?hs(e.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"):[],y=m&&l.runningJobs?{source:"jobs",count:l.runningJobs,since:l.runningJobsSince,summary:l.runningJobs===1?"a background job is still running":`${l.runningJobs} background jobs are still running`}:g.length?{source:"queue",count:g.length,since:Math.min(...g.map(b=>b.ts||Date.now())),summary:"a queued message is about to send"}:null,x=oI({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:rI(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:y,completedTurnAt:l.completedTurnAt||a,live:m});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:x}}function xI(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),d=l.createdAt-j2,p=r[u+1]?.createdAt??1/0,f=o.find(w=>!s.has(w.id)&&w.birthMs>=d&&w.birthMs<p);f&&(s.add(f.id),c.push({box:l.name,sessionId:f.id}))}return c}async function vI(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(p=>p.box.sessionId),a=D0(r),i=new Set(a.map(p=>p.id)),c=s.every(p=>p&&i.has(p)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(p=>p.box),d=xI(u,a,p=>i.has(p));for(let p of d){let f=u.find(w=>w.name===p.box);f&&(f.sessionId=p.sessionId),await T0(p.box,p.sessionId),n=!0}}return n}async function ye(){let e=await Z();await vI(e)&&await ae();let t=new Map((await cn()).map(r=>[r.name,r])),n=await mn().catch(()=>[]);return Promise.all(e.tracks.map(r=>Wt(r,t,n)))}async function kc(e,t){let n=await Z();if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===e);if(o)return{track:r,box:o}}if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===t);if(o)return{track:r,box:o}}return null}async function Yc(e){let t=Oo(e);if(!t)return null;let n=await Z();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&ck(o.hookTokenHash,t))return{track:r,box:o};return null}async function Cg(e){return de(await Z(),e)??null}async function ue(e){let t=await Z(),n=de(t,e);return n?(await vI(t)&&await ae(),Wt(n)):null}async function Ng(e){let t=await q(e).catch(()=>[]),n;try{n=Mn(t)}catch{return[]}let r=Cu(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=Xx(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Tg(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(L2[e.agent]||[]).some(n=>n.test(t))}function Eg(e){let t=(e.text||"").trim();return t?F2.some(n=>n.test(t)):!1}async function pp(e,t={}){let n=await ue(e);if(!n)return null;let r=new Set([...n.events.filter(O=>O.type==="orchestration-prompt"&&O.prompt).map(O=>String(O.prompt).trim()),...n.events.filter(O=>O.type==="said"&&O.text).map(O=>String(O.text).trim())]),o=Wa(n.id),s=!!(o&&!o.finishedAt&&o.step!=="done"&&!o.error),a=s&&o?.startedAt?[...o.fromBox?[{box:o.fromBox,from:o.startedAt,to:Date.now()+1e12}]:[],...o.toBox?[{box:o.toBox,from:o.startedAt,to:Date.now()+1e12}]:[]]:[],i=Dw(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...BE(n),...l],p={windows:[...kv(n),...xv(n,Bu),...a,...u]},w=(await Promise.all(n.boxes.map(O=>ch(O,t)))).flat(),m=w.map(O=>{let ce={kind:"message",...O};if(ce.role==="assistant"&&(ce.text||"").trim()&&ce.tools?.length){let ve=Zr(ce.agent).cliTools,wt=ce.tools.filter(Q=>!ve.has(Q));return{...ce,tools:wt.length?wt:void 0}}return ce}).map(O=>{if(O.role!=="user")return O;let ce=Lx(O);return ce?ce.kind==="suppress"?null:{...O,note:ce,text:Ux(ce)}:O}).filter(Boolean).filter(O=>!(O.role==="user"&&r.has((O.text||"").trim()))).filter(O=>!Tg(O)).filter(O=>!Eg(O)).filter(O=>!Ag(O)).filter(O=>!ag(O)).filter(O=>O.role!=="assistant"||!!(O.text||"").trim()||!!O.images?.length).filter(O=>!vv(O,p)),g=m.filter(O=>O.failed&&O.text===Uo);if(g.length){let O=new Map;for(let ce of g){if(!O.has(ce.box)){let Q=[...(await De(ce.box,{lines:Xe}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(ge=>ge[1]);O.set(ce.box,Q.length?Q[Q.length-1]:null)}let ve=O.get(ce.box);ve&&(ce.text=`\u25A0 ${ve}`)}}let y=await Promise.all(n.boxes.map(O=>cS(O,t)));await dE(n,y.flat());let{agentTurnBoxes:x}=await lE(n,m);for(let O of n.boxes)x.has(O.name)&&O.cwd&&tu(O.cwd);await eA(n),await WE(n,m).catch(()=>{});for(let O of n.boxes)O.agent==="codex"&&O.state==="live"&&await fE(n,O),O.agent==="cursor"&&O.state==="live"&&await yE(n,O);let b=await Promise.all(n.boxes.map(O=>iS(O,t)));await uE(n,b.flat().filter(O=>!xg(O.box,O.ts,u)));let I=await q(n),$=c&&i.viewId?i.viewId:null,P=fA(I),F=Mn(I).filter(O=>!(O.kind==="message"&&(Tg(O)||Eg(O)||Ag(O)||ag(O)))&&!(O.kind==="view-card"&&$&&O.viewId===$)),B=mA(F,P),T=F.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&!B.has(O)&&xg(O.box,O.ts,P))),_=Um(I,T).map(O=>({kind:"command-batch",id:O.id,ts:O.pending?O.ts:(O.anchorTs??O.ts)-1,anchorTs:O.anchorTs,anchorBox:O.anchorBox,agent:O.agent,boxRole:O.boxRole,commands:O.commands,pending:O.pending})).filter(O=>!xg(O.anchorBox,O.anchorTs??O.ts,u)),U=Jx(Yx([...T,..._].filter(O=>O.ts!=null).sort((O,ce)=>O.ts-ce.ts))),J=H2(n),R=J.size?U.filter(O=>O.kind==="event"||!J.has(O.box??O.anchorBox)):U,A=n.boxes.find(O=>O.name===n.leadBox)||null,M=A?await Pi(A.cwd,A.sessionId,{fallbackNewest:!1}):null;if(!M&&A){let O=[...I].reverse().find(ce=>ce.type==="context.usage"&&ce.boxId===A.name);O?.payload?.window&&(M={pct:O.payload.pct??(O.payload.occupancy!=null?O.payload.occupancy/O.payload.window:null),occupancy:O.payload.occupancy??null,window:O.payload.window,windowKnown:!0,model:O.payload.model||null})}let N=[...w].reverse().find(O=>O.role==="assistant"&&O.model),K=N?.model||null,Y=[...n.events||[]].reverse().find(O=>O.type==="model-change"),fe=M?.model||K;Y&&(!N?.ts||Y.at>=N.ts)&&(fe=Y.to);let Ie=A?await De(A.name,{lines:Xe}).catch(()=>""):"",Ce=A&&to(A.agent,Ie)?await ln(A.name).catch(()=>Ie):Ie,X=A?Nn(A,Ce):null;if(X&&A){let O=Ju(A,X,Ce);if(O){let ce=SS(A.name,X.promptId);ce.action!=="give-up"&&(ce.action==="send"&&(Ge(A.name,O.keys,{kind:"auto-reject"}).catch(()=>{}),ce.first&&C(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:A.name,provider:A.agent,payload:{ts:Date.now(),promptId:X.promptId,rule:O.id}}).catch(()=>{})),X=null)}}!X&&A&&!ea(A.agent,Ie)&&!hs(n.id).length&&(X=jm(R,{leadBoxId:A.name,provider:A.agent,isAnswered:O=>I.some(ce=>ce.type==="prompt.answered"&&ce.payload?.promptId===O)})),X&&tA(n,A,X);let et=R.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&O.ask&&!String(O.text||"").trim()&&!O.images?.length)),se=!!A&&vd(A.name,A.agent,Ie)&&!X;A&&!A.readyAt&&(se||X||Ie&&Wo(A.agent,Ie))&&(A.readyAt=Date.now(),await ae());let ee=!!A&&!A.readyAt&&Date.now()-(n.createdAt||0)<U2;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&A&&Wo(A.agent,Ie)&&!X){let O=await Z(),ce=de(O,n.id);ce?.setup&&!ce.setup.connectedAt&&(ce.setup.connectedAt=Date.now(),n.setup.connectedAt=ce.setup.connectedAt,await C(ce,{type:"provider.connected",actor:"system",source:"pane",boxId:A.name,provider:A.agent,payload:{provider:A.agent,ts:ce.setup.connectedAt}}).catch(()=>{}),await ae())}let Oe=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,z=Zc(n.id),we=z&&!z.finishedAt?{running:!0,step:z.step||null,added:z.added||[],removed:z.removed||[]}:null,Fe=null;if(c){let O=Date.now()-i.startedAt;if(i.viewId&&!se){let ce=Ud(n.id);ce&&(Ae(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:ce.finishedAt}),await ae())}else if(X||O>PE&&!se&&!i.viewId||O>Pw){let ce=X?"needs-input":O>Pw?"timeout":"no-view";Ud(n.id,{error:ce})&&await C(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:A?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:ce}}).catch(()=>{})}else Fe={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:et,context:M?{pct:M.pct,occupancy:M.occupancy,window:M.window,windowKnown:M.windowKnown,model:M.model}:null,models:{current:fe,options:Ch(A?.agent)},pendingPrompt:X,working:se,stopping:AI(n.id),leadStarting:ee,handoff:Oe,reshape:we,view:Fe,queued:hs(n.id).filter(O=>O.kind!=="ship-notify"&&O.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function H2(e){let t=new Set;for(let n of e.boxes||[])n.role==="subtask"&&n.name&&t.add(n.name);for(let n of Object.values(e.subtasks||{}))n?.box&&t.add(n.box);return t}async function Pg(e,t){let n=await ue(e);if(!n)return null;let r=ks(e).find(d=>d.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await q(n),a=Mn(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Um(s.filter(d=>d.boxId===o),a.filter(d=>d.kind==="message")).map(d=>({kind:"command-batch",id:d.id,ts:d.pending?d.ts:(d.anchorTs??d.ts)-1,anchorTs:d.anchorTs,anchorBox:d.anchorBox,agent:d.agent,boxRole:d.boxRole,commands:d.commands,pending:d.pending})),c=[...a,...i].filter(d=>d.ts!=null).sort((d,p)=>d.ts-p.ts),l=n.boxes.find(d=>d.name===o)||null,u=!1;if(l&&l.state==="live"){let d=await De(o,{lines:Xe}).catch(()=>"");u=vd(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function W2(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>lI)throw new Error(`custom answer is too long (max ${lI} characters)`);return r})}function q2(e,t){let n=String(e||"").replace(/\s+/g," ").trim(),r=String(t||"").replace(/\s+/g," ").trim();return!n||!r?!1:n===r||r.startsWith(n)||n.startsWith(r.slice(0,24))}async function fp(e,t={}){let n=jc.get(e);n&&await n.catch(()=>{});let r=K2(e,t);jc.set(e,r);try{return await r}finally{jc.get(e)===r&&jc.delete(e)}}async function K2(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=de(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);Ua(e,"prompt-answer");let a=s.boxes.find(y=>y.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await be(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await wh(a);if(c||(c=await G2(s,a)),!c)throw new Error("no pending prompt to answer");if(t&&t!==c.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let l=W2(o,c.questions?.length??1);if(l.some(Boolean)&&!c.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let u=(n||[]).some(y=>Array.isArray(y)&&y.length>0);if(c.custom&&!u&&!l.some(Boolean)&&c.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");l.some(Boolean)&&(n=(c.questions||[]).map((y,x)=>l[x]&&!y.multiSelect?[]:Array.isArray(n?.[x])?n[x]:[]));let d;if(c.answerMode==="text"){let y=typeof r=="string"?r.trim():"";if(!y)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(y)||y.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await at(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(c.answerMode==="esc")await Ge(s.leadBox,["Escape"],{kind:"answer-prompt"}),d={mode:"keys",value:"Escape",count:1};else if(c.answerMode==="say"){let y=Kx(c,n||[],typeof r=="string"?r:"",l);if(!y)throw new Error("no answer selected \u2014 pick an option or reply in chat");await qt(s.id,y,{kind:"prompt-answer"}),d={mode:"say",value:y,count:1}}else if(l[0]&&c.provider==="claude"){let y=bS(c,n||[],l[0]);await rm(s.leadBox,[...y.pre,{text:y.text}],{kind:"answer-prompt"});let x=!1;for(let I of[150,300,600]){await $r(I);let $=await ln(s.leadBox).catch(()=>""),P=Nn(a,$);if(P?.customText&&q2(P.customText,y.text)){x=!0;break}}if(!x)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await rm(s.leadBox,y.post,{kind:"answer-prompt"});let b=I=>I.map($=>$.key).join(" ");d={mode:"keys+text",value:`${b(y.pre)} \u2039text\u203A ${b(y.post)}`.trim(),count:y.pre.length+1+y.post.length}}else if(c.provider==="claude"||c.answerMode==="keys"){let y=gh(c,n||[]);await Ge(s.leadBox,y,{kind:"answer-prompt"}),d={mode:"keys",value:y.join(" "),count:y.length}}else{let y=ux(c,n||[]);await at(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text",value:y,count:1}}if(c.answerMode==="say"){let y=c.questions||[];for(let x=0;x<y.length;x++){let b=y[x],I=new Set(Array.isArray(n?.[x])?n[x]:[]),$=[...I].map(F=>b.options?.[F]).filter(Boolean).map(F=>({label:F.label,description:F.description||""}));l[x]&&$.push({label:l[x],description:"",custom:!0});let P=(b.options||[]).map((F,B)=>I.has(B)?null:F?.label).filter(Boolean);Nh(s,a,c,{...d,groupId:c.groupId||c.promptId,questionIndex:x,questionTotal:c.questionTotal??y.length,header:b.header||"",question:b.question||"",multiSelect:!!b.multiSelect,chosen:$,rejected:P})}return await pe({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),{ok:!0,promptId:c.promptId,sent:d.count}}let p=c.questions?.[0]||{},f=new Set(Array.isArray(n?.[0])?n[0]:[]),w=[...f].map(y=>p.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));l[0]&&w.push({label:l[0],description:"",custom:!0});let m=(p.options||[]).map((y,x)=>f.has(x)?null:y?.label).filter(Boolean),g=c.review?"review":/^claude:model-confirm:/.test(c.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(c.promptId||"")?"resume-confirm":void 0;return d={...d,groupId:c.groupId||c.promptId,questionIndex:c.questionIndex??0,questionTotal:c.questionTotal??1,header:p.header||"",question:p.question||"",multiSelect:!!p.multiSelect,chosen:w,rejected:m,...g?{control:g}:{}},await pe({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),Nh(s,a,c,d),{ok:!0,promptId:c.promptId,sent:d.count}}async function G2(e,t){if(!t)return null;let n=await q(e).catch(()=>[]);return jm(Mn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Dg(e,{promptId:t,questionIndex:n}={}){let r=de(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await be(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await wh(o);if(!a)throw new Error("no pending prompt to navigate");if(a.provider!=="claude")throw new Error("prompt navigation not supported for this provider");if(a.review)throw new Error("cannot navigate on the review screen \u2014 answer or cancel");let i=a.questionTotal??1;if(i<2)throw new Error("not a multi-question prompt");if(!Number.isInteger(n)||n<0||n>=i)throw new Error("questionIndex out of range");if(t&&t!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=kS(a,n);return c.length?(await Ge(r.leadBox,c,{kind:"navigate-prompt"}),await pe({flow:"prompt",phase:"navigated",sessionName:r.leadBox,agent:o.agent,provider:a.provider,promptId:a.promptId,fromIndex:a.questionIndex??0,toIndex:n,mode:"keys",value:c.join(" "),count:c.length}).catch(()=>{}),{ok:!0,promptId:a.promptId,sent:c.length}):{ok:!0,promptId:a.promptId,sent:0}}function mp(e){let t=Ba.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},Ba.set(e,t)),t}function hs(e){return(Ba.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Bg(e=Date.now()){let t=0,n=0;for(let r of Ba.values())for(let o of r.items){t+=1;let s=e-(o.delivery?.queuedAt??o.ts??e);s>n&&(n=s)}return{queueDepth:t,queueOldestAgeMs:n}}function z2(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=de(await Z(),e)||null;for(let s of r)await wn(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Xc(e,t="cancel"){let n=Ba.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),z2(e,r,t),r}async function jg(e){let t=Xc(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=de(await Z(),e);if(o)return r=ja(o,n),await ae(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Lg(e){let t=mp(e);t.timer||(t.timer=setInterval(()=>J2(e).catch(()=>{}),V2))}async function J2(e){let t=Ba.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=de(await Z(),e);if(!n||n.archivedAt){Xc(e,"archived");return}let r=async(l,u="")=>{let d=[];for(let g of t.items)EE(g.delivery,l),G_(g,l)&&d.push(g);if(!d.length)return;t.items=t.items.filter(g=>!d.includes(g));let p=Date.now()-Math.min(...d.map(g=>g.heldSince||Date.now())),f=Math.max(1,Math.round(cg()/6e4)),w=String(u||"").split(`
|
|
214
214
|
`).map(g=>g.trimEnd()).filter(g=>g.trim()).slice(-3).join(`
|
|
215
|
-
`),
|
|
215
|
+
`),m=l==="noSession"?`The scheduled prompt waited ${f} min for the box's session to come back and was dropped \u2014 open the terminal.`:`The scheduled prompt waited ${f} min for the box to become idle and was dropped \u2014 open the terminal.`;for(let g of d)g.delivery&&await wn(n,g.delivery,l==="noSession"?"failed:not-running":"failed:blocked");Ae(n,"delivery-held",{box:n.leadBox,agent:o?.agent??null,reason:l,heldMs:p,producer:"loop",deliveryId:d[0]?.delivery?.id??null,message:m,...w?{detail:w}:{}}),await ae(),Qi(n,{provider:o?.agent??null,cls:"delivery-held",note:m}).catch(()=>{})},o=n.boxes.find(l=>l.name===n.leadBox),s=Wa(e);if(s&&!s.finishedAt&&s.step!=="done"&&!s.error){ms(t,!1),await r("handoff");return}let a=await be(n.leadBox);if(a&&await ey(a)&&(a=await Vc(n,o,"queue")?await be(n.leadBox):null,await ae()),!a){ms(t,!1),await r("noSession");return}if(no(o?.agent)){ms(t,!1),await r("cap");return}let i=await De(n.leadBox,{lines:Xe}).catch(()=>"");if(Ui(o?.agent,i)){ms(t,!1),await r("busy",i);return}if(to(o?.agent,i)){let l=await ln(n.leadBox).catch(()=>i);if(Nn(o,l)){ms(t,!1),await r("prompt");return}}if(!ms(t,!0)){await r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await _g(n,o,a,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await wn(n,c.delivery,Ta(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await Sc(n,c.delivery,{position:1,reason:"requeue"})),await Vc(n,o,"queue-gate")}await ae()}finally{t.flushing=!1}}}async function SI(e,t,n,r){let o=no(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(ja(e,[n]),await ae()),jS(e.id,o))try{await C(e,{type:"usage.cap.hit",actor:"system",provider:t?.agent??null,boxId:e.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${t?.agent??"the lead provider"} is paused \u2014 its ${o.window} spend limit is reached ($${o.spentUsd.toFixed(2)} of $${o.limitUsd.toFixed(2)})`);throw s.usageCap=o,s}async function Y2(e,t){let n=await De(e.leadBox,{lines:Xe}).catch(()=>"");if(!to(t?.agent,n))return!1;let r=await ln(e.leadBox).catch(()=>n);return!!Nn(t,r)}async function _g(e,t,n,r,o=null,s=null,a=null){a||(a=vc({text:r,producer:xc({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await SI(e,t,r,o);let i=Wc.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=gI(r,e.pendingHandoffHydrate.artifact||go),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(m=>m&&m.rel):[];if(d.length){let m=K_(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
|
|
216
216
|
|
|
217
|
-
${
|
|
217
|
+
${m}`:m}let p=Ae(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||Da(e,null);try{let m=Date.now(),g=null;try{g=await sr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:gs(n.agent),bailOnDialog:!0})}catch(x){throw Ac(a,{ms:Date.now()-m,outcome:x?.code==="cli-not-running"?"cli-not-running":"blocked"}),x}if(Ac(a,{ms:Date.now()-m,outcome:g||"up"}),(Wc.get(e.id)||0)!==i){!o&&r.trim()&&(ja(e,[r]),await ae());let x=new Error("delivery stopped \u2014 the message was handed back as the draft");throw x.interrupted=!0,x}if(await Y2(e,t)){let x=mp(e.id);a.requeued+=1,a.dequeuedAt=null;let b={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};x.items.unshift(b),Lg(e.id),await Sc(e,a,{position:1,reason:"prompt"});let I=new Error("lead is blocked on a prompt \u2014 message queued");throw I.requeued={id:b.id,position:x.items.length},I}let y=On(t?.agent,c);a.paste=!!y.paste,await at(e.leadBox,c,{...y,kind:l?"lead-handoff-first-prompt":"say"})}catch(m){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Ae(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,...m?.interrupted?{reason:"interrupted"}:{},...m?.requeued?{reason:"requeued"}:{}}),m?.requeued)return{queued:!0,...m.requeued};throw m?.code!=="cli-not-running"&&await wn(e,a,Ta(m)),m}let f={},w=await pH(e,t,c,f);a.verify=f,w?await wn(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await TI(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Ae(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||ja(e,[r]),await wn(e,a,"unsubmitted")),l&&await pe({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Fg(e,{actions:t}={}){let n=mp(e),r=hA(t),o=vc({text:r,producer:xc({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),Lg(e),(async()=>{let s=de(await Z(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await Sc(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function X2(e,t,n,r){await Ge(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await $r(c),o=await De(e.leadBox,{lines:Xe}).catch(()=>""),!to(t?.agent,o)){s=!0;break}let l=await ln(e.leadBox).catch(()=>o);if(!Nn(t,l)){s=!0;break}}let a=n.questions?.[0]||{},i={groupId:n.groupId||n.promptId,questionIndex:n.questionIndex??0,questionTotal:n.questionTotal??1,header:a.header||"",question:a.question||"",multiSelect:!!a.multiSelect,options:(a.options||[]).map(c=>c?.label).filter(Boolean),via:"send",deliveryId:r?.id??null,gone:s};return pe({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&nA(e,t,n,i),{gone:s,pane:o}}async function qt(e,t,{kind:n=null,attachments:r=null,producer:o=null,dismissPrompt:s=!1}={}){let a=Array.isArray(r)?r.filter(d=>d&&typeof d.rel=="string"):[];if((typeof t!="string"||!la(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=de(await Z(),e);if(!i)throw new Error(`track "${e}" not found`);if(i.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);Sp(i);let c=i.boxes.find(d=>d.name===i.leadBox),l=la(t),u=vc({text:l,producer:xc({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});try{return await Z2(e,i,c,l,{kind:n,atts:a,d:u,dismissPrompt:s})}catch(d){throw await wn(i,u,Ta(d)),d}}async function Z2(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await SI(t,n,r,o),Ua(e,"say");let c=await be(t.leadBox);if(c&&await ey(c)?await Vc(t,n,"say")?(await ae(),c=await be(t.leadBox)):c=null:!c&&await Qc(t)&&(await ae(),c=await be(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=jc.get(e);l&&await l.catch(()=>{});let u=mp(e),d=await De(t.leadBox,{lines:Xe}).catch(()=>""),p=u.items.length>0?"queue":Ui(n?.agent,d)?"busy":null,f=p!=null,w=i&&!o;if((!f||p==="queue"&&w)&&to(n?.agent,d)){let g=await ln(t.leadBox).catch(()=>d),y=Nn(n,g);if(f||(f=!!y,f&&(p="prompt")),y&&w&&y.dismissable){let x=await X2(t,n,y,a);x.gone&&p==="prompt"&&(d=x.pane,f=Ui(n?.agent,d),p=f?"busy":null)}}if(f){let g={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return u.items.push(g),Lg(e),o||Da(t,null),await ae(),await Sc(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:g.id,position:u.items.length,deliveryId:a.id}}let m;try{m=await _g(t,n,c,r,o,s,a)}catch(g){if(g?.code!=="cli-not-running"||!await Vc(t,n,"say-gate")||(await ae(),c=await be(t.leadBox),!c))throw g;m=await _g(t,n,c,r,o,s,a)}return await ae(),m?.queued?{ok:!0,leadBox:t.leadBox,queued:!0,id:m.id,position:m.position,deliveryId:a.id}:{ok:!0,leadBox:t.leadBox,deliveryId:a.id}}async function Ug(e,{hint:t}={}){let n=de(await Z(),e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it first`);let r=Dw(n.id);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o=n.boxes.find(i=>i.name===n.leadBox),s=String(t||"").trim()?String(t).trim().slice(0,40):"preview";DE(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${uI}
|
|
218
218
|
|
|
219
|
-
What to preview: ${String(t).trim()}`:
|
|
219
|
+
What to preview: ${String(t).trim()}`:uI;try{await qt(e,a,{kind:"spin-up-view"})}catch(i){throw Ud(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function hp(e){let t=de(await Z(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Wc.set(e,(Wc.get(e)||0)+1);let n=Xc(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Pa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=ja(t,r),await ae()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=oH(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,$r(Q2)]);let a=de(await Z(),e)||t;return{ok:!0,interrupted:s.result!=="no-session",stopped:s.result==="stopped"||s.result==="stopped-late",stopping:!s.result,dropped:n.length,restored:s.restored,draftRev:a.draftRev||0}}function AI(e){let t=Pa.get(e);return!!t&&!t.canceled}function Ua(e,t){let n=Pa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Hg(e){Ua(e,"track-ended"),Wc.delete(e),Xc(e,"track-ended")}function oH(e,{droppedCount:t,droppedTexts:n}){let r={startedAt:Date.now(),clicks:1,escSends:0,bgSends:0,queuedTexts:[...n],canceled:!1,cancelReason:null,result:null,restored:null},o;return r.settled=new Promise(s=>{o=s}),Pa.set(e,r),(async()=>{let s=de(await Z(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await be(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<eH&&!r.canceled;g++){await Ge(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let y of tH){await $r(y);let x=await De(s.leadBox,{lines:Xe}).catch(()=>"");if(!ea(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<rH&&!r.canceled&&(await $r(nH),!r.canceled);g++){let y=await De(s.leadBox,{lines:Xe}).catch(()=>"");if(!ea(a?.agent,y)){c=!0;break}await Ge(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=de(await Z(),e)||s,d=u?.boxes.find(g=>g.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await cH(u,d).catch(()=>null),p||(f=await dH(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await aH(u).catch(()=>null):null,m=[p||f,...r.queuedTexts].filter(Boolean);u&&m.length&&(r.restored=ja(u,m),await ae()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await sH(u||s,d,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await pe({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:d?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Pa.get(e)===r&&Pa.delete(e),o()}),r}async function sH(e,t,n){await C(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function aH(e){let t=_a(await q(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await C(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function cH(e,t){if(t?.agent!=="claude")return null;let n=[...e.events||[]].reverse().find(r=>r.type==="said"&&r.text);if(!n)return null;for(let r of iH){await $r(r);let o=await De(e.leadBox,{lines:Xe}).catch(()=>""),s=qi(t.agent,o);if(s&&Eu(n.text,s))return await TI(e.leadBox,t.agent,n.text.length+8),Ae(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function dH(e,t){if(t?.agent!=="claude")return null;let n=e.events||[],r=[...n].reverse().find(s=>s.type==="said"&&s.text);if(!r||r.kind||Date.now()-r.at>lH||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Ue(r.text))return null;for(let s of uH){await $r(s);let a;try{a=await ch(t,{})}catch{return null}if(bx(a,r))return null;let i=await De(e.leadBox,{lines:Xe}).catch(()=>"");if(qi(t.agent,i))return null}return Ae(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function pH(e,t,n,r=null){return Vi({sessionName:e.leadBox,agent:t?.agent,agentCmd:gs(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function TI(e,t,n,r=null){for(let o=0;o<3;o++){await Vs(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await $r(200);let s=await De(e,{lines:Xe}).catch(()=>""),a=qi(t,s);if(!a||r&&!Eu(r,a)&&!(t==="codex"&&$m(r,a)))return!0;n=a.length+8}return!1}function Da(e,t,{source:n}={}){e.draftRev=(e.draftRev||0)+1;let r=typeof t=="string"?t:"";return r.trim()?e.draft={text:r,updatedAt:Date.now(),...n?{source:n}:{}}:delete e.draft,e.draft||null}function ja(e,t){let n=[],r=o=>n.some(s=>Ue(s).includes(Ue(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Da(e,n.join(`
|
|
220
220
|
|
|
221
|
-
`),{source:"restore"})?.text??null:null}function
|
|
221
|
+
`),{source:"restore"})?.text??null:null}function mH(e,t){let n=Ue(t);if(!n)return!1;if(hs(e.id).some(o=>Ue(o.text)===n))return!0;let r=e.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>fH)break;if(!(s.type!=="said"||!s.text||Ue(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Wg(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=de(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=la(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&mH(r,s))return{ok:!0,draft:r.draft||null,rev:null,ignored:"already-sent"};if(typeof n=="number"&&n<(r.draftRev||0)&&!o.trim()&&r.draft?.text)return{ok:!0,draft:r.draft,rev:r.draftRev||0,ignored:"stale-clear"};if(typeof n=="number"&&n<(r.draftRev||0)&&r.draft?.source==="restore"){let i=r.draft.text;Ue(o).includes(Ue(i))?Da(r,o):Da(r,`${i}
|
|
222
222
|
|
|
223
|
-
${o}`,{source:"restore"})}else Pa(r,o);return await se(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Fg(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=ue(await ee(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await ke(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(d=>d.name===r.leadBox)?.agent||o.agent||"claude",i=FS(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await Ci(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await rr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ws(o.agent)});let u=await US(a,r.leadBox,i);return Se(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await se(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function yI(e){for(let t of e){if(!t||!await la(t))continue;let n=await bS(t).catch(()=>null);if(!n)continue;if((await V.stat(G.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Bt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:G.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function ls(e){let t=[];for(let n of Bt(e?.workspace)){if(!n?.dir)continue;let r=await Jo(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Yo(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function Ug(e){let t=e;typeof t=="string"&&!G.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Ns(t)??await ql(t));let n=await yI([t]);if(!n){let r=typeof e=="string"&&G.isAbsolute(e)&&!await V.stat(e).catch(()=>null);throw new Error(`tagged repo "${e}" is not a usable base (${r?"that path does not exist on this node \u2014 pick one of this node's repos or use owner/name":"need a primary checkout or a synced owner/name"})`)}return n}async function Q2(e,t,n,r){let o=`track/${Sp(t)}-${e}`,s=[];try{await V.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await Ug(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await $e(c).catch(()=>null),u=G.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${G.basename(c)}-${f}`;a.add(u);let d=G.join(n,u),p=await Zo(c);await Xo(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await Ua(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Tt(i.base,i.dir).catch(()=>{});throw await V.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function fp(e,t){let n=await ee(),r=ue(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await Ug(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await $e(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=G.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${G.basename(s)}-${p}`;let l=G.join(o.dir,c),u=await Zo(s);await km(s,o.branch)?await ec(s,l,o.branch):await Xo(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await Ua(o.dir,o.repos,o.branch),Se(r,"retagged",{action:"add",repo:a??s,name:c,workspace:Hg(o)}),await se(),d}async function hp(e,t){let n=await ee(),r=ue(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Dt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await Jo(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Yo(s.dir,s.baseRef).catch(()=>0);if(a||i>0)throw new Error(`"${s.name}" has work (${a?"uncommitted changes":`${i} commit${i===1?"":"s"} ahead of ${s.baseRef??"base"}`}) \u2014 ship or discard it first`);return await Tt(s.base,s.dir).catch(()=>{}),await V.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Ua(o.dir,o.repos,o.branch),Se(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:Hg(o)}),await se(),{removed:s.name}}async function ep(e,t){let n=await ee(),r=ue(n,e);r&&(r.reshape={...r.reshape||{},...t},await se())}async function eH(e){let t=await V.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await V.readFile(G.join(e,n),"utf8").catch(()=>"");if(jc(r))continue}return!0}try{let{stdout:n}=await sp("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function rI(e,t,n){let r=G.basename(e);n.has(r)&&t&&(r=t.replace("/","-"));for(let o=2;n.has(r);o++)r=`${G.basename(e)}-${o}`;return n.add(r),r}async function bI(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await Tt(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await bn(l)&&!await bn(u)&&await V.rename(l,u)};if(n==="worktree"&&s){let l=G.join(r,s);await bn(l)&&(await c(G.join(r,".bostrat"),G.join(l,".bostrat")),await tp(a,l,o))}if(n==="repo"&&i){let l=G.join(r,i);await bn(l)&&(await bn(o)&&await V.rm(o,{recursive:!0,force:!0}),await V.rename(l,o))}return await bn(o)?(await bn(r)&&(await c(G.join(r,".bostrat"),G.join(o,".bostrat")),await V.rm(r,{recursive:!0,force:!0})),n==="worktree"?await tp(a,o,r):await V.rename(o,r),!0):!1}async function Wg(e,t,{skipPermissions:n=!0}={}){let r=await ee(),o=ue(r,e);if(!o)throw kt(`track "${e}" not found`,404);if(o.archivedAt)throw kt("track is archived \u2014 unarchive it first");try{kp(o)}catch(g){throw Object.assign(g,{status:409})}if(o.kind==="setup")throw kt("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw kt("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=Ag.get(e);if(s&&!s.finishedAt)throw kt("a reshape is already running for this Track");let a=ms.get(e);if(a&&!a.finishedAt)throw kt("a lead handoff is running \u2014 retry when it settles");let i=rp.get(e);if(i&&!i.finishedAt)throw kt("a node transfer is running \u2014 retry when it settles");if(Zd.has(e))throw kt("an adopt is running for this Track \u2014 retry when it settles");for(let g of Dt.values())if(g.trackId===e&&!g.finishedAt)throw kt("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(g=>typeof g=="string"?g.trim():"").filter(Boolean);if(!c.length)throw kt("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let g of c){let y;try{y=await Ug(g)}catch(k){throw kt(k?.message||String(k),400)}if(l.some(k=>k.base===y))throw kt(`repo tagged twice: ${g}`,400);l.push({sel:g,base:y,slug:await $e(y).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let g=(u.repos??[]).filter(Boolean),y=g.filter(I=>!l.some(R=>R.base===I.base)),k=l.filter(I=>!g.some(R=>R.base===I.base));if(!y.length&&!k.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let I of y){let R=await Jo(I.dir,{ignorePlumbing:!0}).catch(()=>!1),N=await Yo(I.dir,I.baseRef).catch(()=>0);if(R||N>0)throw kt(`"${I.name}" has work \u2014 ship or discard it before dropping it`)}let b={trackId:e,step:"retag",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:null,error:null};for(let I of k){let R=await fp(e,I.base);b.added.push(R.repo??R.base)}for(let I of y)await hp(e,I.name),b.removed.push(I.repo??I.base);return b.step="done",b.finishedAt=Date.now(),b}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw kt(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(g=>g.base===u.base);if(u.kind==="worktree"&&!d){let g=await Jo(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),y=await Yo(u.dir??o.cwd,u.baseRef).catch(()=>0);if(g||y>0)throw kt(`"${G.basename(u.base)}" has work (${g?"uncommitted changes":`${y} commit${y===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}Fa(e,"reshape");let p=o.boxes.find(g=>g.name===o.leadBox)||null;if(!p)throw kt("this Track has no lead box");let f=p.agent||"claude",w=await La(f,n),h={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(g=>!(u.kind==="worktree"&&g.base===u.base)).map(g=>g.slug??g.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return Ag.set(e,h),await ep(e,{step:h.step,startedAt:h.startedAt,finishedAt:null,error:null,added:h.added,removed:h.removed,layout:null}),tH(h,o,{desired:l,keep:d,lead:p,agent:f,agentCmd:w,skipPermissions:n}).catch(async g=>{h.error=g?.message||String(g),h.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${h.step}": ${h.error}`),await ep(e,{step:h.step,error:h.error,finishedAt:h.finishedAt}).catch(()=>{})}),h}async function tH(e,t,{desired:n,keep:r,lead:o,agent:s,agentCmd:a,skipPermissions:i}){let c=e.trackId,l=t.workspace,u=t.cwd,d=async(S,_={})=>{e.step=S,console.log(`[reshape ${c}] step \u2192 ${S}`),await ep(c,{step:S,..._})},p=await ke(o.name).catch(()=>null),f=o.sessionId??p?.sessionId??null,w=o.pinned===!0;if(await d("checkpoint"),e.checkpoint="llm",!p)e.checkpoint="skipped-dead";else if(eo(s))e.checkpoint="skipped-capped";else try{await Pu(o.name,{timeoutMs:_g})}catch{e.checkpoint="reconstructed"}let h=null;e.checkpoint!=="llm"&&(h=await Du(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await jw(c).catch(()=>0),await Ql(u).catch(()=>{}),p&&(await Kh(o.name,{fromAgent:s}).catch(()=>{}),await Mt(o.name).catch(()=>{}));let g=`${u}.reshape-${Date.now()}`,y=new Set([".bostrat"]),k={shape:l.kind,dir:u,staging:g,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?rI(l.base,l.repo??null,y):null,scratch:null},b=l.branch||`track/${Sp(t.name||c)}-${c}`,I=[],R=[],N=null;try{if(await d("move",{layout:k}),l.kind==="worktree")if(await tp(l.base,u,g),await V.mkdir(u,{recursive:!0}),r){let _=G.join(u,k.sub);await tp(l.base,g,_),await bn(G.join(_,".bostrat"))&&await V.rename(G.join(_,".bostrat"),G.join(u,".bostrat"));let H=G.join(_,"AGENTS.md");jc(await V.readFile(H,"utf8").catch(()=>null))&&(await V.rm(H,{force:!0}).catch(()=>{}),await vI(_,"/AGENTS.md").catch(()=>{})),I.push({name:k.sub,dir:_,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await bn(G.join(g,".bostrat"))&&await V.rename(G.join(g,".bostrat"),G.join(u,".bostrat"));else await V.rename(u,g),await V.mkdir(u,{recursive:!0}),await bn(G.join(g,".bostrat"))&&await V.rename(G.join(g,".bostrat"),G.join(u,".bostrat"));await d("materialize");for(let _ of n){if(l.kind==="worktree"&&_.base===l.base)continue;let H=rI(_.base,_.slug,y),K=G.join(u,H),X=await Zo(_.base);await km(_.base,b)?await ec(_.base,K,b):await Xo(_.base,K,b,X);let pe={name:H,dir:K,base:_.base,baseRef:X,repo:_.slug};I.push(pe),R.push(pe)}if(l.kind==="repo"&&await eH(g)){let _="scratch";for(let H=2;y.has(_);H++)_=`scratch-${H}`;y.add(_),k.scratch=_,await ep(c,{layout:k}),await V.rename(g,G.join(u,_)),e.scratch=!0}await Ua(u,I,b,{scratch:k.scratch}),await d("relaunch"),N=await $n(o.name,u,{agentCmd:a,agent:s}),await rr({cwd:u,sessionName:o.name,agent:s,agentCmd:ws(s)}).catch(_=>{if(_?.code!=="cli-not-running")throw _});let S=await Pe(o.name,{lines:et}).catch(()=>"");if(!Ho(s,S))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(S){await d("rollback",{error:S?.message||String(S)}),await Mt(o.name).catch(()=>{}),await bI(k,{added:R}).catch(X=>{console.error(`[reshape ${c}] rollback move failed: ${X?.message||X}`)});let _=await ee(),H=ue(_,c),K=H?.boxes.find(X=>X.name===o.name)||null;try{let X=ip(s,f,{skipPermissions:i,cwd:u,peerName:o.name}),pe=await $n(o.name,u,{agentCmd:X,agent:s,resumeSessionId:f,pinned:w});K&&(K.hookTokenHash=Ro(pe.hookToken),K.state="live"),Wo({cwd:u,sessionName:o.name,agent:s,agentCmd:X})}catch(X){console.error(`[reshape ${c}] rollback relaunch failed: ${X?.message||X}`)}throw H&&(Se(H,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:S?.message||String(S),rolledBack:!0}),H.reshape={...H.reshape||{},step:"error",error:S?.message||String(S),finishedAt:Date.now(),recovered:"rolled-back"},await se()),e.step="error",e.recovered="rolled-back",e.error=S?.message||String(S),e.finishedAt=Date.now(),S}await d("commit");let D=await ee(),j=ue(D,c);if(!j)throw new Error(`track "${c}" vanished mid-reshape`);let T=j.boxes.find(S=>S.name===o.name);if(!T)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let $=Date.now(),F=ho(T),J=F[F.length-1];J.endedAt==null&&(J.endedAt=$),J.endReason==null&&(J.endReason="reshape");let M=await Ko({agent:s,agentCmd:a});F.push({agent:s,sessionId:N.sessionId,pinned:N.pinned===!0,cliVersion:M,startedAt:$,endedAt:null}),T.cwd=u,T.agent=s,T.cliVersion=M,T.sessionId=N.sessionId,T.pinned=N.pinned===!0,T.hookTokenHash=Ro(N.hookToken),T.state="live",T.role="lead",delete T.readyAt,j.cwd=u,j.workspace={dir:u,kind:"multi",branch:b,repos:I},j.pendingHandoffHydrate={artifact:h||mo,at:$},Se(j,"retagged",{action:"reshape",added:e.added,removed:e.removed,scratch:e.scratch,checkpoint:e.checkpoint,views:e.views,box:o.name,agent:s,fromSessionId:f,toSessionId:N.sessionId,epoch:F.length-1,workspace:Hg(j.workspace)}),j.reshape={...j.reshape||{},step:"done",finishedAt:$,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await se(),Wo({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{T.readyAt||(T.readyAt=Date.now(),await se())}}),await bn(g)&&(l.kind==="worktree"&&await Tt(l.base,g).catch(()=>{}),await V.rm(g,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=$}async function qg(){let e=await ee(),t=0;for(let n of e.tracks||[]){let r=n.reshape;if(!r||r.finishedAt)continue;t++;let o=n.boxes.find(c=>c.name===n.leadBox)||null;o&&await Mt(o.name).catch(()=>{});let s=!1,a=null;if(r.layout)try{let{dir:c,sub:l,scratch:u}=r.layout,d=new Set([".bostrat",l,u].filter(Boolean)),p=[];for(let f of await V.readdir(c).catch(()=>[])){if(d.has(f))continue;let w=G.join(c,f),h=await V.readFile(G.join(w,".git"),"utf8").catch(()=>null),g=h&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(h);g&&p.push({base:g[1],dir:w})}s=await bI(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!Er.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Se(n,"retag-failed",{action:"reshape",box:n.leadBox,agent:o?.agent??null,reason:i,rolledBack:!a,recovered:!0}),n.reshape={...r,step:"error",error:i,finishedAt:Date.now(),recovered:a?"rollback-failed":"rolled-back",layout:null}}return t&&await se(),t}async function nH(e,t,{repo:n,repos:r,cwd:o}={}){await V.mkdir(Lc,{recursive:!0});let s=G.join(Lc,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return Q2(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!G.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Ns(n)??await ql(n));let i=await yI([n,o,f2]);if(i){let c=`track/${Sp(t)}-${e}`;try{let l=await Zo(i);await Xo(i,s,c,l),await Wc(s);let u=await $e(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await V.mkdir(s,{recursive:!0}),await xm(s),await Wc(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Wc(e){try{await V.writeFile(G.join(e,"AGENTS.md"),Bc,{flag:"wx"})}catch{return}await aH(e,["/AGENTS.md"])}function sH(e,t,{scratch:n=null}={}){let r=e.map(s=>`- \`${s.name}/\`${s.repo?` \u2014 github.com/${s.repo}`:""}${s.baseRef?` (forked from ${s.baseRef})`:""}`).join(`
|
|
223
|
+
${o}`,{source:"restore"})}else Da(r,o);return await ae(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function qg(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=de(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await be(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(d=>d.name===r.leadBox)?.agent||o.agent||"claude",i=zS(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await Pi(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await sr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:gs(o.agent)});let u=await JS(a,r.leadBox,i);return Ae(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ae(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function EI(e){for(let t of e){if(!t||!await ua(t))continue;let n=await _S(t).catch(()=>null);if(!n)continue;if((await V.stat(G.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function jt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:G.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function us(e){let t=[];for(let n of jt(e?.workspace)){if(!n?.dir)continue;let r=await Yo(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Xo(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function Kg(e){let t=e;typeof t=="string"&&!G.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Ps(t)??await Vl(t));let n=await EI([t]);if(!n){let r=typeof e=="string"&&G.isAbsolute(e)&&!await V.stat(e).catch(()=>null);throw new Error(`tagged repo "${e}" is not a usable base (${r?"that path does not exist on this node \u2014 pick one of this node's repos or use owner/name":"need a primary checkout or a synced owner/name"})`)}return n}async function hH(e,t,n,r){let o=`track/${Ep(t)}-${e}`,s=[];try{await V.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await Kg(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Re(c).catch(()=>null),u=G.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${G.basename(c)}-${f}`;a.add(u);let d=G.join(n,u),p=await Qo(c);await Zo(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await Ha(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Et(i.base,i.dir).catch(()=>{});throw await V.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function wp(e,t){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await Kg(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Re(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=G.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${G.basename(s)}-${p}`;let l=G.join(o.dir,c),u=await Qo(s);await Ah(s,o.branch)?await nc(s,l,o.branch):await Zo(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await Ha(o.dir,o.repos,o.branch),Ae(r,"retagged",{action:"add",repo:a??s,name:c,workspace:Gg(o)}),await ae(),d}async function gp(e,t){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Bt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await Yo(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Xo(s.dir,s.baseRef).catch(()=>0);if(a||i>0)throw new Error(`"${s.name}" has work (${a?"uncommitted changes":`${i} commit${i===1?"":"s"} ahead of ${s.baseRef??"base"}`}) \u2014 ship or discard it first`);return await Et(s.base,s.dir).catch(()=>{}),await V.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Ha(o.dir,o.repos,o.branch),Ae(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:Gg(o)}),await ae(),{removed:s.name}}async function rp(e,t){let n=await Z(),r=de(n,e);r&&(r.reshape={...r.reshape||{},...t},await ae())}async function wH(e){let t=await V.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await V.readFile(G.join(e,n),"utf8").catch(()=>"");if(Fc(r))continue}return!0}try{let{stdout:n}=await cp("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function dI(e,t,n){let r=G.basename(e);n.has(r)&&t&&(r=t.replace("/","-"));for(let o=2;n.has(r);o++)r=`${G.basename(e)}-${o}`;return n.add(r),r}async function _I(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await Et(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await bn(l)&&!await bn(u)&&await V.rename(l,u)};if(n==="worktree"&&s){let l=G.join(r,s);await bn(l)&&(await c(G.join(r,".bostrat"),G.join(l,".bostrat")),await op(a,l,o))}if(n==="repo"&&i){let l=G.join(r,i);await bn(l)&&(await bn(o)&&await V.rm(o,{recursive:!0,force:!0}),await V.rename(l,o))}return await bn(o)?(await bn(r)&&(await c(G.join(r,".bostrat"),G.join(o,".bostrat")),await V.rm(r,{recursive:!0,force:!0})),n==="worktree"?await op(a,o,r):await V.rename(o,r),!0):!1}async function Vg(e,t,{skipPermissions:n=!0}={}){let r=await Z(),o=de(r,e);if(!o)throw bt(`track "${e}" not found`,404);if(o.archivedAt)throw bt("track is archived \u2014 unarchive it first");try{Sp(o)}catch(g){throw Object.assign(g,{status:409})}if(o.kind==="setup")throw bt("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw bt("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=Ig.get(e);if(s&&!s.finishedAt)throw bt("a reshape is already running for this Track");let a=ws.get(e);if(a&&!a.finishedAt)throw bt("a lead handoff is running \u2014 retry when it settles");let i=ap.get(e);if(i&&!i.finishedAt)throw bt("a node transfer is running \u2014 retry when it settles");if(tp.has(e))throw bt("an adopt is running for this Track \u2014 retry when it settles");for(let g of Bt.values())if(g.trackId===e&&!g.finishedAt)throw bt("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(g=>typeof g=="string"?g.trim():"").filter(Boolean);if(!c.length)throw bt("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let g of c){let y;try{y=await Kg(g)}catch(x){throw bt(x?.message||String(x),400)}if(l.some(x=>x.base===y))throw bt(`repo tagged twice: ${g}`,400);l.push({sel:g,base:y,slug:await Re(y).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let g=(u.repos??[]).filter(Boolean),y=g.filter(I=>!l.some($=>$.base===I.base)),x=l.filter(I=>!g.some($=>$.base===I.base));if(!y.length&&!x.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let I of y){let $=await Yo(I.dir,{ignorePlumbing:!0}).catch(()=>!1),P=await Xo(I.dir,I.baseRef).catch(()=>0);if($||P>0)throw bt(`"${I.name}" has work \u2014 ship or discard it before dropping it`)}let b={trackId:e,step:"retag",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:null,error:null};for(let I of x){let $=await wp(e,I.base);b.added.push($.repo??$.base)}for(let I of y)await gp(e,I.name),b.removed.push(I.repo??I.base);return b.step="done",b.finishedAt=Date.now(),b}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw bt(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(g=>g.base===u.base);if(u.kind==="worktree"&&!d){let g=await Yo(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),y=await Xo(u.dir??o.cwd,u.baseRef).catch(()=>0);if(g||y>0)throw bt(`"${G.basename(u.base)}" has work (${g?"uncommitted changes":`${y} commit${y===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}Ua(e,"reshape");let p=o.boxes.find(g=>g.name===o.leadBox)||null;if(!p)throw bt("this Track has no lead box");let f=p.agent||"claude",w=await Fa(f,n),m={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(g=>!(u.kind==="worktree"&&g.base===u.base)).map(g=>g.slug??g.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return Ig.set(e,m),await rp(e,{step:m.step,startedAt:m.startedAt,finishedAt:null,error:null,added:m.added,removed:m.removed,layout:null}),gH(m,o,{desired:l,keep:d,lead:p,agent:f,agentCmd:w,skipPermissions:n}).catch(async g=>{m.error=g?.message||String(g),m.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${m.step}": ${m.error}`),await rp(e,{step:m.step,error:m.error,finishedAt:m.finishedAt}).catch(()=>{})}),m}async function gH(e,t,{desired:n,keep:r,lead:o,agent:s,agentCmd:a,skipPermissions:i}){let c=e.trackId,l=t.workspace,u=t.cwd,d=async(A,M={})=>{e.step=A,console.log(`[reshape ${c}] step \u2192 ${A}`),await rp(c,{step:A,...M})},p=await be(o.name).catch(()=>null),f=o.sessionId??p?.sessionId??null,w=o.pinned===!0;if(await d("checkpoint"),e.checkpoint="llm",!p)e.checkpoint="skipped-dead";else if(no(s))e.checkpoint="skipped-capped";else try{await ju(o.name,{timeoutMs:Og})}catch{e.checkpoint="reconstructed"}let m=null;e.checkpoint!=="llm"&&(m=await Lu(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await Hw(c).catch(()=>0),await nu(u).catch(()=>{}),p&&(await Jm(o.name,{fromAgent:s}).catch(()=>{}),await Ct(o.name).catch(()=>{}));let g=`${u}.reshape-${Date.now()}`,y=new Set([".bostrat"]),x={shape:l.kind,dir:u,staging:g,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?dI(l.base,l.repo??null,y):null,scratch:null},b=l.branch||`track/${Ep(t.name||c)}-${c}`,I=[],$=[],P=null;try{if(await d("move",{layout:x}),l.kind==="worktree")if(await op(l.base,u,g),await V.mkdir(u,{recursive:!0}),r){let M=G.join(u,x.sub);await op(l.base,g,M),await bn(G.join(M,".bostrat"))&&await V.rename(G.join(M,".bostrat"),G.join(u,".bostrat"));let N=G.join(M,"AGENTS.md");Fc(await V.readFile(N,"utf8").catch(()=>null))&&(await V.rm(N,{force:!0}).catch(()=>{}),await RI(M,"/AGENTS.md").catch(()=>{})),I.push({name:x.sub,dir:M,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await bn(G.join(g,".bostrat"))&&await V.rename(G.join(g,".bostrat"),G.join(u,".bostrat"));else await V.rename(u,g),await V.mkdir(u,{recursive:!0}),await bn(G.join(g,".bostrat"))&&await V.rename(G.join(g,".bostrat"),G.join(u,".bostrat"));await d("materialize");for(let M of n){if(l.kind==="worktree"&&M.base===l.base)continue;let N=dI(M.base,M.slug,y),K=G.join(u,N),Y=await Qo(M.base);await Ah(M.base,b)?await nc(M.base,K,b):await Zo(M.base,K,b,Y);let fe={name:N,dir:K,base:M.base,baseRef:Y,repo:M.slug};I.push(fe),$.push(fe)}if(l.kind==="repo"&&await wH(g)){let M="scratch";for(let N=2;y.has(M);N++)M=`scratch-${N}`;y.add(M),x.scratch=M,await rp(c,{layout:x}),await V.rename(g,G.join(u,M)),e.scratch=!0}await Ha(u,I,b,{scratch:x.scratch}),await d("relaunch"),P=await $n(o.name,u,{agentCmd:a,agent:s}),await sr({cwd:u,sessionName:o.name,agent:s,agentCmd:gs(s)}).catch(M=>{if(M?.code!=="cli-not-running")throw M});let A=await De(o.name,{lines:Xe}).catch(()=>"");if(!Wo(s,A))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(A){await d("rollback",{error:A?.message||String(A)}),await Ct(o.name).catch(()=>{}),await _I(x,{added:$}).catch(Y=>{console.error(`[reshape ${c}] rollback move failed: ${Y?.message||Y}`)});let M=await Z(),N=de(M,c),K=N?.boxes.find(Y=>Y.name===o.name)||null;try{let Y=up(s,f,{skipPermissions:i,cwd:u,peerName:o.name}),fe=await $n(o.name,u,{agentCmd:Y,agent:s,resumeSessionId:f,pinned:w});K&&(K.hookTokenHash=Oo(fe.hookToken),K.state="live"),qo({cwd:u,sessionName:o.name,agent:s,agentCmd:Y})}catch(Y){console.error(`[reshape ${c}] rollback relaunch failed: ${Y?.message||Y}`)}throw N&&(Ae(N,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:A?.message||String(A),rolledBack:!0}),N.reshape={...N.reshape||{},step:"error",error:A?.message||String(A),finishedAt:Date.now(),recovered:"rolled-back"},await ae()),e.step="error",e.recovered="rolled-back",e.error=A?.message||String(A),e.finishedAt=Date.now(),A}await d("commit");let F=await Z(),B=de(F,c);if(!B)throw new Error(`track "${c}" vanished mid-reshape`);let T=B.boxes.find(A=>A.name===o.name);if(!T)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let _=Date.now(),U=wo(T),J=U[U.length-1];J.endedAt==null&&(J.endedAt=_),J.endReason==null&&(J.endReason="reshape");let R=await Go({agent:s,agentCmd:a});U.push({agent:s,sessionId:P.sessionId,pinned:P.pinned===!0,cliVersion:R,startedAt:_,endedAt:null}),T.cwd=u,T.agent=s,T.cliVersion=R,T.sessionId=P.sessionId,T.pinned=P.pinned===!0,T.hookTokenHash=Oo(P.hookToken),T.state="live",T.role="lead",delete T.readyAt,B.cwd=u,B.workspace={dir:u,kind:"multi",branch:b,repos:I},B.pendingHandoffHydrate={artifact:m||go,at:_},Ae(B,"retagged",{action:"reshape",added:e.added,removed:e.removed,scratch:e.scratch,checkpoint:e.checkpoint,views:e.views,box:o.name,agent:s,fromSessionId:f,toSessionId:P.sessionId,epoch:U.length-1,workspace:Gg(B.workspace)}),B.reshape={...B.reshape||{},step:"done",finishedAt:_,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await ae(),qo({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{T.readyAt||(T.readyAt=Date.now(),await ae())}}),await bn(g)&&(l.kind==="worktree"&&await Et(l.base,g).catch(()=>{}),await V.rm(g,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=_}async function zg(){let e=await Z(),t=0;for(let n of e.tracks||[]){let r=n.reshape;if(!r||r.finishedAt)continue;t++;let o=n.boxes.find(c=>c.name===n.leadBox)||null;o&&await Ct(o.name).catch(()=>{});let s=!1,a=null;if(r.layout)try{let{dir:c,sub:l,scratch:u}=r.layout,d=new Set([".bostrat",l,u].filter(Boolean)),p=[];for(let f of await V.readdir(c).catch(()=>[])){if(d.has(f))continue;let w=G.join(c,f),m=await V.readFile(G.join(w,".git"),"utf8").catch(()=>null),g=m&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(m);g&&p.push({base:g[1],dir:w})}s=await _I(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!Ir.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Ae(n,"retag-failed",{action:"reshape",box:n.leadBox,agent:o?.agent??null,reason:i,rolledBack:!a,recovered:!0}),n.reshape={...r,step:"error",error:i,finishedAt:Date.now(),recovered:a?"rollback-failed":"rolled-back",layout:null}}return t&&await ae(),t}async function yH(e,t,{repo:n,repos:r,cwd:o}={}){await V.mkdir(Uc,{recursive:!0});let s=G.join(Uc,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return hH(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!G.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Ps(n)??await Vl(n));let i=await EI([n,o,$2]);if(i){let c=`track/${Ep(t)}-${e}`;try{let l=await Qo(i);await Zo(i,s,c,l),await Kc(s);let u=await Re(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await V.mkdir(s,{recursive:!0}),await Th(s),await Kc(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Kc(e){try{await V.writeFile(G.join(e,"AGENTS.md"),Lc,{flag:"wx"})}catch{return}await vH(e,["/AGENTS.md"])}function xH(e,t,{scratch:n=null}={}){let r=e.map(s=>`- \`${s.name}/\`${s.repo?` \u2014 github.com/${s.repo}`:""}${s.baseRef?` (forked from ${s.baseRef})`:""}`).join(`
|
|
224
224
|
`),o=n?`
|
|
225
225
|
\`${n}/\` is this Track's pre-repo workspace, carried over when the
|
|
226
226
|
Track was reshaped onto these repos. It is not part of any tagged repo and
|
|
227
227
|
cannot be shipped \u2014 move anything worth keeping into the repo it belongs to.
|
|
228
|
-
`:"";return`${
|
|
228
|
+
`:"";return`${kH}
|
|
229
229
|
|
|
230
230
|
This directory is NOT a git repo. It is a bostrat Track workspace holding one
|
|
231
231
|
git worktree per tagged repo, ALL on the same branch \`${t}\`:
|
|
@@ -237,20 +237,20 @@ push / open PRs) in each repo separately, always on that shared branch. Work
|
|
|
237
237
|
only needs to land in the repos it actually touches \u2014 an untouched repo's
|
|
238
238
|
branch simply stays at its fork point and never gets pushed. When asked to run
|
|
239
239
|
or preview an app, run it from that app's own repo directory.
|
|
240
|
-
${o}`}async function
|
|
240
|
+
${o}`}async function Ha(e,t,n,r={}){let o=xH(t,n,r);for(let s of["CLAUDE.md","AGENTS.md"])await V.writeFile(G.join(e,s),o).catch(()=>{})}async function $I(e){let{stdout:t}=await cp("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return G.resolve(e,t.trim())}async function vH(e,t){try{let n=await $I(e);await V.mkdir(G.dirname(n),{recursive:!0});let r=await V.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
|
|
241
241
|
`).includes(s));o.length&&await V.appendFile(n,(r.endsWith(`
|
|
242
242
|
`)||!r?"":`
|
|
243
243
|
`)+o.join(`
|
|
244
244
|
`)+`
|
|
245
|
-
`)}catch{}}async function
|
|
245
|
+
`)}catch{}}async function RI(e,t){try{let n=await $I(e),r=await V.readFile(n,"utf8"),o=r.split(`
|
|
246
246
|
`).filter(s=>s!==t);o.length!==r.split(`
|
|
247
247
|
`).length&&await V.writeFile(n,o.join(`
|
|
248
|
-
`))}catch{}}async function
|
|
248
|
+
`))}catch{}}async function Jg(){let e={refreshed:0,removed:0,codexGlobal:null};try{await V.mkdir(Vn,{recursive:!0}),await V.writeFile(G.join(Vn,"CLAUDE.md"),bH).catch(()=>{}),await V.writeFile(G.join(Vn,"AGENTS.md"),Lc).catch(()=>{});let t=process.env.CODEX_HOME||G.join(process.env.HOME||"/tmp",".codex");if((await V.stat(t).catch(()=>null))?.isDirectory()){let r=G.join(t,"AGENTS.md"),o=await V.readFile(r,"utf8").catch(()=>null);o===null?(await V.writeFile(r,vg,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Fc(o)&&o!==vg&&(await V.writeFile(r,vg).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Uc,La]){let o=await V.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=G.join(r,s.name),i=G.join(a,"AGENTS.md"),c=await V.readFile(i,"utf8").catch(()=>null);c!==null&&Fc(c)&&c!==Lc&&(await V.writeFile(i,Lc).catch(()=>{}),e.refreshed++);let l=G.join(a,"CLAUDE.md"),u=await V.readFile(l,"utf8").catch(()=>null);u!==null&&Fc(u)&&(await V.rm(l,{force:!0}).catch(()=>{}),await RI(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function OI(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of jt(t))n.base&&n.dir&&await Et(n.base,n.dir).catch(()=>{});await V.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Et(t.base,t.dir):await V.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function yp({name:e,cwd:t,repo:n,repos:r,agent:o="claude",model:s=null,skipPermissions:a=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let i=await Fa(o,a,s),c=Go({agent:o,agentCmd:i}),l=await Z(),u=ip().slice(0,8),d=await yH(u,e,{repo:n,repos:r,cwd:t}),p=new Set(l.tracks.flatMap(g=>(g.boxes||[]).map(y=>y.name))),f=`${e.trim()} lead`;p.has(hu(f))&&(f=`${e.trim().slice(0,50).trim()} ${u} lead`);let w=await $n(f,d.dir,{agentCmd:i,agent:o,freshWorkspace:!0}),m={id:u,name:e.trim(),cwd:w.cwd,workspace:d,leadBox:w.name,boxes:[sy(w,"lead","live")],events:[],createdAt:Date.now()};return m.boxes[0].cliVersion=await c,Ae(m,"opened",{agent:o,...s?{model:s}:{},box:w.name,cliVersion:m.boxes[0].cliVersion,skipPermissions:a,name:m.name,cwd:m.cwd,workspace:{base:d.base??null,branch:d.branch,kind:d.kind,...d.baseRef?{baseRef:d.baseRef}:{},...d.repo?{repo:d.repo}:{},...d.repos?{repos:d.repos.map(({name:g,base:y,baseRef:x,repo:b})=>({name:g,base:y,baseRef:x,repo:b}))}:{}}}),l.tracks.push(m),await ae(),qo({cwd:w.cwd,sessionName:w.name,agent:o,agentCmd:i,onBlocked:({message:g})=>yI(m.id,{box:w.name,agent:o,message:g}).catch(()=>{}),onReady:async()=>{let g=m.boxes.find(y=>y.name===m.leadBox);!g||g.readyAt||(g.readyAt=Date.now(),await ae())}}),Wt(m)}async function Yg({provider:e="claude",fresh:t=!1}={}){if(!SH.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await Z()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Wt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await ys(r.id).catch(()=>{})}let o=(await Fa(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=ip().slice(0,8),a=G.join(Vn,"setup",s);await V.mkdir(a,{recursive:!0});let i=await $n(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&qo({cwd:i.cwd,sessionName:i.name,agent:e,agentCmd:o});let c={id:s,name:`Connect ${e}`,kind:"setup",setup:{provider:e,startedAt:Date.now(),connectedAt:null},cwd:i.cwd,workspace:{dir:a,base:null,branch:null,kind:"scratch"},leadBox:i.name,boxes:[sy(i,"lead","live")],events:[],createdAt:Date.now()};return Ae(c,"opened",{agent:e,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await Z()).tracks.push(c),await ae(),Wt(c)}async function Xg(e,t,n){await nu(t.cwd).catch(()=>{}),await Hw(e).catch(()=>{});let r=ws.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ws.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of ks(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await hy(a).catch(()=>{}),Bt.delete(a.id);for(let a of Object.values(t.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await Z(),s=new Set((o.tracks||[]).filter(a=>a.id!==e&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of t.boxes)s.has(a.name)||await Ct(a.name).catch(()=>{})}async function Zg(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await Z(),o=r.tracks.findIndex(a=>a.id===e);if(o===-1)throw new Error(`track "${e}" not found`);let s=r.tracks[o];return t||await l_(s),Hg(e),await Xg(e,s,"track deleted"),n?await F_(e).catch(()=>{}):await L_(e).catch(()=>{}),await ZS(),await OI(s),t&&await u_(e).catch(()=>{}),t?await __(e).catch(()=>{}):await E_(s).catch(()=>{}),Ae(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ae(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function ys(e){let t=await Z(),n=de(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),Hg(e),Ae(n,"archived",{boxes:n.boxes.length}),await ae(),n.kind==="setup"?(await MI(e),Wt(n)):(Gc.add(e),EH(e).catch(()=>{}).finally(()=>Gc.delete(e)),{...await Wt(n),archiving:!0})}async function EH(e){try{await _H(e)}catch{}await MI(e).catch(()=>{})}async function MI(e){let t=await Z(),n=de(t,e);if(!(!n||!n.archivedAt)){await Xg(e,n,"track archived");for(let r of n.boxes)Ir.has(r.state)||(r.state="stopped");await ae()}}async function _H(e){let t=await Z(),n=de(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await be(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await yv(n.leadBox,i.cwd,{timeoutMs:TH})),s="lead-cli"}catch{}if(r||(r=Cv(n,await q(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await C(n,{type:"track.summary.recorded",actor:"orchestrator",source:"orchestrator",boxId:n.leadBox||null,provider:i?.agent||null,payload:o.length?{text:r,items:o,source:s}:{text:r,source:s}}).catch(()=>{}),await ae()}async function hr(e,t){let n=await ut(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Qg(n);if(r.length){for(let o of r)await ns(o.repo,o.number,!0).catch(()=>{});return!1}try{return await ys(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Qg(e){return(await mn().catch(()=>[])).filter(n=>n.trackId===e.trackId&&n.state!=="merged"&&n.state!=="closed"&&n.state!=="lost"&&!(n.repo===e.repo&&n.number===e.number))}async function wr(e,t){return bp(e,t,"merged")}async function bs(e,t){let n=await ut(e,t).catch(()=>null);if(!n?.trackId)return null;let r={repo:n.repo??null,number:n.number,title:n.title??null,url:n.url??null},o=await Qg(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await OA(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=de(await Z(),n.trackId);if(!a)return null;let i=s[0];return yc(await Wt(a),"pr.merged",{repo:n.repo??a.workspace?.repo??null,prs:s,prNumber:i?.number??null,prTitle:i?.title??null,prUrl:i?.url??null}).catch(()=>null)}async function bp(e,t,n="merged"){let r=await ut(e,t).catch(()=>null);if(!r?.notifyOnMerge||r.archiveOnMerge||!r.trackId)return!1;let o={repo:r.repo??null,number:r.number,title:r.title??null,url:r.url??null,headRef:r.headRef??null,outcome:n},s=await Qg(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await RA(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await xA(r.repo,r.number).catch(()=>!0))return!1;try{return await qt(r.trackId,CI(a),{kind:"merge-notify"}),!0}catch{return await rs(r.repo,r.number,!0).catch(()=>{}),!1}}function CI(e){let t=i=>`${i.repo?`${i.repo}`:""}#${i.number}${i.title?` "${i.title}"`:""}${i.url?` (${i.url})`:""}`;if(e.length===1){let i=e[0],c=`#${i.number}${i.title?` "${i.title}"`:""}`;return i.outcome!=="merged"?`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} was ${pI[i.outcome]??i.outcome}. This is an automated notification: the work did NOT land \u2014 check whether it still needs to ship another way. If not, say so briefly.`:`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} has merged. This is an automated merge notification: pick up whatever follow-up work this merge unblocks (dependent tasks, cleanup, next steps that were waiting on it). If nothing needs doing, say so briefly.`}let n=e.filter(i=>i.outcome==="merged"),r=e.filter(i=>i.outcome!=="merged"),o=r.length?`${n.length} of the ${e.length} PRs on this Track merged; ${r.length} did not land:`:`All ${e.length} PRs on this Track have merged:`,s=e.map(i=>`- ${t(i)} \u2014 ${pI[i.outcome]??i.outcome}`).join(`
|
|
249
249
|
`),a=n.length?r.length?`This is an automated merge notification: pick up whatever follow-up work the merged PR${n.length===1?"":"s"} unblock${n.length===1?"s":""} \u2014 and note the unmerged one${r.length===1?"":"s"}: that work did NOT land, so check whether it still needs to ship. If nothing needs doing, say so briefly.`:"This is an automated merge notification: pick up whatever follow-up work these merges unblock (dependent tasks, cleanup, next steps that were waiting on them). If nothing needs doing, say so briefly.":"This is an automated notification: NONE of the PRs landed \u2014 the work did not ship. Check whether it still needs to go out another way. If not, say so briefly.";return`${o}
|
|
250
250
|
${s}
|
|
251
|
-
${a}`}async function Yg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<Oi()?!1:nr(e.name)}async function Kc(e,t,n){return!t||e.archivedAt||Er.has(t.state)?!1:(await de({flow:"rehydrate",phase:"resume-dead-cli",trackId:e.id,sessionName:t.name,agent:t.agent,via:n}).catch(()=>{}),console.warn(`[track] ${t.name}: CLI is not running (bare shell) \u2014 relaunching (${n})`),await Mt(t.name).catch(()=>{}),t.state="stopped",Xc(e))}async function Xc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=bg.get(r.name);if(o)return o;let s=pH(e,r,{freshSession:t,reason:n}).finally(()=>bg.delete(r.name));return bg.set(r.name,s),s}async function pH(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||Er.has(t.state)||await ke(t.name))return!1;let o=n===!0,s=o?op():null,a=o?$i(Eg(t.agent),s,t.name):ip(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await du(a);if(i===qs)return Se(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Ks&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);let c=o?{sessionId:t.sessionId??null,pinned:t.pinned===!0,epochs:JSON.parse(JSON.stringify(ho(t)))}:null,l=Date.now();if(o){let u=ho(t),d=u[u.length-1];d.endedAt==null&&(d.endedAt=l),d.endReason==null&&(d.endReason=r||"fresh-session"),u.push({agent:t.agent,sessionId:s,pinned:t.agent==="claude",startedAt:l,endedAt:null}),t.sessionId=s,t.pinned=t.agent==="claude"}try{let u=Ko({agent:t.agent,agentCmd:a}),d=await $n(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Ro(d.hookToken),t.cliVersion=await u,ho(t)[t.epochs.length-1].cliVersion=t.cliVersion,Wo({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a,onBlocked:({message:p})=>uI(e.id,{box:t.name,agent:t.agent,message:p}).catch(()=>{})}),t.state="live",o&&Se(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session",cliVersion:t.cliVersion??null}),Se(e,"rehydrated",{box:t.name,agent:t.agent,...o?{fresh:!0}:{}}),!0}catch(u){return o&&(t.sessionId=c.sessionId,t.pinned=c.pinned,t.epochs=c.epochs),Se(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function gp(e,{freshSession:t=!1}={}){let n=await ee(),r=ue(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,qc.delete(e),Se(r,"unarchived",{}),await Xc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await se(),Wt(r)}async function Xg(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Tg)throw new Error(`name too long (max ${Tg} chars)`);let r=await ee(),o=ue(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return Wt(o);let s=o.name;return o.name=n,Se(o,"renamed",{from:s,to:n}),await se(),Wt(o)}async function Zg(){let e=await ee(),t=0;for(let n of e.tracks||[])n.transferredTo&&zu(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await se(),t}async function Qg(){let e=await ee(),t=new Set((await cn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!je(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(je(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Mt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Se(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Er.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await se(),r}async function yp(e,{freshSession:t=!1}={}){let n=await ee(),r=ue(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);kp(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(Er.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ke(r.leadBox)){let i=await Pe(r.leadBox,{lines:et}).catch(()=>"");if(Li(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Mt(r.leadBox),o.state="stopped"}let a=await Xc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await se(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Wt(r)}async function ey(e,t,n){let r=await le(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await q(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await yp(e),await C(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function sI(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return Td({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ho(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,cliVersion:e.cliVersion??null,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function np(e,t){let n=await ee(),r=ue(n,e);r&&(r.handoff={...r.handoff||{},...t},await se())}function EI(e,t=Date.now()){let n=e?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=e.boxes?.find?.(i=>i.name===e.leadBox)||null;return(o?e.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&e.leadBox===n.toBox)?{...n,step:"done",finishedAt:t,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${r}"; lead "${e.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function ny(){let e=await ee(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=EI(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await ke(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),d=ho(l),p=d[d.length-1],f=p.agent,w=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let h=c.agent==="claude"&&!!c.sessionId,g=await Ko({agent:r.toAgent});d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:h,cliVersion:g,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.cliVersion=g,l.sessionId=c.sessionId||null,l.pinned=h,l.state="live",n.pendingHandoffHydrate={artifact:mo,at:u},Se(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:f,toAgent:r.toAgent,fromSessionId:w,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await de({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:"done",recovered:n.handoff.recovered,fromBox:r.fromBox,toBox:r.toBox}).catch(()=>{});continue}}let a=!s&&o.recovered==="rolled-back"&&r.toBox&&r.toBox!==n.leadBox?r.toBox:null,i=!s&&o.step==="done"?r.fromBox:null;n.handoff=o,await de({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Mt(i).catch(()=>{}),a&&await Mt(a).catch(()=>{})}return t&&await se(),t}async function bp(e,t,n=!0,r=null){let o=ms.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=ue(await ee(),e);if(!s)throw new Error(`track "${e}" not found`);Fa(e,"handoff");let a=await La(t,n),i=eo(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await ke(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:dI(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ms.set(e,l),await np(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),fH(l,s,c,a,t).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${l.step}": ${l.error}`),await np(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),de({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),de({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function fH(e,t,n,r,o){let s=async(D,j={})=>{e.step=D,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${D}`),await np(e.trackId,{step:D,toBox:e.toBox}),await de({flow:"lead-handoff",phase:D,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:j.sessionName,...j})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await ee(),i=ue(a,e.trackId)?.boxes.find(D=>D.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",eo(c))e.checkpoint="skipped-capped";else try{await Pu(e.fromBox,{timeoutMs:_g})}catch(D){e.checkpoint="reconstructed",await de({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:D?.message||String(D)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Du(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let p=Ko({agent:o,agentCmd:r}),f=await Gh(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let w=cx(f.launchCmd);await rr({cwd:n.cwd,sessionId:f.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ws(o),launchEcho:w}).catch(D=>{if(D?.code!=="cli-not-running")throw D});let h=Sh(await Pe(e.fromBox,{lines:et}).catch(()=>""),w);if(!Ho(o,h)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let D=ip(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await Gh(e.fromBox,{agentCmd:D,agent:c,resumeSessionId:l,pinned:u});let j=await ee(),T=ue(j,e.trackId);if(T){let $=T.boxes.find(F=>F.name===e.fromBox);$&&($.state="live"),Se(T,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await se()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let g=await ee(),y=ue(g,e.trackId);if(!y)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let k=y.boxes.find(D=>D.name===e.fromBox);if(!k)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let b=Date.now(),I=ho(k),R=I[I.length-1];R.endedAt=b,e.reason&&(R.endReason=e.reason);let N=await p;I.push({agent:o,sessionId:f.sessionId,pinned:f.pinned,cliVersion:N,startedAt:b,endedAt:null}),k.agent=o,k.sessionId=f.sessionId,k.pinned=f.pinned,k.cliVersion=N,k.state="live",k.role="lead",y.pendingHandoffHydrate={artifact:e.statusArtifact||mo,at:b},Se(y,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:f.sessionId,epoch:I.length-1,singleBox:!0,forced:f.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,cliVersion:N,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await se(),await s("done",{sessionName:e.fromBox}),await np(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function sy(e){let t=rp.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await ee(),r=ue(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=ms.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Dt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return rp.set(e,s),hH(s,r).catch(a=>{s.error=a?.message||String(a),s.finishedAt=Date.now(),console.error(`[transfer-out ${e}] FAILED at step "${s.step}": ${s.error}`)}),s}async function hH(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await ke(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&eo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Pu(t.leadBox,{timeoutMs:_g})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Du(t.id,t.cwd,{trackName:t.name||t.id}).catch(()=>null),e.step="push";let o=t.workspace?.branch??null,s=[];if(o)for(let u of Bt(t.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await kn(u.dir,["push","origin",o],ry);let{stdout:p}=await kn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
|
|
252
|
-
`)[0]}s.push(d)}e.step="wip";let a=await
|
|
253
|
-
`)[0],advanced:null}}}function yH(e){if(typeof e!="string"||!gH.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function iy(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(e.branch!=null&&yH(e.branch),Zd.has(t))throw new Error("an adopt is already running for this Track");Zd.set(t,{startedAt:Date.now()});try{return await bH({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Zd.delete(t)}}async function bH({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,wips:u=null,brief:d=null,epochs:p=[],createdAt:f=null,leadBox:w=null,reason:h=null,downSince:g=null}){let y=await La(n,r),k=await ee(),b=ue(k,e);if(b&&!b.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);b&&(await ig(b).catch(()=>{}),await SI(b),k.tracks.splice(k.tracks.indexOf(b),1),await se()),await V.mkdir(Lc,{recursive:!0});let I=G.join(Lc,e);await V.rm(I,{recursive:!0,force:!0}).catch(()=>{});let R=null,N=!1,D=[];try{let j=[];if(i)for(let Z of Array.isArray(c)?c:[]){let me=typeof Z=="string"?Z:Z?.repo;if(!me||!/^[^/\s]+\/[^/\s]+$/.test(me))continue;let Te=await Ns(me)??await ql(me);await kn(Te,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],ry),j.push({slug:me,base:Te,name:typeof Z=="object"?Z?.name??null:null})}if(i&&j.length===1){let{base:Z,slug:me}=j[0];await aI(Z,I,i),D.push({base:Z,dir:I}),await Wc(I);let Te=await Zo(Z);R={dir:I,base:Z,branch:i,kind:"worktree",baseRef:Te,repo:me}}else if(i&&j.length>=2){await V.mkdir(I,{recursive:!0});let Z=new Set([".bostrat"]),me=[];for(let Te of j){let z=Te.name||G.basename(Te.base);Z.has(z)&&(z=Te.slug.replace("/","-"));for(let O=2;Z.has(z);O++)z=`${G.basename(Te.base)}-${O}`;Z.add(z);let ge=G.join(I,z);await aI(Te.base,ge,i),D.push({base:Te.base,dir:ge});let Ge=await Zo(Te.base);me.push({name:z,dir:ge,base:Te.base,baseRef:Ge,repo:Te.slug})}await Ua(I,me,i),R={dir:I,kind:"multi",branch:i,repos:me}}else N=!0,await V.mkdir(I,{recursive:!0}),await xm(I),await Wc(I),R={dir:I,base:null,branch:null,kind:"repo"};let T=[];for(let Z of mH(R,{wip:l,wips:u})){let me=await wH(Z.dir,e);T.push({name:Z.name,repo:Z.repo,applied:me.applied,skipped:me.skipped,...me.advanced?{advanced:me.advanced}:{}})}let $=T.some(Z=>Z.applied),F=T.length===1?T[0].skipped:T.filter(Z=>Z.skipped).map(Z=>`${Z.name??Z.repo}: ${Z.skipped}`).join("; ")||null,J=T.length===1?T[0].advanced??null:null;await G_({id:e,cwd:I}).catch(()=>({restored:!1}));let M=G.join(I,mo),S=null;(await ou(I)).restored?S="checkpoint":typeof d=="string"&&d.trim()&&(await V.mkdir(G.dirname(M),{recursive:!0}),await V.writeFile(M,d),S="brief");let H=new Set(k.tracks.flatMap(Z=>(Z.boxes||[]).map(me=>me.name))),K=null;w&&!H.has(w)&&!await ke(w).catch(()=>null)?K=w:(K=`${t.trim()} lead`,H.has(pu(K))&&(K=`${t.trim().slice(0,50).trim()} ${e} lead`));let X=await $n(K,I,{agentCmd:y,agent:n});Wo({cwd:X.cwd,sessionName:X.name,agent:n,agentCmd:y});let pe=Date.now(),Oe=ty(X,"lead","live"),Me=(Array.isArray(p)?p:[]).filter(Z=>Z&&typeof Z=="object").map(Z=>({...Z})),Q=Me[Me.length-1];Q&&Q.endedAt==null&&(Q.endedAt=pe,Q.endReason==null&&(Q.endReason=o==="recover"?"node-offline":"node-transfer"));let qe=await Ko({agent:n,agentCmd:y});Me.push({agent:n,sessionId:X.sessionId??null,pinned:X.pinned===!0,cliVersion:qe,startedAt:pe,endedAt:null}),Oe.epochs=Me,Oe.cliVersion=qe;let Ae={id:e,name:t.trim(),cwd:X.cwd,workspace:R,leadBox:X.name,boxes:[Oe],events:[],createdAt:Number.isFinite(f)?f:pe,...S?{pendingHandoffHydrate:{artifact:mo,at:pe}}:{}};return Se(Ae,"transferred-in",{box:X.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(g)?g:null}:{},branch:R.branch??null,wip:$,...J?{wipAdvanced:J}:{},...R.kind==="multi"&&T.length?{wipRepos:T}:{},epoch:Me.length-1,name:Ae.name,cwd:Ae.cwd,workspace:{base:R.base??null,branch:R.branch??null,kind:R.kind,...R.baseRef?{baseRef:R.baseRef}:{},...R.repo?{repo:R.repo}:{},...R.repos?{repos:R.repos.map(({name:Z,base:me,baseRef:Te,repo:z})=>({name:Z,base:me,baseRef:Te,repo:z}))}:{}}}),k.tracks.push(Ae),await se(),{...await Wt(Ae),adopt:{wipApplied:$,wipSkipped:F,...J?{wipAdvanced:J}:{},...R.kind==="multi"?{wipRepos:T}:{},codeless:N,artifactSource:S}}}catch(j){for(let T of D)await Tt(T.base,T.dir).catch(()=>{});throw await V.rm(I,{recursive:!0,force:!0}).catch(()=>{}),j}}async function _I(e,t,n){let r=await ee(),o=ue(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await se())}async function Ca(e,t){e.step=t,await Zc(e)}function II(e,t=Date.now()){if(!e||e.finishedAt)return null;let n=e.step;return["snapshot","spawn","working"].includes(n)?{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; no changes were applied to the lead \u2014 retry the delegation`,recovered:"rolled-back"}:{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; the lead's working tree may hold a PARTIAL merge \u2014 review git status. The subtask's work is preserved on branch ${e.branch}`,recovered:"partial-merge"}}function $I(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function SH(e,t,n){if(!$I(n)||Dt.has(t)||!await ke(n.box).catch(()=>null))return!1;try{await V.access(n.dir)}catch{return!1}let o=await ke(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Dt.set(t,s),OI(s,o).catch(a=>RI(s,a)),!0}async function cy(){let e=await ee(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Dt.has(r))continue;if(await SH(n,r,o)){t=!0,Se(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await de({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=II(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Er.has(i.state)&&(i.state="canceled"),Se(n,"subtask-failed",{from:o.box,fromAgent:o.agent,task:o.task,subtaskId:r,failedStep:s,error:a.error,recovered:a.recovered,durationMs:o.startedAt?a.finishedAt-o.startedAt:null}),await de({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await iI(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Er.has(r.state)||Dt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?G.join(ja,`${n.id}-${r.subtaskId}`):null;await de({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await iI(n,r.name,o)}}return t=await AH(e)||t,t&&await se(),t}async function iI(e,t,n){if(t&&await Mt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Bt(e.workspace)){let s=G.join(n,o.name);await Tt(o.base,s).then(()=>!0,()=>!1)||await Tt(o.dir,s).catch(()=>{})}await V.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ke(e.leadBox).catch(()=>null);r?.cwd&&await Tt(r.cwd,n).catch(()=>{})}async function AH(e){let t;try{t=await V.readdir(ja)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of Dt.values())o.dir&&n.add(G.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=G.join(ja,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Bt(a.workspace))await Tt(i.base,G.join(s,i.name)).catch(()=>{});await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ke(a.leadBox).catch(()=>null):null;i?.cwd?await Tt(i.cwd,s).catch(()=>{}):await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await de({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function ly(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!ca(n))throw new Error("task (string) required");let s=await La(t,r),a=eo(t);if(a){let f=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw f.usageCap=a,f}let i=ue(await ee(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await ke(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let f=Bt(i.workspace);if(!f.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let w of f)if(!w?.dir||!await la(w.dir))throw new Error(`tagged checkout "${w?.name??"?"}" is missing from the lead workspace (${w?.dir??"no dir"})`);u=f.map(w=>({name:w.name,leadDir:w.dir,base:null}))}else if(!await la(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=op().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:ca(n),skipPermissions:r,reason:dI(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${Sp(i.name)}-${d}`,base:null,repos:u,dir:G.join(ja,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Dt.set(d,p),await Zc(p),TH(p,c,s).catch(f=>RI(p,f)),p}async function RI(e,t){e.failedStep=e.step,e.error=t instanceof Gc?"canceled":t?.message||String(t),e.step=t instanceof Gc?"canceled":"error",e.finishedAt=Date.now(),await dy(e).catch(()=>{}),await Zc(e).catch(()=>{}),await $H(e).catch(()=>{})}function Ap(e){let t=Dt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");return t.canceled=!0,t}function uy(e){let t=Dt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");if(t.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${t.step})`);return t.forceMerge=!0,t}async function TH(e,t,n){if(await Ca(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await ua(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Zc(e)}else e.base=await ua(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Ca(e,"spawn"),await V.mkdir(ja,{recursive:!0}),e.repos){await V.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Xo(a.leadDir,G.join(e.dir,a.name),e.branch,a.base);let s=Bt((ue(await ee(),e.trackId)||{}).workspace);await Ua(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch)}else await Xo(t.cwd,e.dir,e.branch,e.base),await Wc(e.dir);await EH(e,t);let r=e.trackName.slice(0,38).trim(),o=await $n(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await _H(e,o),await pI(e.trackId,o.name,m2(e.task,!!e.repos),{kind:"subtask"}),await OI(e,t)}async function OI(e,t){await Ca(e,"working");let n=G.join(e.dir,Qd);if(await OH(n,e),e.canceled)throw new Gc;if(await Ca(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=G.join(e.dir,l.name);await bm(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:sI({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Sm(l.leadDir,l.base,e.branch,Ma),l.files=await Am(l.leadDir,l.base,e.branch,Ma);let d=await Tm(l.leadDir,l.base,e.branch,Ma);l.applied=d.applied,l.conflicts=d.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(p=>G.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:G.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await bm(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:sI({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Sm(t.cwd,e.base,e.branch,Ma),e.files=await Am(t.cwd,e.base,e.branch,Ma);let s=await Tm(t.cwd,e.base,e.branch,Ma);e.applied=s.applied,e.conflicts=s.conflicts}await Zc(e);let r=await RH(e,t,n);await Ca(e,"resume"),await pI(e.trackId,e.leadBox,w2(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Ca(e,"reap"),await dy(e),e.step="done";let o=Date.now();await _I(e.trackId,e.id,{...vp(e),finishedAt:o}),await IH(e,o),e.finishedAt=o}async function EH(e,t){let n=G.join(e.dir,G.dirname(Fc));await V.mkdir(n,{recursive:!0});let r="";try{r=await K0(t.cwd,t.sessionId)}catch{}if(!r)try{r=await V.readFile(G.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
|
|
251
|
+
${a}`}async function ey(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<Ci()?!1:or(e.name)}async function Vc(e,t,n){return!t||e.archivedAt||Ir.has(t.state)?!1:(await pe({flow:"rehydrate",phase:"resume-dead-cli",trackId:e.id,sessionName:t.name,agent:t.agent,via:n}).catch(()=>{}),console.warn(`[track] ${t.name}: CLI is not running (bare shell) \u2014 relaunching (${n})`),await Ct(t.name).catch(()=>{}),t.state="stopped",Qc(e))}async function Qc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=Sg.get(r.name);if(o)return o;let s=IH(e,r,{freshSession:t,reason:n}).finally(()=>Sg.delete(r.name));return Sg.set(r.name,s),s}async function IH(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||Ir.has(t.state)||await be(t.name))return!1;let o=n===!0,s=o?ip():null,a=o?Oi(Rg(t.agent),s,t.name):up(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await mu(a);if(i===Ks)return Ae(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Gs&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);let c=o?{sessionId:t.sessionId??null,pinned:t.pinned===!0,epochs:JSON.parse(JSON.stringify(wo(t)))}:null,l=Date.now();if(o){let u=wo(t),d=u[u.length-1];d.endedAt==null&&(d.endedAt=l),d.endReason==null&&(d.endReason=r||"fresh-session"),u.push({agent:t.agent,sessionId:s,pinned:t.agent==="claude",startedAt:l,endedAt:null}),t.sessionId=s,t.pinned=t.agent==="claude"}try{let u=Go({agent:t.agent,agentCmd:a}),d=await $n(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Oo(d.hookToken),t.cliVersion=await u,wo(t)[t.epochs.length-1].cliVersion=t.cliVersion,qo({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a,onBlocked:({message:p})=>yI(e.id,{box:t.name,agent:t.agent,message:p}).catch(()=>{})}),t.state="live",o&&Ae(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session",cliVersion:t.cliVersion??null}),Ae(e,"rehydrated",{box:t.name,agent:t.agent,...o?{fresh:!0}:{}}),!0}catch(u){return o&&(t.sessionId=c.sessionId,t.pinned=c.pinned,t.epochs=c.epochs),Ae(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function kp(e,{freshSession:t=!1}={}){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,Gc.delete(e),Ae(r,"unarchived",{}),await Qc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ae(),Wt(r)}async function ty(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>$g)throw new Error(`name too long (max ${$g} chars)`);let r=await Z(),o=de(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return Wt(o);let s=o.name;return o.name=n,Ae(o,"renamed",{from:s,to:n}),await ae(),Wt(o)}async function ny(){let e=await Z(),t=0;for(let n of e.tracks||[])n.transferredTo&&Xu(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ae(),t}async function ry(){let e=await Z(),t=new Set((await cn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Le(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Le(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Ct(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Ae(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Ir.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ae(),r}async function xp(e,{freshSession:t=!1}={}){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);Sp(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(Ir.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await be(r.leadBox)){let i=await De(r.leadBox,{lines:Xe}).catch(()=>"");if(Ui(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Ct(r.leadBox),o.state="stopped"}let a=await Qc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ae(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Wt(r)}async function oy(e,t,n){let r=await ue(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await q(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await xp(e),await C(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function fI(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return Id({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function wo(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,cliVersion:e.cliVersion??null,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function sp(e,t){let n=await Z(),r=de(n,e);r&&(r.handoff={...r.handoff||{},...t},await ae())}function NI(e,t=Date.now()){let n=e?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=e.boxes?.find?.(i=>i.name===e.leadBox)||null;return(o?e.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&e.leadBox===n.toBox)?{...n,step:"done",finishedAt:t,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${r}"; lead "${e.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function ay(){let e=await Z(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=NI(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await be(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),d=wo(l),p=d[d.length-1],f=p.agent,w=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let m=c.agent==="claude"&&!!c.sessionId,g=await Go({agent:r.toAgent});d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:m,cliVersion:g,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.cliVersion=g,l.sessionId=c.sessionId||null,l.pinned=m,l.state="live",n.pendingHandoffHydrate={artifact:go,at:u},Ae(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:f,toAgent:r.toAgent,fromSessionId:w,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await pe({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:"done",recovered:n.handoff.recovered,fromBox:r.fromBox,toBox:r.toBox}).catch(()=>{});continue}}let a=!s&&o.recovered==="rolled-back"&&r.toBox&&r.toBox!==n.leadBox?r.toBox:null,i=!s&&o.step==="done"?r.fromBox:null;n.handoff=o,await pe({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Ct(i).catch(()=>{}),a&&await Ct(a).catch(()=>{})}return t&&await ae(),t}async function vp(e,t,n=!0,r=null){let o=ws.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=de(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);Ua(e,"handoff");let a=await Fa(t,n),i=no(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await be(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:bI(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ws.set(e,l),await sp(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),$H(l,s,c,a,t).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${l.step}": ${l.error}`),await sp(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),pe({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),pe({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function $H(e,t,n,r,o){let s=async(F,B={})=>{e.step=F,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${F}`),await sp(e.trackId,{step:F,toBox:e.toBox}),await pe({flow:"lead-handoff",phase:F,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:B.sessionName,...B})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await Z(),i=de(a,e.trackId)?.boxes.find(F=>F.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",no(c))e.checkpoint="skipped-capped";else try{await ju(e.fromBox,{timeoutMs:Og})}catch(F){e.checkpoint="reconstructed",await pe({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:F?.message||String(F)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Lu(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let p=Go({agent:o,agentCmd:r}),f=await Ym(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let w=wx(f.launchCmd);await sr({cwd:n.cwd,sessionId:f.sessionId,sessionName:e.fromBox,agent:o,agentCmd:gs(o),launchEcho:w}).catch(F=>{if(F?.code!=="cli-not-running")throw F});let m=_m(await De(e.fromBox,{lines:Xe}).catch(()=>""),w);if(!Wo(o,m)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let F=up(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await Ym(e.fromBox,{agentCmd:F,agent:c,resumeSessionId:l,pinned:u});let B=await Z(),T=de(B,e.trackId);if(T){let _=T.boxes.find(U=>U.name===e.fromBox);_&&(_.state="live"),Ae(T,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await ae()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let g=await Z(),y=de(g,e.trackId);if(!y)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let x=y.boxes.find(F=>F.name===e.fromBox);if(!x)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let b=Date.now(),I=wo(x),$=I[I.length-1];$.endedAt=b,e.reason&&($.endReason=e.reason);let P=await p;I.push({agent:o,sessionId:f.sessionId,pinned:f.pinned,cliVersion:P,startedAt:b,endedAt:null}),x.agent=o,x.sessionId=f.sessionId,x.pinned=f.pinned,x.cliVersion=P,x.state="live",x.role="lead",y.pendingHandoffHydrate={artifact:e.statusArtifact||go,at:b},Ae(y,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:f.sessionId,epoch:I.length-1,singleBox:!0,forced:f.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,cliVersion:P,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ae(),await s("done",{sessionName:e.fromBox}),await sp(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function ly(e){let t=ap.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=ws.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Bt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return ap.set(e,s),RH(s,r).catch(a=>{s.error=a?.message||String(a),s.finishedAt=Date.now(),console.error(`[transfer-out ${e}] FAILED at step "${s.step}": ${s.error}`)}),s}async function RH(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await be(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&no(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await ju(t.leadBox,{timeoutMs:Og})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Lu(t.id,t.cwd,{trackName:t.name||t.id}).catch(()=>null),e.step="push";let o=t.workspace?.branch??null,s=[];if(o)for(let u of jt(t.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await kn(u.dir,["push","origin",o],iy);let{stdout:p}=await kn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
|
|
252
|
+
`)[0]}s.push(d)}e.step="wip";let a=await ug(t,{force:!0}),i=await Z(),c=de(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&wo(l),await ae(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:d,baseSha:p})=>({name:u,repo:d,baseSha:p})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:p})=>({name:u,repo:d,error:p})),wip:a.pushed[0]?{ref:a.pushed[0].ref,sha:a.pushed[0].sha}:null,wips:a.pushed,wipSkipped:a.skipped,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function Sp(e){if(!e?.transferredTo)return;let t=new Error(`track "${e.id}" moved to node ${e.transferredTo} \u2014 drive it there`);throw t.transferredTo=e.transferredTo,t}async function Ap(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Z(),o=de(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Hg(e),await Xg(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Xu(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await dg(o,{ts:s}),i=a.pushed[0]??null;return o.transferredTo=t,o.transferredAt=s,Ae(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...i?{rescueRef:i.ref,rescueSha:i.sha}:{},...a.pushed.length?{rescues:a.pushed}:{}}),await ae(),{ok:!0,toNode:t,rescue:i?{ref:i.ref,sha:i.sha}:null,rescues:a.pushed}}async function uy(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Ap(n.id,{toNode:n.toNode,mode:n.mode==="recover"?"recover":"transfer"});t.push({id:n.id,...r})}catch(r){/not found/i.test(String(r?.message))||console.error(`[transfer] demote of ${n.id} failed: ${r?.message||r}`)}return t}async function mI(e,t,n){try{await nc(e,t,n)}catch{await kn(e,["worktree","prune"]).catch(()=>{}),await nc(e,t,n)}return t}function OH(e,{wip:t=null,wips:n=null}={}){let r=jt(e).filter(a=>a?.dir),o=Array.isArray(n)?n.filter(a=>a?.sha):[];if(!o.length)return t?.sha&&r.length===1?r:[];let s=r.filter(a=>o.some(i=>i.repo?i.repo===a.repo:i.name!=null&&i.name===a.name));return!s.length&&r.length===1&&o.length===1?r:s}async function MH(e,t){try{await kn(e,["fetch","origin",lg(t)],iy);let{stdout:n}=await kn(e,["rev-parse","FETCH_HEAD^"]),{stdout:r}=await kn(e,["rev-parse","HEAD"]),o=null,s=n.trim()===r.trim();return s||await kn(e,["merge-base","--is-ancestor",r.trim(),n.trim()]).then(()=>!0,()=>!1)&&(await kn(e,["reset","--hard",n.trim()]),o={from:r.trim(),to:n.trim()},s=!0),s?(await kn(e,["read-tree","--reset","-u","FETCH_HEAD"]),await kn(e,["reset","-q"]),{applied:!0,skipped:null,advanced:o}):{applied:!1,skipped:"snapshot does not parent the fetched branch head",advanced:null}}catch(n){return{applied:!1,skipped:String(n?.message||n).split(`
|
|
253
|
+
`)[0],advanced:null}}}function NH(e){if(typeof e!="string"||!CH.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function dy(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(e.branch!=null&&NH(e.branch),tp.has(t))throw new Error("an adopt is already running for this Track");tp.set(t,{startedAt:Date.now()});try{return await PH({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{tp.delete(t)}}async function PH({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,wips:u=null,brief:d=null,epochs:p=[],createdAt:f=null,leadBox:w=null,reason:m=null,downSince:g=null}){let y=await Fa(n,r),x=await Z(),b=de(x,e);if(b&&!b.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);b&&(await dg(b).catch(()=>{}),await OI(b),x.tracks.splice(x.tracks.indexOf(b),1),await ae()),await V.mkdir(Uc,{recursive:!0});let I=G.join(Uc,e);await V.rm(I,{recursive:!0,force:!0}).catch(()=>{});let $=null,P=!1,F=[];try{let B=[];if(i)for(let se of Array.isArray(c)?c:[]){let ee=typeof se=="string"?se:se?.repo;if(!ee||!/^[^/\s]+\/[^/\s]+$/.test(ee))continue;let Oe=await Ps(ee)??await Vl(ee);await kn(Oe,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],iy),B.push({slug:ee,base:Oe,name:typeof se=="object"?se?.name??null:null})}if(i&&B.length===1){let{base:se,slug:ee}=B[0];await mI(se,I,i),F.push({base:se,dir:I}),await Kc(I);let Oe=await Qo(se);$={dir:I,base:se,branch:i,kind:"worktree",baseRef:Oe,repo:ee}}else if(i&&B.length>=2){await V.mkdir(I,{recursive:!0});let se=new Set([".bostrat"]),ee=[];for(let Oe of B){let z=Oe.name||G.basename(Oe.base);se.has(z)&&(z=Oe.slug.replace("/","-"));for(let O=2;se.has(z);O++)z=`${G.basename(Oe.base)}-${O}`;se.add(z);let we=G.join(I,z);await mI(Oe.base,we,i),F.push({base:Oe.base,dir:we});let Fe=await Qo(Oe.base);ee.push({name:z,dir:we,base:Oe.base,baseRef:Fe,repo:Oe.slug})}await Ha(I,ee,i),$={dir:I,kind:"multi",branch:i,repos:ee}}else P=!0,await V.mkdir(I,{recursive:!0}),await Th(I),await Kc(I),$={dir:I,base:null,branch:null,kind:"repo"};let T=[];for(let se of OH($,{wip:l,wips:u})){let ee=await MH(se.dir,e);T.push({name:se.name,repo:se.repo,applied:ee.applied,skipped:ee.skipped,...ee.advanced?{advanced:ee.advanced}:{}})}let _=T.some(se=>se.applied),U=T.length===1?T[0].skipped:T.filter(se=>se.skipped).map(se=>`${se.name??se.repo}: ${se.skipped}`).join("; ")||null,J=T.length===1?T[0].advanced??null:null;await eI({id:e,cwd:I}).catch(()=>({restored:!1}));let R=G.join(I,go),A=null;(await iu(I)).restored?A="checkpoint":typeof d=="string"&&d.trim()&&(await V.mkdir(G.dirname(R),{recursive:!0}),await V.writeFile(R,d),A="brief");let N=new Set(x.tracks.flatMap(se=>(se.boxes||[]).map(ee=>ee.name))),K=null;w&&!N.has(w)&&!await be(w).catch(()=>null)?K=w:(K=`${t.trim()} lead`,N.has(hu(K))&&(K=`${t.trim().slice(0,50).trim()} ${e} lead`));let Y=await $n(K,I,{agentCmd:y,agent:n});qo({cwd:Y.cwd,sessionName:Y.name,agent:n,agentCmd:y});let fe=Date.now(),Ie=sy(Y,"lead","live"),Ce=(Array.isArray(p)?p:[]).filter(se=>se&&typeof se=="object").map(se=>({...se})),X=Ce[Ce.length-1];X&&X.endedAt==null&&(X.endedAt=fe,X.endReason==null&&(X.endReason=o==="recover"?"node-offline":"node-transfer"));let et=await Go({agent:n,agentCmd:y});Ce.push({agent:n,sessionId:Y.sessionId??null,pinned:Y.pinned===!0,cliVersion:et,startedAt:fe,endedAt:null}),Ie.epochs=Ce,Ie.cliVersion=et;let Ee={id:e,name:t.trim(),cwd:Y.cwd,workspace:$,leadBox:Y.name,boxes:[Ie],events:[],createdAt:Number.isFinite(f)?f:fe,...A?{pendingHandoffHydrate:{artifact:go,at:fe}}:{}};return Ae(Ee,"transferred-in",{box:Y.name,agent:n,fromNode:s,toNode:a,mode:o,reason:m,...o==="recover"?{downSince:Number.isFinite(g)?g:null}:{},branch:$.branch??null,wip:_,...J?{wipAdvanced:J}:{},...$.kind==="multi"&&T.length?{wipRepos:T}:{},epoch:Ce.length-1,name:Ee.name,cwd:Ee.cwd,workspace:{base:$.base??null,branch:$.branch??null,kind:$.kind,...$.baseRef?{baseRef:$.baseRef}:{},...$.repo?{repo:$.repo}:{},...$.repos?{repos:$.repos.map(({name:se,base:ee,baseRef:Oe,repo:z})=>({name:se,base:ee,baseRef:Oe,repo:z}))}:{}}}),x.tracks.push(Ee),await ae(),{...await Wt(Ee),adopt:{wipApplied:_,wipSkipped:U,...J?{wipAdvanced:J}:{},...$.kind==="multi"?{wipRepos:T}:{},codeless:P,artifactSource:A}}}catch(B){for(let T of F)await Et(T.base,T.dir).catch(()=>{});throw await V.rm(I,{recursive:!0,force:!0}).catch(()=>{}),B}}async function PI(e,t,n){let r=await Z(),o=de(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ae())}async function Na(e,t){e.step=t,await el(e)}function DI(e,t=Date.now()){if(!e||e.finishedAt)return null;let n=e.step;return["snapshot","spawn","working"].includes(n)?{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; no changes were applied to the lead \u2014 retry the delegation`,recovered:"rolled-back"}:{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; the lead's working tree may hold a PARTIAL merge \u2014 review git status. The subtask's work is preserved on branch ${e.branch}`,recovered:"partial-merge"}}function BI(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function LH(e,t,n){if(!BI(n)||Bt.has(t)||!await be(n.box).catch(()=>null))return!1;try{await V.access(n.dir)}catch{return!1}let o=await be(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Bt.set(t,s),LI(s,o).catch(a=>jI(s,a)),!0}async function py(){let e=await Z(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Bt.has(r))continue;if(await LH(n,r,o)){t=!0,Ae(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await pe({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=DI(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Ir.has(i.state)&&(i.state="canceled"),Ae(n,"subtask-failed",{from:o.box,fromAgent:o.agent,task:o.task,subtaskId:r,failedStep:s,error:a.error,recovered:a.recovered,durationMs:o.startedAt?a.finishedAt-o.startedAt:null}),await pe({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await hI(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Ir.has(r.state)||Bt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?G.join(La,`${n.id}-${r.subtaskId}`):null;await pe({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await hI(n,r.name,o)}}return t=await FH(e)||t,t&&await ae(),t}async function hI(e,t,n){if(t&&await Ct(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of jt(e.workspace)){let s=G.join(n,o.name);await Et(o.base,s).then(()=>!0,()=>!1)||await Et(o.dir,s).catch(()=>{})}await V.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await be(e.leadBox).catch(()=>null);r?.cwd&&await Et(r.cwd,n).catch(()=>{})}async function FH(e){let t;try{t=await V.readdir(La)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of Bt.values())o.dir&&n.add(G.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=G.join(La,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of jt(a.workspace))await Et(i.base,G.join(s,i.name)).catch(()=>{});await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await be(a.leadBox).catch(()=>null):null;i?.cwd?await Et(i.cwd,s).catch(()=>{}):await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await pe({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function fy(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!la(n))throw new Error("task (string) required");let s=await Fa(t,r),a=no(t);if(a){let f=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw f.usageCap=a,f}let i=de(await Z(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await be(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let f=jt(i.workspace);if(!f.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let w of f)if(!w?.dir||!await ua(w.dir))throw new Error(`tagged checkout "${w?.name??"?"}" is missing from the lead workspace (${w?.dir??"no dir"})`);u=f.map(w=>({name:w.name,leadDir:w.dir,base:null}))}else if(!await ua(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=ip().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:la(n),skipPermissions:r,reason:bI(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${Ep(i.name)}-${d}`,base:null,repos:u,dir:G.join(La,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Bt.set(d,p),await el(p),UH(p,c,s).catch(f=>jI(p,f)),p}async function jI(e,t){e.failedStep=e.step,e.error=t instanceof zc?"canceled":t?.message||String(t),e.step=t instanceof zc?"canceled":"error",e.finishedAt=Date.now(),await hy(e).catch(()=>{}),await el(e).catch(()=>{}),await KH(e).catch(()=>{})}function _p(e){let t=Bt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");return t.canceled=!0,t}function my(e){let t=Bt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");if(t.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${t.step})`);return t.forceMerge=!0,t}async function UH(e,t,n){if(await Na(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await da(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await el(e)}else e.base=await da(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Na(e,"spawn"),await V.mkdir(La,{recursive:!0}),e.repos){await V.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Zo(a.leadDir,G.join(e.dir,a.name),e.branch,a.base);let s=jt((de(await Z(),e.trackId)||{}).workspace);await Ha(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch)}else await Zo(t.cwd,e.dir,e.branch,e.base),await Kc(e.dir);await HH(e,t);let r=e.trackName.slice(0,38).trim(),o=await $n(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await WH(e,o),await kI(e.trackId,o.name,O2(e.task,!!e.repos),{kind:"subtask"}),await LI(e,t)}async function LI(e,t){await Na(e,"working");let n=G.join(e.dir,np);if(await VH(n,e),e.canceled)throw new zc;if(await Na(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=G.join(e.dir,l.name);await Sh(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:fI({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await _h(l.leadDir,l.base,e.branch,Ca),l.files=await Ih(l.leadDir,l.base,e.branch,Ca);let d=await $h(l.leadDir,l.base,e.branch,Ca);l.applied=d.applied,l.conflicts=d.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(p=>G.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:G.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Sh(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:fI({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await _h(t.cwd,e.base,e.branch,Ca),e.files=await Ih(t.cwd,e.base,e.branch,Ca);let s=await $h(t.cwd,e.base,e.branch,Ca);e.applied=s.applied,e.conflicts=s.conflicts}await el(e);let r=await GH(e,t,n);await Na(e,"resume"),await kI(e.trackId,e.leadBox,M2(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Na(e,"reap"),await hy(e),e.step="done";let o=Date.now();await PI(e.trackId,e.id,{...Tp(e),finishedAt:o}),await qH(e,o),e.finishedAt=o}async function HH(e,t){let n=G.join(e.dir,G.dirname(Hc));await V.mkdir(n,{recursive:!0});let r="";try{r=await Q0(t.cwd,t.sessionId)}catch{}if(!r)try{r=await V.readFile(G.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
|
|
254
254
|
|
|
255
255
|
**Delegated task:** ${e.task}
|
|
256
256
|
|
|
@@ -261,15 +261,15 @@ ${a}`}async function Yg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<
|
|
|
261
261
|
## Conversation so far (lead \u2192 you)
|
|
262
262
|
|
|
263
263
|
${r}
|
|
264
|
-
`;await V.writeFile(G.join(e.dir,
|
|
264
|
+
`;await V.writeFile(G.join(e.dir,Hc),o)}async function WH(e,t){let n=await Z(),r=de(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:Oo(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Ae(r,"subtask-delegated",{to:t.name,toAgent:e.agent,task:e.task,subtaskId:e.id,skipPermissions:e.skipPermissions,reason:e.reason}),r.subtasks=r.subtasks||{},r.subtasks[e.id]={...r.subtasks[e.id]||{},...Tp(e)},await ae())}async function qH(e,t=e.finishedAt){let n=await Z(),r=de(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),Ae(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await ae()}async function KH(e){let t=await Z(),n=de(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),Ae(n,r?"subtask-canceled":"subtask-failed",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,failedStep:e.failedStep||e.step,error:e.error,durationMs:e.finishedAt?e.finishedAt-e.startedAt:null}),n.subtasks=n.subtasks||{},n.subtasks[e.id]={...n.subtasks[e.id]||{},...Tp(e)},await ae()}async function GH(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=G.join(t.cwd,r);await V.mkdir(G.dirname(o),{recursive:!0}),await V.copyFile(n,o)}catch{}return r}async function hy(e){if(e.dir&&await nu(e.dir).catch(()=>{}),e.box&&await Ct(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Et(t.leadDir,G.join(e.dir,t.name)).catch(()=>{});await V.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await be(e.leadBox).catch(()=>null))?.cwd;n&&await Et(n,e.dir).catch(()=>{})}}async function VH(e,t){let n=(t.startedAt||Date.now())+DH;for(;;){if(t.canceled||t.forceMerge)return;try{await V.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await $r(BH)}}function $r(e){return new Promise(t=>setTimeout(t,e))}var cp,Vn,wI,I2,Uc,$2,lp,Jc,ho,go,Og,R2,np,Hc,O2,M2,Dt,yg,de,bg,Ae,kg,xg,P2,Ir,cI,j2,L2,F2,U2,lI,jc,V2,Ba,uI,Q2,eH,tH,nH,rH,Pa,Wc,iH,lH,uH,fH,Gg,Ig,Zc,bt,bn,op,qc,II,bH,Lc,Fc,kH,vg,SH,Gc,AH,TH,pI,Sg,$g,sy,ws,Wa,iy,kn,ap,cy,CH,tp,DH,BH,La,Ca,Bt,jH,ks,Tp,el,Ep,zc,gr=W(()=>{xi();ft();qm();Nv();ta();jr();vu();Fv();gt();In();Wu();Wv();Ms();xu();lh();Ho();yh();kh();TS();Ki();Rm();Su();Lm();dn();Yu();Pr();Zt();Wi();td();YS();Ph();pE();Nu();Mu();mE();Aw();me();_w();Rd();Wd();fc();ts();Rc();Ra();eg();Yd();ig();Dn();Dd();V_();pg();tI();cu();sI();hg();gg();cp=_2(E2),Vn=process.env.BOSTRAT_STATE_DIR||G.join(process.env.HOME||"/tmp",".bostrat"),wI=G.join(Vn,"tracks.json"),I2=G.join(Vn,"events.jsonl"),Uc=G.join(Vn,"workspaces"),$2=process.env.BOSTRAT_DEFAULT_REPO||null,lp={claude:{envVar:"BOSTRAT_AGENT_CMD",base:"claude",skipFlag:"--dangerously-skip-permissions"},cursor:{envVar:"BOSTRAT_CURSOR_CMD",base:"cursor-agent",skipFlag:"--force"},codex:{envVar:"BOSTRAT_CODEX_CMD",base:"codex",skipFlag:"--dangerously-bypass-approvals-and-sandbox"}},Jc=Object.keys(lp);ho={at:0,value:null};go=".bostrat/handoff/latest.md",Og=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;R2=/\(Read \S{1,300} for handoff context from the prior lead — you are now the lead; none of the prior chat is in your context\. Then respond to the user above\.\)$/;np=".bostrat/handoff/subtask-result.md",Hc=".bostrat/handoff/lead-context.md",O2=(e,t=!1)=>t?`You are a SUBTASK agent working in an isolated multi-repo workspace, delegated by a lead agent on a shared workstream. This directory is NOT itself a git repo: each subdirectory is an isolated git worktree of one of the workstream's repos, already seeded with the lead's full working tree for that repo. The conversation so far is summarized in ${Hc} \u2014 read that first for context. Your scoped task:
|
|
265
265
|
|
|
266
266
|
${e}
|
|
267
267
|
|
|
268
|
-
Work ONLY inside this directory. cd into the repo a change belongs to before running git commands, and commit per repo with a clear message (repos you don't touch need nothing). When you are finished: (1) make your code changes, (2) commit them in each changed repo, (3) LAST, write a short markdown digest to ${
|
|
268
|
+
Work ONLY inside this directory. cd into the repo a change belongs to before running git commands, and commit per repo with a clear message (repos you don't touch need nothing). When you are finished: (1) make your code changes, (2) commit them in each changed repo, (3) LAST, write a short markdown digest to ${np} (at this directory's root) with sections \u2014 Result (what you did), Files (paths you changed, prefixed with the repo directory), Notes (anything the lead must know). Writing that file is your DONE signal: do it last, then stop and take no further action.`:`You are a SUBTASK agent working in an isolated git worktree, delegated by a lead agent on a shared workstream. The lead's full working tree is already checked out here, and the conversation so far is summarized in ${Hc} \u2014 read that first for context. Your scoped task:
|
|
269
269
|
|
|
270
270
|
${e}
|
|
271
271
|
|
|
272
|
-
Work ONLY inside this directory. When you are finished: (1) make your code changes, (2) commit them with git and a clear message, (3) LAST, write a short markdown digest to ${
|
|
272
|
+
Work ONLY inside this directory. When you are finished: (1) make your code changes, (2) commit them with git and a clear message, (3) LAST, write a short markdown digest to ${np} with sections \u2014 Result (what you did), Files (paths you changed), Notes (anything the lead must know). Writing that file is your DONE signal: do it last, then stop and take no further action.`,M2=(e,t,n,r)=>`A subtask box you delegated has finished: "${e}". Its changes are now merged into your working tree (${t.files} file${t.files===1?"":"s"}, +${t.insertions} \u2212${t.deletions}). Read ${r} for exactly what it did. `+(n.length?`IMPORTANT: ${n.length} merge conflict${n.length===1?"":"s"} need resolving \u2014 fix the conflict markers in: ${n.join(", ")}, then continue.`:"Review the merged changes and continue the work."),Dt=null,yg=null;de=(e,t)=>e.tracks.find(n=>n.id===t)||null,bg=Promise.resolve();Ae=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),C2(e.id,r),QS(e,r),r};rx(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await Z()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(Ae(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ae().catch(()=>{}))});kg=G.join(Vn,"plane-link","update-notice.json");xg=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),P2=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Ir=new Set(["merged","conflict","canceled","failed","handed-off"]),cI=new Map;j2=5e3;L2={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};F2=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];U2=10*6e4;lI=400;jc=new Map;V2=1500,Ba=new Map;uI="Spin up a live preview View of this app so I can see it on another device. From the repo root, run `bostrat-view up --name \"<short name>\" -- <serve command>` \u2014 pick the right dev/serve command for this repo yourself (e.g. `npm run dev`), pass $PORT through if the command needs an explicit port, and share the public URL it prints. If a suitable View is already live, just re-share its URL instead of starting another. Don't paste a localhost link \u2014 it's dead on my device.\n\nIMPORTANT: if you cannot confidently identify WHICH project/app to serve, or which serve command to use (e.g. several apps in this tree, or no obvious dev script), do NOT guess and do NOT run `bostrat-view up`. Instead, reply with a short question asking me which one you should preview, and stop.";Q2=4e3,eH=3,tH=[300,350,400],nH=1e3,rH=12,Pa=new Map,Wc=new Map;iH=[250,400,500,600];lH=3e4,uH=[350,650,900];fH=12e4;Gg=e=>({branch:e.branch,kind:e.kind,repos:(e.repos??[]).filter(Boolean).map(({name:t,base:n,baseRef:r,repo:o})=>({name:t,base:n,baseRef:r,repo:o}))});Ig=new Map,Zc=e=>Ig.get(e)||(Dt?de(Dt,e)?.reshape:null)||null,bt=(e,t=409)=>Object.assign(new Error(e),{status:t});bn=e=>V.access(e).then(()=>!0,()=>!1),op=(e,t,n)=>cp("git",["-C",e,"worktree","move","--end-of-options",t,n],{timeout:6e4});qc="# bostrat workspace",II=`${qc}
|
|
273
273
|
|
|
274
274
|
TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
|
|
275
275
|
before substantive work \u2014 it is the shared cross-provider memory for this repo
|
|
@@ -647,16 +647,16 @@ for the same follow-up at the same moment twice; run bostrat-followup ls first
|
|
|
647
647
|
specifics (no PR numbers, URLs, SHAs, tags \u2014 the card supplies them), and HOLD
|
|
648
648
|
HERE after proposing until the operator answers the card. Bostrat never runs a
|
|
649
649
|
follow-up on its own; the operator's tap is the gate.
|
|
650
|
-
`,
|
|
651
|
-
`)),
|
|
652
|
-
`,`${
|
|
650
|
+
`,bH=II,Lc=II+Gx;Fc=e=>typeof e=="string"&&(e===qc||e.startsWith(`${qc}
|
|
651
|
+
`)),kH="# bostrat multi-repo workspace";vg=Lc.replace(`${qc}
|
|
652
|
+
`,`${qc}
|
|
653
653
|
|
|
654
654
|
(Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
|
|
655
655
|
SCOPE: these instructions apply ONLY when your working directory is under
|
|
656
656
|
~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
|
|
657
657
|
When working anywhere else, ignore everything below.
|
|
658
|
-
`);iH=new Set(["claude","codex","cursor"]);qc=new Set,cH=e=>qc.has(e);lH=9e4;oI={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};bg=new Map;Tg=120;ty=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Ro(e.hookToken),createdAt:Date.now()});ms=new Map,Ha=e=>ms.get(e)||(Pt?ue(Pt,e)?.handoff:null)||null;ry=6e4,kn=(e,t,n=15e3)=>sp("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),rp=new Map,oy=e=>rp.get(e)||null;gH=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Zd=new Map;kH=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,xH=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ja=G.join(Vn,"worktrees"),Ma=[Fc,Qd],Dt=new Map,vH=e=>Dt.get(e)||(Pt?Pt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,bs=e=>{let t=new Map([...Dt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Pt?ue(Pt,e):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))t.has(r)||t.set(r,o);return[...t.values()].sort((r,o)=>r.startedAt-o.startedAt)},vp=e=>({id:e.id,trackId:e.trackId,trackName:e.trackName,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,reason:e.reason||null,step:e.step,failedStep:e.failedStep||null,box:e.box,branch:e.branch,base:e.base,repos:e.repos||null,dir:e.dir,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt});Zc=e=>_I(e.trackId,e.id,vp(e));Sp=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Gc=class extends Error{}});ht();import Ie from"node:path";import St from"node:fs";import _G from"node:readline";import{fileURLToPath as IG}from"node:url";import Jt from"express";import $G from"node:http";import RG from"node:https";import Il from"node:os";import{randomUUID as OG}from"node:crypto";import{WebSocketServer as MG}from"ws";ht();import oP from"node-pty";async function S0(e,t,n={}){if(!De(t)){wu(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Fr()){wu(e,`host tmux server not running on ${Ft}`),e.close(1011,"tmux server unavailable");return}if(!await ke(t)){wu(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=v0(n.cols,120,A0),o=v0(n.rows,32,T0),s;try{s=oP.spawn(ne,["-S",Ft,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){wu(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&eh(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(eh(e,{type:"exit",code:a??null,signal:i??null}),e.close(1e3,"tmux exited"))}),e.on("message",a=>{let i;try{i=JSON.parse(a.toString())}catch{return}if(!(!i||typeof i!="object")){if(i.type==="data"&&typeof i.data=="string")s.write(i.data);else if(i.type==="resize"&&cP(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),e.on("close",()=>{try{s.kill()}catch{}iP(t)})}var sP=6,aP=250;async function iP(e,t=sP,n=aP){for(let r=0;r<t;r++){if(await jo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var A0=20,T0=6;function cP(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=A0&&Number(t)>=T0}function v0(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function eh(e,t){try{e.send(JSON.stringify(t))}catch{}}function wu(e,t){eh(e,{type:"error",message:t})}function E0(e){let t=typeof e=="string"&&e?e:"/",n=t.indexOf("?"),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n+1),s=r.match(/^\/api\/attach\/([^/]+)$/);if(!s)return{ok:!1,status:404};let a;try{a=decodeURIComponent(s[1])}catch{return{ok:!1,status:400}}let i=new URLSearchParams(o);return{ok:!0,sessionName:a,cols:Number(i.get("cols"))||void 0,rows:Number(i.get("rows"))||void 0}}dn();yu();Fh();mr();import{createRequire as CG}from"node:module";var MH=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function py({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[]}={}){let s=[];for(let a of e)!a||a.archivedAt&&!a.archiving||a.transferredTo||(a.working&&s.push(`working:${a.id}`),a.prompted&&s.push(`prompted:${a.id}`),(n(a.id)??[]).length&&s.push(`queued:${a.id}`),(a.boxes||[]).some(i=>i?.role==="subtask"&&i?.state==="live")&&s.push(`subtask:${a.id}`),(r(a.id)??[]).length&&s.push(`job:${a.id}`),Object.values(a.subtasks||{}).some(MH)&&s.push(`merge-back:${a.id}`),(o(a.id)??[]).length&&s.push(`pr:${a.id}`));return t.some(a=>a?.state==="live"||a?.state==="starting")&&s.push("views"),{busy:s.length>0,reasons:s}}fe();sm();ht();import DH from"node:fs/promises";import fy from"node:fs/promises";var CH=100;async function NH(e){let t;try{t=await fy.readFile(`/proc/${e}/stat`,"utf8")}catch{return null}let n=t.lastIndexOf(")");if(n<0)return null;let r=t.slice(n+2).split(" "),o=Number(r[1]),s=Number(r[11])+Number(r[12]);return!Number.isFinite(o)||!Number.isFinite(s)?null:{ppid:o,cpuMs:s/CH*1e3,ioBytes:await PH(e)}}async function PH(e){let t;try{t=await fy.readFile(`/proc/${e}/io`,"utf8")}catch{return 0}let n=r=>Number(t.match(new RegExp(`^${r}: (\\d+)$`,"m"))?.[1]||0);return n("rchar")+n("wchar")}async function CI(e){let t=[...new Set((e||[]).map(Number).filter(l=>Number.isFinite(l)&&l>0))];if(!t.length)return{procs:0,cpuMs:0,ioBytes:0};let n;try{n=await fy.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await NH(l);u&&r.set(Number(l),u)}));let o=new Map;for(let[l,u]of r)o.has(u.ppid)||o.set(u.ppid,[]),o.get(u.ppid).push(l);let s=new Set,a=t.filter(l=>r.has(l));for(let l of a)s.add(l);let i=0,c=0;for(let l=0;l<a.length;l++){let u=a[l];i+=r.get(u).cpuMs,c+=r.get(u).ioBytes;for(let d of o.get(u)||[])s.has(d)||(s.add(d),a.push(d))}return{procs:s.size,cpuMs:Math.round(i),ioBytes:c}}var BH=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,jH=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,LH=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,FH=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,UH=5*6e4,PI={readOpenJobs:tS,statFile:async e=>{try{let t=await DH.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Yr(e.agent).updatedAt(e),panePids:y0,treeStats:CI,appendEvent:C},xn=new Map,NI=new Map,hy=new Map,my=(e,t,n)=>`${e}|${t}|${n}`;function DI(e){let t=[];for(let n of e||[])if(!(!n||n.archivedAt&&!n.archiving||n.transferredTo))for(let r of n.boxes||[])r?.state==="live"&&r.name&&t.push({track:n,box:r});return t}async function BI(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=NI.get(e.name);if(o&&o.mtime===r&&t-o.at<UH)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return NI.set(e.name,{at:t,mtime:r,jobs:s}),s}async function HH(e,t,n){let r=await n.panePids(e.name),o=r.length?await n.treeStats(r):null,s=null;try{s=await n.updatedAt(e)}catch{s=null}return{at:t,cpuMs:o?.cpuMs??null,ioBytes:o?.ioBytes??null,procs:o?.procs??null,mtime:s}}async function WH(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function qH(e,t){if(!e)return!0;let n=Math.max(1,(t.at-e.at)/1e3);return t.mtime!=null&&e.mtime!=null&&t.mtime>e.mtime||t.procs!=null&&e.procs!=null&&t.procs>e.procs||t.cpuMs!=null&&e.cpuMs!=null&&(t.cpuMs-e.cpuMs)/n>=LH||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=FH}function jI(e,t,n,r){let o=[];for(let s of n){let a=my(e.id,t.name,s.id),i=xn.get(a);i?i.job=s:xn.set(a,{trackId:e.id,boxName:t.name,agent:t.agent||null,job:s,firstSeenAt:r,quiet:0,stalled:!1}),o.push(a)}return o}async function LI(e,{now:t=Date.now(),deps:n=PI}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of DI(e)){let i=await BI(a,t,n);for(let l of i)o.add(my(s.id,a.name,l.id));let c=jI(s,a,i,t).filter(l=>!xn.get(l).stalled).map(l=>xn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...xn.keys()])o.has(s)||xn.delete(s);return r}async function KH(e,{now:t=Date.now(),deps:n=PI}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=DI(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...xn])s.has(i.boxName)||xn.delete(a);for(let{track:a,box:i}of o){let c=await BI(i,t,n),l=new Set(c.map(w=>my(a.id,i.name,w.id)));for(let[w,h]of[...xn])h.boxName===i.name&&!l.has(w)&&xn.delete(w);if(!c.length){hy.delete(i.name);continue}let u=jI(a,i,c,t),d=await HH(i,t,n),p=hy.get(i.name);hy.set(i.name,d);let f=qH(p,d);for(let w of u){let h=xn.get(w);r.checked++;let g=await WH(h.job,n),y=!!g&&!!h.file&&(g.size>h.file.size||g.mtimeMs>h.file.mtimeMs),k=!!g&&!h.file;if(h.file=g??h.file,f||y||k){h.quiet=0,h.lastProgressAt=t,h.stalled=!1,r.progressing++;continue}if(h.stalled||(h.quiet++,r.quiet++,h.quiet<jH))continue;h.stalled=!0,h.stalledAt=t,r.stalled.push(w);let I=t-(h.lastProgressAt??h.firstSeenAt);try{await n.appendEvent(a,{type:"job.stalled",actor:"orchestrator",source:"orchestrator",boxId:i.name,provider:i.agent||null,payload:{id:h.job.id,kind:h.job.kind||"agent",name:h.job.name||null,detail:h.job.detail||null,startedTs:h.job.ts??h.firstSeenAt,quietMs:I,checks:h.quiet}})}catch{}console.log(`[job-watch] ${a.id}/${i.name} job ${h.job.id} (${h.job.name||h.job.kind}) quiet for ${Math.round(I/6e4)}m over ${h.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function FI({listTracks:e,intervalMs:t=BH}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await KH(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}fe();Ic();Dn();Rd();Zt();var Tp=60*6e4,GH=1440*6e4,VH=new Set(["merged","closed","lost"]),Qc=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function zH({trackId:e,shipPending:t=null,links:n=[],observers:r=0,now:o=Date.now()}={}){let s=[];t&&Number.isFinite(Number(t.ts))&&o-Number(t.ts)<=Fw&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||VH.has(a.state))continue;let i=[a.ciFix,a.reconcile,a.ciFixAwait,a.reconcileAwait];if(!(a.trackId===e||i.some(d=>d?.trackId===e)))continue;let l=a.number??"?";a.ciFix&&Qc(a.ciFix.delegatedAt,Tp,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Qc(a.reconcile.delegatedAt,Tp,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Qc(a.ciFixAwait.since,Tp,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Qc(a.reconcileAwait.since,Tp,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Qc(u,GH,o)&&s.push(`auto-merge#${l}`)}return s}var Ep=new Map;Xe.on("event",e=>{e?.trackId&&Ep.delete(e.trackId)});async function JH(e){if(Ep.has(e.id))return Ep.get(e.id);let t=await q(e).catch(()=>[]),n=Ea(t,-1/0);return Ep.set(e.id,n),n}async function UI(e,{now:t=Date.now()}={}){let n=new Map,r=await hn().catch(()=>[]);for(let o of e||[]){if(!o||je(o))continue;let s=zH({trackId:o.id,shipPending:await JH(o),links:r,observers:RT(o.id),now:t});s.length&&n.set(o.id,s)}return n}dg();import QI from"node:fs";import go from"node:fs/promises";import fW from"node:os";import wt from"node:path";import{spawn as hW}from"node:child_process";import{createRequire as mW}from"node:module";fe();Zu();import Wa from"node:fs";import tl from"node:fs/promises";import ZH from"node:http";import Kt from"node:path";import Ip from"node:os";import{createRequire as QH}from"node:module";import gy from"ws";import YH from"node:path";import XH from"node:os";var el=process.env.BOSTRAT_STATE_DIR||YH.join(process.env.HOME||XH.tmpdir(),".bostrat");function wy(e=process.env){let t=(e.BOSTRAT_HOST||"").trim();if(t!=="all")return t||(e.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function HI(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=wy(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function WI(e){let t=String(e||"").trim();if(!t)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:`wss://${t}`,r;try{r=new URL(n)}catch{return t}let o={"https:":"wss:","http:":"ws:","wss:":"wss:","ws:":"ws:"}[r.protocol];return o?(r.protocol=o,(r.pathname===""||r.pathname==="/")&&(r.pathname="/v1/node"),r.toString()):t}If();var vn=(()=>{try{return QH(import.meta.url)("../package.json").version||null}catch{return null}})(),by=process.env.BOSTRAT_STATE_DIR||Kt.join(process.env.HOME||Ip.tmpdir(),".bostrat"),YI=Kt.join(by,"plane-link","removed.json");function qI(e){return typeof e!="string"||e.length<8?"\u2022\u2022\u2022\u2022":`${e.slice(0,6)}\u2026${e.slice(-4)}`}function eW(e=YI){try{let t=JSON.parse(Wa.readFileSync(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function ks({env:e=process.env,pkgDir:t=Kt.resolve(Kt.dirname(new URL(import.meta.url).pathname),".."),exists:n=Wa.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(Kt.join(t,"..",".git"))?"git-checkout":"dev"}function nl(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!1;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function _p(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 tW({home:e=process.env.HOME||Ip.homedir(),env:t=process.env}={}){let n=r=>{try{return Wa.statSync(r),!0}catch{return!1}};return{claude:n(Kt.join(e,".claude",".credentials.json")),codex:n(Kt.join(t.CODEX_HOME||Kt.join(e,".codex"),"auth.json"))}}var ft=1,KI=1e3,GI=3e4,nW=6e4,rW=1500,oW=500,wo=100,sW=2e3,aW=25e3,iW=6e4,XI=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},cW=XI(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),lW=3e4,VI=10*6e4,uW=400,zI=250,dW=XI(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),yy=4,pW=6e4,JI=6e4;function ZI({url:e,token:t,nodeId:n=Ip.hostname(),name:r=Ip.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,metricsMs:u=pW,onUpdateAvailable:d=null,onUpdatePolicy:p=null,onHelloRefused:f=null,updatePolicy:w=null,installKind:h=ks(),selfUrl:g=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:y=null,removedMarkerFile:k=YI,onRemoved:b=null,onDegraded:I=null,onRecovered:R=null,onConnected:N=null,ingestMode:D=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:j=cW,unackedRetryMs:T=iW,pingMs:$=aW,maxInflightEvents:F=uW,httpTimeoutMs:J=dW,stallBackoffMinMs:M=lW,fetchImpl:S=globalThis.fetch,log:_=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=WI(e);let H=g.replace(/^http/,"ws"),K=new Set,X=new Map,pe=new Map,Oe=Kt.join(by,"plane-link","cursor.json"),Me=Kt.join(by,"plane-link","dead-letter.ndjson"),Q=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),qe={},Ae={},Z=new Map,me=null,Te=null,z=0,ge=0,Ge=0,O=Promise.resolve(),Y="ws",Le=0,Qe=!1,oe=0,ye=!1,Fe=wo,jt=new Set,x=[],m=null,v=null,P=!1,ce=!1,be=KI,Ne=null,gt=null,rt=null,lt=null,Xn=null,mf=!1,Pl=0,oi=!1,Rr=eW(k);if(Rr)if(Rr.tokenPreview===qI(t))oi=!0,_f({reason:Rr.reason??"removed",at:Rr.at??null,nodeId:Rr.nodeId??n}),_.error(`[plane-link] this node was REMOVED from the plane (${Rr.reason??"removed"}${Rr.at?` at ${new Date(Rr.at).toISOString()}`:""}) \u2014 not dialing. Re-provision it with a new node token, or delete ${k} to force a dial.`);else try{Wa.unlinkSync(k),_.log("[plane-link] stale removed-marker discarded \u2014 the node token changed")}catch{}function wf({reason:B="removed",at:U=Date.now(),via:A="ctl"}={}){if(!oi){oi=!0,_f({reason:B,at:U,nodeId:n,via:A});try{Wa.mkdirSync(Kt.dirname(k),{recursive:!0}),Wa.writeFileSync(k,JSON.stringify({at:U,reason:B,via:A,nodeId:n,tokenPreview:qI(t)},null,2))}catch(L){_.error(`[plane-link] could not write ${k}: ${L?.message||L}`)}_.error(`[plane-link] the plane REMOVED this node (${B}, via ${A}) \u2014 going dormant: no more dials, ingest or broker calls. Re-provision with a new node token to reconnect; the box and its data are untouched.`);try{b?.({reason:B,at:U,via:A})}catch{}Xb({bye:!1})}}async function NM(){try{qe=JSON.parse(await tl.readFile(Oe,"utf8"))}catch{qe={}}}function PM(){mf=!0,!rt&&(rt=setTimeout(async()=>{if(rt=null,!!mf){mf=!1;try{await tl.mkdir(Kt.dirname(Oe),{recursive:!0}),await tl.writeFile(Oe,JSON.stringify(qe))}catch(B){_.error("[plane-link] cursor flush failed:",B?.message||B)}}},sW),rt.unref?.())}function ut(B){return!v||v.readyState!==gy.OPEN?!1:(v.send(JSON.stringify(B)),!0)}function si(B){let U=Date.now();for(let{trackId:A,event:L}of B){let te=Z.get(L.id);Z.set(L.id,{trackId:A,seq:L.seq,event:L,sentAt:U,firstSentAt:te?.firstSentAt??U,retryAt:U+T,tries:(te?.tries??0)+1,nacks:te?.nacks??0})}return Y==="http"?(LM(B),!0):ut({v:ft,ch:"events",type:"append",events:B})}function DM(B){let U=null;for(let A of Z.values())A.trackId===B&&(U==null||A.seq<U)&&(U=A.seq);return U}function gf(B){let U=Ae[B];if(U==null)return;let A=DM(B),L=A==null?U:Math.min(U,A-1);L>(qe[B]??0)&&(qe[B]=L,PM())}function ai(){if(me=Date.now(),Te!=null){let B=Date.now()-Te;_.log(`[plane-link] spine sync recovered after ${Math.round(B/1e3)}s degraded (${z} stall redial(s))`);let U=Te;Te=null,z=0,ge=0,Qe=!1,oe=0;try{R?.({since:U,downMs:B})}catch(A){_.error(`[plane-link] onRecovered failed: ${A?.message||A}`)}}}function yf(B){if(!Array.isArray(B)||!B.length)return;let U=new Set;for(let A of B){let L=Z.get(A);L&&(Z.delete(A),(Ae[L.trackId]??0)<L.seq&&(Ae[L.trackId]=L.seq),U.add(L.trackId))}for(let A of U)gf(A);ai()}function Wb(B,U){Ge++;let A={at:Date.now(),trackId:B.trackId,seq:B.seq,id:B.event?.id??null,type:B.event?.type??null,reason:U,event:B.event??null};_.error(`[plane-link] DEAD-LETTER ${B.trackId} seq ${B.seq} (${A.type??"?"}): plane rejected it permanently (${U}) \u2014 kept in ${Me}`),O=O.then(async()=>{await tl.mkdir(Kt.dirname(Me),{recursive:!0}),await tl.appendFile(Me,JSON.stringify(A)+`
|
|
659
|
-
`)}).catch(L=>_.error(`[plane-link] dead-letter write failed: ${L?.message||L}`))}function qb(B,U,A,L=null){if(!Array.isArray(B)||!B.length)return;let te=new Set,xe=Date.now();for(let Ee of B){let Ve=Z.get(Ee);Ve&&(A?(Z.delete(Ee),Wb(Ve,U),(Ae[Ve.trackId]??0)<Ve.seq&&(Ae[Ve.trackId]=Ve.seq),te.add(Ve.trackId)):(Ve.nacks++,Ve.retryAt=xe+Math.max(1e3,Number(L)||T)))}for(let Ee of te)gf(Ee);ai()}function Kb(B=Date.now()){let U=1/0;for(let A of Z.values())A.firstSentAt<U&&(U=A.firstSentAt);return U===1/0?0:B-U}function Gb(){if(!P||!Z.size)return;let B=Date.now(),U=Kb(B);if(U<j||me!=null&&B-me<j||Y==="http"&&Qe||ge>B)return;z++;let A=Math.min(M*2**(z-1),VI);if(Te==null){Te=B-U,_.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(U/1e3)}s with ${Z.size} event(s) in flight (${Y} door) \u2014 the plane is not answering appends`);try{I?.({since:Te,unacked:Z.size,oldestAgeMs:U,mode:Y})}catch(L){_.error(`[plane-link] onDegraded failed: ${L?.message||L}`)}}if(Y==="http"){Qe=!0,oe=B+A,_.error(`[plane-link] ingest circuit OPEN (stall #${z}); probing /v1/ingest/health in ${Math.round(A/1e3)}s`);return}ge=B+A,_.error(`[plane-link] closing the link and redialing in ${Math.round(A/1e3)}s (stall redial #${z})`);try{v?.terminate()}catch{}}function bf(){if(!P)return;let B=Date.now();if(Y==="http"&&Qe)return;let U=[...Z.values()].filter(L=>L.event&&L.retryAt<=B&&!(Y==="http"&&jt.has(L.trackId)));if(!U.length)return;U.sort((L,te)=>L.trackId===te.trackId?L.seq-te.seq:L.trackId<te.trackId?-1:1),_.log(`[plane-link] re-sending ${U.length} unacked event(s) the plane never confirmed`);let A=Y==="http"?Fe:wo;if(Y==="http"){let L=new Map;for(let te of U)(L.get(te.trackId)??L.set(te.trackId,[]).get(te.trackId)).push(te);for(let[,te]of L){if(Le>=yy)return;si(te.slice(0,A).map(xe=>({trackId:xe.trackId,event:xe.event})))}return}for(let L=0;L<U.length;L+=A){let te=U.slice(L,L+A).map(xe=>({trackId:xe.trackId,event:xe.event}));if(!si(te))return}}async function BM(B=null){for(;;){if(!P)return!1;let U=Z.size<F,A=Y!=="http"||Le<yy&&!Qe&&(!B||!jt.has(B));if(U&&A)return!0;await new Promise(L=>setTimeout(L,100))}}function kf(){if(m=null,!P||!x.length)return;let B=x;if(x=[],Y!=="http"){for(let A=0;A<B.length;A+=wo)si(B.slice(A,A+wo));return}let U=new Map;for(let A of B)(U.get(A.trackId)??U.set(A.trackId,[]).get(A.trackId)).push(A);for(let[A,L]of U){if(jt.has(A)||Le>=yy||Qe){x.push(...L);continue}for(let te=0;te<L.length;te+=Fe)si(L.slice(te,te+Fe))}x.length&&!m&&(m=setTimeout(kf,zI),m.unref?.())}let jM=B=>{let U=new Map;for(let{trackId:A,event:L}of B)(U.get(A)??U.set(A,[]).get(A)).push(L);return[...U].map(([A,L])=>({trackId:A,events:L}))},$o=(B,U,A,{progress:L})=>{let te=Date.now();for(let{event:xe}of B){let Ee=Z.get(xe.id);Ee&&(Ee.nacks++,Ee.retryAt=te+Math.max(1e3,A||T))}L&&ai()};async function LM(B){let U=new Set(B.map(A=>A.trackId));for(let A of U)jt.add(A);Le++;try{let A=await S(`${Q}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:jM(B)}),signal:AbortSignal.timeout(J)}),L=(Number(A.headers.get("retry-after"))||0)*1e3;if(A.status===200){let te=await A.json();Fe=wo;for(let xe of te.results??[]){yf(xe.acked??[]);let Ee=(Ve,$t)=>{let Yt=new Map;for(let st of Ve??[])(Yt.get(st.reason)??Yt.set(st.reason,[]).get(st.reason)).push(st.id);for(let[st,Zb]of Yt)qb(Zb,st,$t,te.retryAfterMs??null)};Ee(xe.rejected,!0),Ee(xe.deferred,!1)}yf(te.discarded??[]),ai();return}if(A.status===429){$o(B,"overloaded",L||5e3,{progress:!0});return}if(A.status===413&&B.length>1){Fe=Math.max(1,Math.floor(B.length/2)),_.error(`[plane-link] ingest request too large (${B.length} events) \u2014 halving batches to ${Fe}`),$o(B,"too_large",1e3,{progress:!0});return}if(A.status===413){let te=Z.get(B[0].event.id);te&&(Z.delete(te.event.id),Wb(te,"too_large"),(Ae[te.trackId]??0)<te.seq&&(Ae[te.trackId]=te.seq),gf(te.trackId)),ai();return}if(A.status===410){wf({reason:"removed",via:"410"}),$o(B,"http_410",6e4,{progress:!1});return}if(A.status===401||A.status===403){let{tripped:te,holdMs:xe}=Ps();if(te&&_.error(`[plane-link] holding every plane call for ${Math.round(xe/6e4)} min \u2014 the ingest door refused this node's token three times in a row`),Date.now()-Pl>=JI){Pl=Date.now();let Ee="";try{Ee=(await A.json())?.error??""}catch{}_.error(`[plane-link] plane refused ingest (HTTP ${A.status}${Ee?`: ${Ee}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}$o(B,`http_${A.status}`,Math.max(6e4,fi()),{progress:!1});return}if(A.status===400){_.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${B.length} event(s) for retry; this is a bug, not data`),$o(B,"http_400",6e4,{progress:!1});return}$o(B,`http_${A.status}`,L||5e3,{progress:!1})}catch(A){let L=A?.name==="TimeoutError"||A?.name==="AbortError";L&&B.length>1&&(Fe=Math.max(1,Math.floor(B.length/2)),_.error(`[plane-link] ingest request of ${B.length} event(s) outlived its ${J} ms deadline \u2014 halving batches to ${Fe}`)),$o(B,L?"timeout":"network",5e3,{progress:!1})}finally{Le--;for(let A of U)jt.delete(A)}}async function FM(){if(Y!=="http"||!Qe||!P||ye)return;let B=Date.now();if(!(oe>B||Ds(B))){ye=!0;try{let U=await S(`${Q}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(J)});if(!U.ok)throw new Error(`HTTP ${U.status}`);_.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Qe=!1,oe=0,ge=Date.now()+J+T+1e3;for(let A of Z.values())A.retryAt=Math.min(A.retryAt,Date.now());bf()}catch(U){z++;let A=Math.min(M*2**(z-1),VI);oe=Date.now()+A,_.error(`[plane-link] ingest door still not answering (${U?.message||U}); next probe in ${Math.round(A/1e3)}s`)}finally{ye=!1}}}function Vb(){let B=Date.now();return{mode:Y,unacked:Z.size,oldestUnackedAgeMs:Kb(B),lastProgressAt:me,degradedSince:Te,stallRedials:z,deadLettered:Ge,http:Y==="http"?{inFlight:Le,circuitOpen:Qe,nextProbeInMs:Qe?Math.max(0,oe-B):0,batchCap:Fe}:null}}async function zb(){if(!i)return;let B;try{B=await i()}catch(A){_.error("[plane-link] metrics sample failed:",A?.message||A);return}let U=null;try{U=c?.()??null}catch{}B&&ut({v:ft,ch:"ctl",type:"metrics",metrics:{...B,planeLink:Vb(),...U?{delivery:U}:{}}})}function UM(){i&&(Xn&&clearInterval(Xn),zb(),Xn=setInterval(zb,u),Xn.unref?.())}async function HM(){let B;try{B=await o()}catch(U){_.error("[plane-link] backfill listTracks failed:",U?.message||U);return}ut({v:ft,ch:"ctl",type:"tracks",ids:B.filter(U=>!U.transferredTo).map(U=>U.id).filter(U=>typeof U=="string")});for(let U of B){if(!P)return;let A;try{A=await q(U)}catch{continue}let L=qe[U.id]??0,te=A.filter(Ee=>Ee.seq>L&&typeof Ee.id=="string"),xe=Y==="http"?Fe:wo;for(let Ee=0;Ee<te.length;Ee+=xe){if(!await BM(U.id))return;let Ve=te.slice(Ee,Ee+Math.min(xe,Y==="http"?Fe:wo)).map($t=>({trackId:U.id,event:$t}));if(!si(Ve))return}}}function Jb(B){!P||!B?.trackId||typeof B.id!="string"||(x.push({trackId:B.trackId,event:B}),m||(m=setTimeout(kf,zI),m.unref?.()))}let ii=new Map;async function WM(B){let{reqId:U,method:A,path:L,headers:te={},body:xe}=B,Ee=Object.fromEntries(Object.entries(te).filter(([,$t])=>$t!=null)),Ve=new AbortController;ii.set(U,Ve);try{if(B.host){await qM(B,Ee,Ve);return}y&&(Ee["x-bostrat-token"]=y);let $t=await fetch(g+L,{method:A,headers:Ee,body:xe?Buffer.from(xe,"base64"):void 0,signal:Ve.signal}),Yt=Object.fromEntries($t.headers);for(let st of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Yt[st];if(Yt["content-type"]||(Yt["content-type"]="application/octet-stream"),ut({v:ft,ch:"control",type:"http_head",reqId:U,status:$t.status,headers:Yt}),$t.body){for await(let st of $t.body)if(!ut({v:ft,ch:"control",type:"http_data",reqId:U,data:Buffer.from(st).toString("base64")}))break}ut({v:ft,ch:"control",type:"http_end",reqId:U,error:null})}finally{ii.delete(U)}}function qM(B,U,A){let{reqId:L,method:te,path:xe,body:Ee}=B,Ve=new URL(g);return new Promise($t=>{let Yt=ZH.request({host:Ve.hostname,port:Ve.port,method:te,path:xe,headers:{...U,host:B.host},signal:A.signal},st=>{let{connection:Zb,"keep-alive":XG,"transfer-encoding":ZG,upgrade:QG,...KM}=st.headers;ut({v:ft,ch:"control",type:"http_head",reqId:L,status:st.statusCode||502,headers:KM}),st.on("data",GM=>{ut({v:ft,ch:"control",type:"http_data",reqId:L,data:Buffer.from(GM).toString("base64")})||st.destroy()}),st.on("end",()=>{ut({v:ft,ch:"control",type:"http_end",reqId:L,error:null}),$t()}),st.on("error",()=>{ut({v:ft,ch:"control",type:"http_end",reqId:L,error:"view upstream error"}),$t()})});Yt.on("error",st=>{ut({v:ft,ch:"control",type:"http_end",reqId:L,error:st?.message||"view request failed"}),$t()}),Ee&&Yt.write(Buffer.from(Ee,"base64")),Yt.end()})}function Yb(){if(ce||oi)return;v=new gy(e,{headers:{authorization:`Bearer ${t}`}}),v.on("open",async()=>{let U=null;try{U=await s?.()||null}catch{U=null}ut({v:ft,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:vn,installKind:h,...typeof w=="function"?{updatePolicy:w()}:w?{updatePolicy:w}:{},providers:tW(),...U?{agents:U}:{}})}),v.on("message",U=>{let A;try{A=JSON.parse(U)}catch{return}if(A.ch==="ctl"&&A.type==="hello_ok"){P=!0,be=KI,Ne=null,ak(),_.log(`[plane-link] connected to plane as ${n}`);try{N?.()}catch{}if(typeof A.hashKey=="string"&&A.hashKey)try{l?.(A.hashKey)}catch{}A.minNodeVersion&&vn&&nl(vn,A.minNodeVersion)&&_.error(`[plane-link] this node is bostrat-node ${vn}; the plane asks for \u2265${A.minNodeVersion} \u2014 update with: ${_p(h)}`);try{p?.(typeof A.updatePolicy=="string"?A.updatePolicy:null)}catch{}let L=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;if(L&&vn&&nl(vn,L)&&!K.has(L)){K.add(L),_.log(`[plane-link] bostrat-node ${L} is available (this node runs ${vn}) \u2014 ${_p(h)}`);try{d?.({current:vn,latest:L,min:A.minNodeVersion??null,installKind:h,required:!!(A.minNodeVersion&&nl(vn,A.minNodeVersion))})}catch(xe){_.error(`[plane-link] update notice failed: ${xe?.message||xe}`)}}let te=A.ingest==="http";Y=D==="ws"?"ws":D==="http"||te?"http":"ws",D==="http"&&!te&&_.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),Y==="http"&&_.log("[plane-link] spine rides the HTTPS ingest door"),Qe=!1,oe=0,Fe=wo,lt&&clearInterval(lt),lt=setInterval(()=>{ut({v:ft,ch:"ctl",type:"ping"}),Gb(),FM().catch(()=>{}),bf(),x.length&&!m&&kf()},$),lt.unref?.(),UM(),HM().catch(xe=>_.error("[plane-link] backfill failed:",xe?.message||xe));return}if(A.ch==="ctl"&&A.type==="hello_refused"){let L=typeof A.minNodeVersion=="string"?A.minNodeVersion:null,te=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;_.error(`[plane-link] plane REFUSED this node: bostrat-node ${vn??"?"} is below its minimum ${L??"?"} \u2014 ${A.fix||_p(h)}`),be=GI,Ne=0;try{f?.({current:vn,min:L,latest:te,fix:A.fix||_p(h),installKind:h})}catch(xe){_.error(`[plane-link] refusal handler failed: ${xe?.message||xe}`)}return}if(A.ch==="ctl"&&A.type==="removed"){ut({v:ft,ch:"ctl",type:"removed_ack",nodeId:n}),wf({reason:typeof A.reason=="string"?A.reason:"removed",at:Number(A.at)||Date.now(),via:"ctl"});return}if(A.ch==="ctl"&&A.type==="update_policy"){try{p?.(typeof A.mode=="string"?A.mode:null)}catch{}return}if(A.ch==="ctl"&&A.type==="usage_caps"){Xu(A.caps??{},{source:"plane",updatedAt:A.updatedAt??Date.now()}).then(L=>_.log(`[plane-link] spend caps ${Object.keys(L.caps).length?`updated (${Object.keys(L.caps).join(", ")})`:"cleared"} from plane`)).catch(L=>_.error("[plane-link] spend-caps push rejected:",L?.message||L));return}if(A.ch==="ctl"&&A.type==="transferred"&&Array.isArray(A.tracks)){Promise.resolve().then(()=>a?.(A.tracks)).catch(L=>_.error("[plane-link] transfer notice failed:",L?.message||L));return}if(A.ch==="events"&&A.type==="ack"&&Array.isArray(A.ids)){yf(A.ids);return}if(A.ch==="events"&&A.type==="nack"&&Array.isArray(A.ids)){qb(A.ids,A.reason,A.permanent===!0,A.retryAfterMs??null);return}if(A.ch==="control"&&A.type==="http_open"){WM(A).catch(L=>ut({v:ft,ch:"control",type:"http_end",reqId:A.reqId,error:L?.message||"tunnel error"}));return}if(A.ch==="control"&&A.type==="http_cancel"){ii.get(A.reqId)?.abort();return}if(A.ch==="attach"&&A.type==="open"){let L=new gy(H+A.path,Array.isArray(A.protocols)?A.protocols:[],A.host?{headers:{host:A.host}}:void 0);X.set(A.streamId,L),pe.set(A.streamId,[]),L.on("open",()=>{let xe=pe.get(A.streamId)||[];pe.delete(A.streamId);for(let{buf:Ee,bin:Ve}of xe)L.send(Ee,{binary:Ve})}),L.on("message",(xe,Ee)=>{let Ve=Ee?xe:Buffer.from(String(xe));ut({v:ft,ch:"attach",type:"data",streamId:A.streamId,data:Ve.toString("base64"),...Ee?{bin:!0}:{}})});let te=()=>{pe.delete(A.streamId),X.delete(A.streamId)&&ut({v:ft,ch:"attach",type:"close",streamId:A.streamId})};L.on("close",te),L.on("error",te);return}if(A.ch==="attach"&&A.type==="data"){let L=X.get(A.streamId);if(!L)return;let te=Buffer.from(A.data,"base64"),xe=A.bin===!0,Ee=pe.get(A.streamId);Ee?Ee.push({buf:te,bin:xe}):L.send(te,{binary:xe});return}if(A.ch==="attach"&&A.type==="close"){let L=X.get(A.streamId);X.delete(A.streamId),pe.delete(A.streamId),L?.close();return}});let B=()=>{P&&_.log("[plane-link] disconnected from plane"),P=!1,lt&&(clearInterval(lt),lt=null),Xn&&(clearInterval(Xn),Xn=null),Z.clear(),Ae={},x=[],m&&(clearTimeout(m),m=null),jt.clear();for(let L of X.values())L.close();X.clear(),pe.clear();for(let L of ii.values())L.abort();if(ii.clear(),ce||gt)return;Ne==null&&(Ne=Date.now());let U=Date.now()-Ne<nW,A=Math.max(U?rW+Math.random()*oW:be,ge-Date.now(),fi());gt=setTimeout(()=>{gt=null,Yb()},A),gt.unref?.(),U||(be=Math.min(be*2,GI))};v.on("close",B),v.on("error",U=>{let A=/Unexpected server response: (\d+)/.exec(U?.message||"")?.[1];if(A==="410"){wf({reason:"removed",via:"410"});return}if(A==="401"||A==="403"){let{tripped:L,holdMs:te}=Ps();L?_.error(`[plane-link] holding every plane call for ${Math.round(te/6e4)} min \u2014 three credential refusals in a row (HTTP ${A}) mean the token is revoked or unknown, not that the plane is down; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN. Next dial in ${Math.round(te/6e4)} min.`):Date.now()-Pl>=JI&&(Pl=Date.now(),_.error(`[plane-link] plane refused this node's credentials (HTTP ${A}) \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)`))}B()})}Xe.on("event",Jb),NM().then(Yb);function Xb({bye:B=!0}={}){ce=!0,Xe.off("event",Jb),gt&&clearTimeout(gt),rt&&clearTimeout(rt),lt&&clearInterval(lt),Xn&&clearInterval(Xn),m&&clearTimeout(m),B&&ut({v:ft,ch:"ctl",type:"bye",reason:"shutdown"}),v?.close()}return{stop:()=>Xb(),status:()=>({connected:P,nodeId:n,cursor:{...qe},inflight:Z.size,...Vb(),auth:ik(),dormant:oi,removed:Hl()}),_tick:()=>{Gb(),bf()}}}bu();var $p=(()=>{try{return mW(import.meta.url)("../package.json").version||null}catch{return null}})(),wW=process.env.BOSTRAT_STATE_DIR||wt.join(process.env.HOME||fW.tmpdir(),".bostrat"),e$=wt.join(wW,"self-update"),Rp=wt.join(e$,"status.json"),gW=1440*6e4,yW=6e4,rl=new Set(["npm-global","git-checkout"]);function t$({kind:e=ks(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:rl.has(e)?e==="git-checkout"||bW(t)?"auto":"prompt":"off"}function bW(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Gt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function kW({kind:e,to:t,from:n=$p,statusFile:r=Rp,logFile:o=wt.join(e$,"last.log"),port:s=Number(process.env.PORT)||3362,npmPrefix:a=null,serviceName:i=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:c=typeof process.getuid=="function"?process.getuid():0,liveDir:l=process.env.BOSTRAT_LIVE_CHECKOUT||wt.resolve(wt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!rl.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 d=(g,y="")=>`write_status ${Gt(g)} ${y}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Gt(i)}`,f=`
|
|
658
|
+
`);SH=new Set(["claude","codex","cursor"]);Gc=new Set,AH=e=>Gc.has(e);TH=9e4;pI={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};Sg=new Map;$g=120;sy=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Oo(e.hookToken),createdAt:Date.now()});ws=new Map,Wa=e=>ws.get(e)||(Dt?de(Dt,e)?.handoff:null)||null;iy=6e4,kn=(e,t,n=15e3)=>cp("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),ap=new Map,cy=e=>ap.get(e)||null;CH=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;tp=new Map;DH=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,BH=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,La=G.join(Vn,"worktrees"),Ca=[Hc,np],Bt=new Map,jH=e=>Bt.get(e)||(Dt?Dt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,ks=e=>{let t=new Map([...Bt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Dt?de(Dt,e):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))t.has(r)||t.set(r,o);return[...t.values()].sort((r,o)=>r.startedAt-o.startedAt)},Tp=e=>({id:e.id,trackId:e.trackId,trackName:e.trackName,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,reason:e.reason||null,step:e.step,failedStep:e.failedStep||null,box:e.box,branch:e.branch,base:e.base,repos:e.repos||null,dir:e.dir,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt});el=e=>PI(e.trackId,e.id,Tp(e));Ep=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",zc=class extends Error{}});ft();import $e from"node:path";import vt from"node:fs";import VG from"node:readline";import{fileURLToPath as zG}from"node:url";import Jt from"express";import JG from"node:http";import YG from"node:https";import Ol from"node:os";import{randomUUID as XG}from"node:crypto";import{WebSocketServer as ZG}from"ws";ft();import kP from"node-pty";async function O0(e,t,n={}){if(!Be(t)){bu(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Hr()){bu(e,`host tmux server not running on ${Ft}`),e.close(1011,"tmux server unavailable");return}if(!await be(t)){bu(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=R0(n.cols,120,M0),o=R0(n.rows,32,C0),s;try{s=kP.spawn(ne,["-S",Ft,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){bu(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&om(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(om(e,{type:"exit",code:a??null,signal:i??null}),e.close(1e3,"tmux exited"))}),e.on("message",a=>{let i;try{i=JSON.parse(a.toString())}catch{return}if(!(!i||typeof i!="object")){if(i.type==="data"&&typeof i.data=="string")s.write(i.data);else if(i.type==="resize"&&AP(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),e.on("close",()=>{try{s.kill()}catch{}SP(t)})}var xP=6,vP=250;async function SP(e,t=xP,n=vP){for(let r=0;r<t;r++){if(await Lo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var M0=20,C0=6;function AP(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=M0&&Number(t)>=C0}function R0(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function om(e,t){try{e.send(JSON.stringify(t))}catch{}}function bu(e,t){om(e,{type:"error",message:t})}function N0(e){let t=typeof e=="string"&&e?e:"/",n=t.indexOf("?"),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n+1),s=r.match(/^\/api\/attach\/([^/]+)$/);if(!s)return{ok:!1,status:404};let a;try{a=decodeURIComponent(s[1])}catch{return{ok:!1,status:400}}let i=new URLSearchParams(o);return{ok:!0,sessionName:a,cols:Number(i.get("cols"))||void 0,rows:Number(i.get("rows"))||void 0}}dn();xu();qm();gr();import{createRequire as QG}from"node:module";var zH=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function wy({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[]}={}){let s=[];for(let a of e)!a||a.archivedAt&&!a.archiving||a.transferredTo||(a.working&&s.push(`working:${a.id}`),a.prompted&&s.push(`prompted:${a.id}`),(n(a.id)??[]).length&&s.push(`queued:${a.id}`),(a.boxes||[]).some(i=>i?.role==="subtask"&&i?.state==="live")&&s.push(`subtask:${a.id}`),(r(a.id)??[]).length&&s.push(`job:${a.id}`),Object.values(a.subtasks||{}).some(zH)&&s.push(`merge-back:${a.id}`),(o(a.id)??[]).length&&s.push(`pr:${a.id}`));return t.some(a=>a?.state==="live"||a?.state==="starting")&&s.push("views"),{busy:s.length>0,reasons:s}}me();lh();ft();import ZH from"node:fs/promises";import gy from"node:fs/promises";var JH=100;async function YH(e){let t;try{t=await gy.readFile(`/proc/${e}/stat`,"utf8")}catch{return null}let n=t.lastIndexOf(")");if(n<0)return null;let r=t.slice(n+2).split(" "),o=Number(r[1]),s=Number(r[11])+Number(r[12]);return!Number.isFinite(o)||!Number.isFinite(s)?null:{ppid:o,cpuMs:s/JH*1e3,ioBytes:await XH(e)}}async function XH(e){let t;try{t=await gy.readFile(`/proc/${e}/io`,"utf8")}catch{return 0}let n=r=>Number(t.match(new RegExp(`^${r}: (\\d+)$`,"m"))?.[1]||0);return n("rchar")+n("wchar")}async function UI(e){let t=[...new Set((e||[]).map(Number).filter(l=>Number.isFinite(l)&&l>0))];if(!t.length)return{procs:0,cpuMs:0,ioBytes:0};let n;try{n=await gy.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await YH(l);u&&r.set(Number(l),u)}));let o=new Map;for(let[l,u]of r)o.has(u.ppid)||o.set(u.ppid,[]),o.get(u.ppid).push(l);let s=new Set,a=t.filter(l=>r.has(l));for(let l of a)s.add(l);let i=0,c=0;for(let l=0;l<a.length;l++){let u=a[l];i+=r.get(u).cpuMs,c+=r.get(u).ioBytes;for(let d of o.get(u)||[])s.has(d)||(s.add(d),a.push(d))}return{procs:s.size,cpuMs:Math.round(i),ioBytes:c}}var QH=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,eW=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,tW=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,nW=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,rW=5*6e4,WI={readOpenJobs:lS,statFile:async e=>{try{let t=await ZH.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Zr(e.agent).updatedAt(e),panePids:E0,treeStats:UI,appendEvent:C},xn=new Map,HI=new Map,yy=new Map,by=(e,t,n)=>`${e}|${t}|${n}`;function qI(e){let t=[];for(let n of e||[])if(!(!n||n.archivedAt&&!n.archiving||n.transferredTo))for(let r of n.boxes||[])r?.state==="live"&&r.name&&t.push({track:n,box:r});return t}async function KI(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=HI.get(e.name);if(o&&o.mtime===r&&t-o.at<rW)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return HI.set(e.name,{at:t,mtime:r,jobs:s}),s}async function oW(e,t,n){let r=await n.panePids(e.name),o=r.length?await n.treeStats(r):null,s=null;try{s=await n.updatedAt(e)}catch{s=null}return{at:t,cpuMs:o?.cpuMs??null,ioBytes:o?.ioBytes??null,procs:o?.procs??null,mtime:s}}async function sW(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function aW(e,t){if(!e)return!0;let n=Math.max(1,(t.at-e.at)/1e3);return t.mtime!=null&&e.mtime!=null&&t.mtime>e.mtime||t.procs!=null&&e.procs!=null&&t.procs>e.procs||t.cpuMs!=null&&e.cpuMs!=null&&(t.cpuMs-e.cpuMs)/n>=tW||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=nW}function GI(e,t,n,r){let o=[];for(let s of n){let a=by(e.id,t.name,s.id),i=xn.get(a);i?i.job=s:xn.set(a,{trackId:e.id,boxName:t.name,agent:t.agent||null,job:s,firstSeenAt:r,quiet:0,stalled:!1}),o.push(a)}return o}async function VI(e,{now:t=Date.now(),deps:n=WI}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of qI(e)){let i=await KI(a,t,n);for(let l of i)o.add(by(s.id,a.name,l.id));let c=GI(s,a,i,t).filter(l=>!xn.get(l).stalled).map(l=>xn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...xn.keys()])o.has(s)||xn.delete(s);return r}async function iW(e,{now:t=Date.now(),deps:n=WI}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=qI(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...xn])s.has(i.boxName)||xn.delete(a);for(let{track:a,box:i}of o){let c=await KI(i,t,n),l=new Set(c.map(w=>by(a.id,i.name,w.id)));for(let[w,m]of[...xn])m.boxName===i.name&&!l.has(w)&&xn.delete(w);if(!c.length){yy.delete(i.name);continue}let u=GI(a,i,c,t),d=await oW(i,t,n),p=yy.get(i.name);yy.set(i.name,d);let f=aW(p,d);for(let w of u){let m=xn.get(w);r.checked++;let g=await sW(m.job,n),y=!!g&&!!m.file&&(g.size>m.file.size||g.mtimeMs>m.file.mtimeMs),x=!!g&&!m.file;if(m.file=g??m.file,f||y||x){m.quiet=0,m.lastProgressAt=t,m.stalled=!1,r.progressing++;continue}if(m.stalled||(m.quiet++,r.quiet++,m.quiet<eW))continue;m.stalled=!0,m.stalledAt=t,r.stalled.push(w);let I=t-(m.lastProgressAt??m.firstSeenAt);try{await n.appendEvent(a,{type:"job.stalled",actor:"orchestrator",source:"orchestrator",boxId:i.name,provider:i.agent||null,payload:{id:m.job.id,kind:m.job.kind||"agent",name:m.job.name||null,detail:m.job.detail||null,startedTs:m.job.ts??m.firstSeenAt,quietMs:I,checks:m.quiet}})}catch{}console.log(`[job-watch] ${a.id}/${i.name} job ${m.job.id} (${m.job.name||m.job.kind}) quiet for ${Math.round(I/6e4)}m over ${m.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function zI({listTracks:e,intervalMs:t=QH}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await iW(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}me();Rc();Dn();Cd();Zt();var Ip=60*6e4,cW=1440*6e4,lW=new Set(["merged","closed","lost"]),tl=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function uW({trackId:e,shipPending:t=null,links:n=[],observers:r=0,now:o=Date.now()}={}){let s=[];t&&Number.isFinite(Number(t.ts))&&o-Number(t.ts)<=qw&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||lW.has(a.state))continue;let i=[a.ciFix,a.reconcile,a.ciFixAwait,a.reconcileAwait];if(!(a.trackId===e||i.some(d=>d?.trackId===e)))continue;let l=a.number??"?";a.ciFix&&tl(a.ciFix.delegatedAt,Ip,o)&&s.push(`ci-fix#${l}`),a.reconcile&&tl(a.reconcile.delegatedAt,Ip,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&tl(a.ciFixAwait.since,Ip,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&tl(a.reconcileAwait.since,Ip,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&tl(u,cW,o)&&s.push(`auto-merge#${l}`)}return s}var $p=new Map;Je.on("event",e=>{e?.trackId&&$p.delete(e.trackId)});async function dW(e){if($p.has(e.id))return $p.get(e.id);let t=await q(e).catch(()=>[]),n=_a(t,-1/0);return $p.set(e.id,n),n}async function JI(e,{now:t=Date.now()}={}){let n=new Map,r=await mn().catch(()=>[]);for(let o of e||[]){if(!o||Le(o))continue;let s=uW({trackId:o.id,shipPending:await dW(o),links:r,observers:jT(o.id),now:t});s.length&&n.set(o.id,s)}return n}hg();import i$ from"node:fs";import bo from"node:fs/promises";import $W from"node:os";import ht from"node:path";import{spawn as RW}from"node:child_process";import{createRequire as OW}from"node:module";me();td();import qa from"node:fs";import rl from"node:fs/promises";import mW from"node:http";import Kt from"node:path";import Op from"node:os";import{createRequire as hW}from"node:module";import xy from"ws";import pW from"node:path";import fW from"node:os";var nl=process.env.BOSTRAT_STATE_DIR||pW.join(process.env.HOME||fW.tmpdir(),".bostrat");function ky(e=process.env){let t=(e.BOSTRAT_HOST||"").trim();if(t!=="all")return t||(e.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function YI(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=ky(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function XI(e){let t=String(e||"").trim();if(!t)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:`wss://${t}`,r;try{r=new URL(n)}catch{return t}let o={"https:":"wss:","http:":"ws:","wss:":"wss:","ws:":"ws:"}[r.protocol];return o?(r.protocol=o,(r.pathname===""||r.pathname==="/")&&(r.pathname="/v1/node"),r.toString()):t}Mf();var vn=(()=>{try{return hW(import.meta.url)("../package.json").version||null}catch{return null}})(),Sy=process.env.BOSTRAT_STATE_DIR||Kt.join(process.env.HOME||Op.tmpdir(),".bostrat"),o$=Kt.join(Sy,"plane-link","removed.json");function ZI(e){return typeof e!="string"||e.length<8?"\u2022\u2022\u2022\u2022":`${e.slice(0,6)}\u2026${e.slice(-4)}`}function wW(e=o$){try{let t=JSON.parse(qa.readFileSync(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function xs({env:e=process.env,pkgDir:t=Kt.resolve(Kt.dirname(new URL(import.meta.url).pathname),".."),exists:n=qa.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(Kt.join(t,"..",".git"))?"git-checkout":"dev"}function ol(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!1;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function Rp(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 gW({home:e=process.env.HOME||Op.homedir(),env:t=process.env}={}){let n=r=>{try{return qa.statSync(r),!0}catch{return!1}};return{claude:n(Kt.join(e,".claude",".credentials.json")),codex:n(Kt.join(t.CODEX_HOME||Kt.join(e,".codex"),"auth.json"))}}var dt=1,QI=1e3,e$=3e4,yW=6e4,bW=1500,kW=500,yo=100,xW=2e3,vW=25e3,SW=6e4,s$=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},AW=s$(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),TW=3e4,t$=10*6e4,EW=400,n$=250,_W=s$(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),vy=4,IW=6e4,r$=6e4;function a$({url:e,token:t,nodeId:n=Op.hostname(),name:r=Op.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,onViewBase:u=null,metricsMs:d=IW,onUpdateAvailable:p=null,onUpdatePolicy:f=null,onHelloRefused:w=null,updatePolicy:m=null,installKind:g=xs(),selfUrl:y=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:x=null,removedMarkerFile:b=o$,onRemoved:I=null,onDegraded:$=null,onRecovered:P=null,onConnected:F=null,ingestMode:B=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:T=AW,unackedRetryMs:_=SW,pingMs:U=vW,maxInflightEvents:J=EW,httpTimeoutMs:R=_W,stallBackoffMinMs:A=TW,fetchImpl:M=globalThis.fetch,log:N=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=XI(e);let K=y.replace(/^http/,"ws"),Y=new Set,fe=new Map,Ie=new Map,Ce=Kt.join(Sy,"plane-link","cursor.json"),X=Kt.join(Sy,"plane-link","dead-letter.ndjson"),et=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),Ee={},se={},ee=new Map,Oe=null,z=null,we=0,Fe=0,O=0,ce=Promise.resolve(),ve="ws",wt=0,Q=!1,ge=0,pt=!1,rt=yo,k=new Set,h=[],v=null,D=null,re=!1,ke=!1,Pe=QI,St=null,tt=null,At=null,Zn=null,Qn=null,bf=!1,jl=0,ai=!1,Mr=wW(b);if(Mr)if(Mr.tokenPreview===ZI(t))ai=!0,Of({reason:Mr.reason??"removed",at:Mr.at??null,nodeId:Mr.nodeId??n}),N.error(`[plane-link] this node was REMOVED from the plane (${Mr.reason??"removed"}${Mr.at?` at ${new Date(Mr.at).toISOString()}`:""}) \u2014 not dialing. Re-provision it with a new node token, or delete ${b} to force a dial.`);else try{qa.unlinkSync(b),N.log("[plane-link] stale removed-marker discarded \u2014 the node token changed")}catch{}function kf({reason:j="removed",at:H=Date.now(),via:S="ctl"}={}){if(!ai){ai=!0,Of({reason:j,at:H,nodeId:n,via:S});try{qa.mkdirSync(Kt.dirname(b),{recursive:!0}),qa.writeFileSync(b,JSON.stringify({at:H,reason:j,via:S,nodeId:n,tokenPreview:ZI(t)},null,2))}catch(L){N.error(`[plane-link] could not write ${b}: ${L?.message||L}`)}N.error(`[plane-link] the plane REMOVED this node (${j}, via ${S}) \u2014 going dormant: no more dials, ingest or broker calls. Re-provision with a new node token to reconnect; the box and its data are untouched.`);try{I?.({reason:j,at:H,via:S})}catch{}sk({bye:!1})}}async function YM(){try{Ee=JSON.parse(await rl.readFile(Ce,"utf8"))}catch{Ee={}}}function XM(){bf=!0,!At&&(At=setTimeout(async()=>{if(At=null,!!bf){bf=!1;try{await rl.mkdir(Kt.dirname(Ce),{recursive:!0}),await rl.writeFile(Ce,JSON.stringify(Ee))}catch(j){N.error("[plane-link] cursor flush failed:",j?.message||j)}}},xW),At.unref?.())}function ct(j){return!D||D.readyState!==xy.OPEN?!1:(D.send(JSON.stringify(j)),!0)}function ii(j){let H=Date.now();for(let{trackId:S,event:L}of j){let te=ee.get(L.id);ee.set(L.id,{trackId:S,seq:L.seq,event:L,sentAt:H,firstSentAt:te?.firstSentAt??H,retryAt:H+_,tries:(te?.tries??0)+1,nacks:te?.nacks??0})}return ve==="http"?(tC(j),!0):ct({v:dt,ch:"events",type:"append",events:j})}function ZM(j){let H=null;for(let S of ee.values())S.trackId===j&&(H==null||S.seq<H)&&(H=S.seq);return H}function xf(j){let H=se[j];if(H==null)return;let S=ZM(j),L=S==null?H:Math.min(H,S-1);L>(Ee[j]??0)&&(Ee[j]=L,XM())}function ci(){if(Oe=Date.now(),z!=null){let j=Date.now()-z;N.log(`[plane-link] spine sync recovered after ${Math.round(j/1e3)}s degraded (${we} stall redial(s))`);let H=z;z=null,we=0,Fe=0,Q=!1,ge=0;try{P?.({since:H,downMs:j})}catch(S){N.error(`[plane-link] onRecovered failed: ${S?.message||S}`)}}}function vf(j){if(!Array.isArray(j)||!j.length)return;let H=new Set;for(let S of j){let L=ee.get(S);L&&(ee.delete(S),(se[L.trackId]??0)<L.seq&&(se[L.trackId]=L.seq),H.add(L.trackId))}for(let S of H)xf(S);ci()}function Xb(j,H){O++;let S={at:Date.now(),trackId:j.trackId,seq:j.seq,id:j.event?.id??null,type:j.event?.type??null,reason:H,event:j.event??null};N.error(`[plane-link] DEAD-LETTER ${j.trackId} seq ${j.seq} (${S.type??"?"}): plane rejected it permanently (${H}) \u2014 kept in ${X}`),ce=ce.then(async()=>{await rl.mkdir(Kt.dirname(X),{recursive:!0}),await rl.appendFile(X,JSON.stringify(S)+`
|
|
659
|
+
`)}).catch(L=>N.error(`[plane-link] dead-letter write failed: ${L?.message||L}`))}function Zb(j,H,S,L=null){if(!Array.isArray(j)||!j.length)return;let te=new Set,xe=Date.now();for(let Te of j){let Ke=ee.get(Te);Ke&&(S?(ee.delete(Te),Xb(Ke,H),(se[Ke.trackId]??0)<Ke.seq&&(se[Ke.trackId]=Ke.seq),te.add(Ke.trackId)):(Ke.nacks++,Ke.retryAt=xe+Math.max(1e3,Number(L)||_)))}for(let Te of te)xf(Te);ci()}function Qb(j=Date.now()){let H=1/0;for(let S of ee.values())S.firstSentAt<H&&(H=S.firstSentAt);return H===1/0?0:j-H}function ek(){if(!re||!ee.size)return;let j=Date.now(),H=Qb(j);if(H<T||Oe!=null&&j-Oe<T||ve==="http"&&Q||Fe>j)return;we++;let S=Math.min(A*2**(we-1),t$);if(z==null){z=j-H,N.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(H/1e3)}s with ${ee.size} event(s) in flight (${ve} door) \u2014 the plane is not answering appends`);try{$?.({since:z,unacked:ee.size,oldestAgeMs:H,mode:ve})}catch(L){N.error(`[plane-link] onDegraded failed: ${L?.message||L}`)}}if(ve==="http"){Q=!0,ge=j+S,N.error(`[plane-link] ingest circuit OPEN (stall #${we}); probing /v1/ingest/health in ${Math.round(S/1e3)}s`);return}Fe=j+S,N.error(`[plane-link] closing the link and redialing in ${Math.round(S/1e3)}s (stall redial #${we})`);try{D?.terminate()}catch{}}function Sf(){if(!re)return;let j=Date.now();if(ve==="http"&&Q)return;let H=[...ee.values()].filter(L=>L.event&&L.retryAt<=j&&!(ve==="http"&&k.has(L.trackId)));if(!H.length)return;H.sort((L,te)=>L.trackId===te.trackId?L.seq-te.seq:L.trackId<te.trackId?-1:1),N.log(`[plane-link] re-sending ${H.length} unacked event(s) the plane never confirmed`);let S=ve==="http"?rt:yo;if(ve==="http"){let L=new Map;for(let te of H)(L.get(te.trackId)??L.set(te.trackId,[]).get(te.trackId)).push(te);for(let[,te]of L){if(wt>=vy)return;ii(te.slice(0,S).map(xe=>({trackId:xe.trackId,event:xe.event})))}return}for(let L=0;L<H.length;L+=S){let te=H.slice(L,L+S).map(xe=>({trackId:xe.trackId,event:xe.event}));if(!ii(te))return}}async function QM(j=null){for(;;){if(!re)return!1;let H=ee.size<J,S=ve!=="http"||wt<vy&&!Q&&(!j||!k.has(j));if(H&&S)return!0;await new Promise(L=>setTimeout(L,100))}}function Af(){if(v=null,!re||!h.length)return;let j=h;if(h=[],ve!=="http"){for(let S=0;S<j.length;S+=yo)ii(j.slice(S,S+yo));return}let H=new Map;for(let S of j)(H.get(S.trackId)??H.set(S.trackId,[]).get(S.trackId)).push(S);for(let[S,L]of H){if(k.has(S)||wt>=vy||Q){h.push(...L);continue}for(let te=0;te<L.length;te+=rt)ii(L.slice(te,te+rt))}h.length&&!v&&(v=setTimeout(Af,n$),v.unref?.())}let eC=j=>{let H=new Map;for(let{trackId:S,event:L}of j)(H.get(S)??H.set(S,[]).get(S)).push(L);return[...H].map(([S,L])=>({trackId:S,events:L}))},Ro=(j,H,S,{progress:L})=>{let te=Date.now();for(let{event:xe}of j){let Te=ee.get(xe.id);Te&&(Te.nacks++,Te.retryAt=te+Math.max(1e3,S||_))}L&&ci()};async function tC(j){let H=new Set(j.map(S=>S.trackId));for(let S of H)k.add(S);wt++;try{let S=await M(`${et}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:eC(j)}),signal:AbortSignal.timeout(R)}),L=(Number(S.headers.get("retry-after"))||0)*1e3;if(S.status===200){let te=await S.json();rt=yo;for(let xe of te.results??[]){vf(xe.acked??[]);let Te=(Ke,Rt)=>{let Yt=new Map;for(let ot of Ke??[])(Yt.get(ot.reason)??Yt.set(ot.reason,[]).get(ot.reason)).push(ot.id);for(let[ot,ak]of Yt)Zb(ak,ot,Rt,te.retryAfterMs??null)};Te(xe.rejected,!0),Te(xe.deferred,!1)}vf(te.discarded??[]),ci();return}if(S.status===429){Ro(j,"overloaded",L||5e3,{progress:!0});return}if(S.status===413&&j.length>1){rt=Math.max(1,Math.floor(j.length/2)),N.error(`[plane-link] ingest request too large (${j.length} events) \u2014 halving batches to ${rt}`),Ro(j,"too_large",1e3,{progress:!0});return}if(S.status===413){let te=ee.get(j[0].event.id);te&&(ee.delete(te.event.id),Xb(te,"too_large"),(se[te.trackId]??0)<te.seq&&(se[te.trackId]=te.seq),xf(te.trackId)),ci();return}if(S.status===410){kf({reason:"removed",via:"410"}),Ro(j,"http_410",6e4,{progress:!1});return}if(S.status===401||S.status===403){let{tripped:te,holdMs:xe}=Ds();if(te&&N.error(`[plane-link] holding every plane call for ${Math.round(xe/6e4)} min \u2014 the ingest door refused this node's token three times in a row`),Date.now()-jl>=r$){jl=Date.now();let Te="";try{Te=(await S.json())?.error??""}catch{}N.error(`[plane-link] plane refused ingest (HTTP ${S.status}${Te?`: ${Te}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}Ro(j,`http_${S.status}`,Math.max(6e4,hi()),{progress:!1});return}if(S.status===400){N.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${j.length} event(s) for retry; this is a bug, not data`),Ro(j,"http_400",6e4,{progress:!1});return}Ro(j,`http_${S.status}`,L||5e3,{progress:!1})}catch(S){let L=S?.name==="TimeoutError"||S?.name==="AbortError";L&&j.length>1&&(rt=Math.max(1,Math.floor(j.length/2)),N.error(`[plane-link] ingest request of ${j.length} event(s) outlived its ${R} ms deadline \u2014 halving batches to ${rt}`)),Ro(j,L?"timeout":"network",5e3,{progress:!1})}finally{wt--;for(let S of H)k.delete(S)}}async function nC(){if(ve!=="http"||!Q||!re||pt)return;let j=Date.now();if(!(ge>j||Bs(j))){pt=!0;try{let H=await M(`${et}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(R)});if(!H.ok)throw new Error(`HTTP ${H.status}`);N.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Q=!1,ge=0,Fe=Date.now()+R+_+1e3;for(let S of ee.values())S.retryAt=Math.min(S.retryAt,Date.now());Sf()}catch(H){we++;let S=Math.min(A*2**(we-1),t$);ge=Date.now()+S,N.error(`[plane-link] ingest door still not answering (${H?.message||H}); next probe in ${Math.round(S/1e3)}s`)}finally{pt=!1}}}function tk(){let j=Date.now();return{mode:ve,unacked:ee.size,oldestUnackedAgeMs:Qb(j),lastProgressAt:Oe,degradedSince:z,stallRedials:we,deadLettered:O,http:ve==="http"?{inFlight:wt,circuitOpen:Q,nextProbeInMs:Q?Math.max(0,ge-j):0,batchCap:rt}:null}}async function nk(){if(!i)return;let j;try{j=await i()}catch(S){N.error("[plane-link] metrics sample failed:",S?.message||S);return}let H=null;try{H=c?.()??null}catch{}j&&ct({v:dt,ch:"ctl",type:"metrics",metrics:{...j,planeLink:tk(),...H?{delivery:H}:{}}})}function rC(){i&&(Qn&&clearInterval(Qn),nk(),Qn=setInterval(nk,d),Qn.unref?.())}async function oC(){let j;try{j=await o()}catch(H){N.error("[plane-link] backfill listTracks failed:",H?.message||H);return}ct({v:dt,ch:"ctl",type:"tracks",ids:j.filter(H=>!H.transferredTo).map(H=>H.id).filter(H=>typeof H=="string")});for(let H of j){if(!re)return;let S;try{S=await q(H)}catch{continue}let L=Ee[H.id]??0,te=S.filter(Te=>Te.seq>L&&typeof Te.id=="string"),xe=ve==="http"?rt:yo;for(let Te=0;Te<te.length;Te+=xe){if(!await QM(H.id))return;let Ke=te.slice(Te,Te+Math.min(xe,ve==="http"?rt:yo)).map(Rt=>({trackId:H.id,event:Rt}));if(!ii(Ke))return}}}function rk(j){!re||!j?.trackId||typeof j.id!="string"||(h.push({trackId:j.trackId,event:j}),v||(v=setTimeout(Af,n$),v.unref?.()))}let li=new Map;async function sC(j){let{reqId:H,method:S,path:L,headers:te={},body:xe}=j,Te=Object.fromEntries(Object.entries(te).filter(([,Rt])=>Rt!=null)),Ke=new AbortController;li.set(H,Ke);try{if(j.host){await aC(j,Te,Ke);return}x&&(Te["x-bostrat-token"]=x);let Rt=await fetch(y+L,{method:S,headers:Te,body:xe?Buffer.from(xe,"base64"):void 0,signal:Ke.signal}),Yt=Object.fromEntries(Rt.headers);for(let ot of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Yt[ot];if(Yt["content-type"]||(Yt["content-type"]="application/octet-stream"),ct({v:dt,ch:"control",type:"http_head",reqId:H,status:Rt.status,headers:Yt}),Rt.body){for await(let ot of Rt.body)if(!ct({v:dt,ch:"control",type:"http_data",reqId:H,data:Buffer.from(ot).toString("base64")}))break}ct({v:dt,ch:"control",type:"http_end",reqId:H,error:null})}finally{li.delete(H)}}function aC(j,H,S){let{reqId:L,method:te,path:xe,body:Te}=j,Ke=new URL(y);return new Promise(Rt=>{let Yt=mW.request({host:Ke.hostname,port:Ke.port,method:te,path:xe,headers:{...H,host:j.host},signal:S.signal},ot=>{let{connection:ak,"keep-alive":gV,"transfer-encoding":yV,upgrade:bV,...iC}=ot.headers;ct({v:dt,ch:"control",type:"http_head",reqId:L,status:ot.statusCode||502,headers:iC}),ot.on("data",cC=>{ct({v:dt,ch:"control",type:"http_data",reqId:L,data:Buffer.from(cC).toString("base64")})||ot.destroy()}),ot.on("end",()=>{ct({v:dt,ch:"control",type:"http_end",reqId:L,error:null}),Rt()}),ot.on("error",()=>{ct({v:dt,ch:"control",type:"http_end",reqId:L,error:"view upstream error"}),Rt()})});Yt.on("error",ot=>{ct({v:dt,ch:"control",type:"http_end",reqId:L,error:ot?.message||"view request failed"}),Rt()}),Te&&Yt.write(Buffer.from(Te,"base64")),Yt.end()})}function ok(){if(ke||ai)return;D=new xy(e,{headers:{authorization:`Bearer ${t}`}}),D.on("open",async()=>{let H=null;try{H=await s?.()||null}catch{H=null}ct({v:dt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:vn,installKind:g,...typeof m=="function"?{updatePolicy:m()}:m?{updatePolicy:m}:{},providers:gW(),...H?{agents:H}:{}})}),D.on("message",H=>{let S;try{S=JSON.parse(H)}catch{return}if(S.ch==="ctl"&&S.type==="hello_ok"){re=!0,Pe=QI,St=null,mk(),N.log(`[plane-link] connected to plane as ${n}`);try{F?.()}catch{}if(typeof S.hashKey=="string"&&S.hashKey)try{l?.(S.hashKey)}catch{}try{u?.(typeof S.viewBase=="string"&&S.viewBase?S.viewBase:null)}catch{}S.minNodeVersion&&vn&&ol(vn,S.minNodeVersion)&&N.error(`[plane-link] this node is bostrat-node ${vn}; the plane asks for \u2265${S.minNodeVersion} \u2014 update with: ${Rp(g)}`);try{f?.(typeof S.updatePolicy=="string"?S.updatePolicy:null)}catch{}let L=typeof S.latestNodeVersion=="string"?S.latestNodeVersion:null;if(L&&vn&&ol(vn,L)&&!Y.has(L)){Y.add(L),N.log(`[plane-link] bostrat-node ${L} is available (this node runs ${vn}) \u2014 ${Rp(g)}`);try{p?.({current:vn,latest:L,min:S.minNodeVersion??null,installKind:g,required:!!(S.minNodeVersion&&ol(vn,S.minNodeVersion))})}catch(xe){N.error(`[plane-link] update notice failed: ${xe?.message||xe}`)}}let te=S.ingest==="http";ve=B==="ws"?"ws":B==="http"||te?"http":"ws",B==="http"&&!te&&N.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),ve==="http"&&N.log("[plane-link] spine rides the HTTPS ingest door"),Q=!1,ge=0,rt=yo,Zn&&clearInterval(Zn),Zn=setInterval(()=>{ct({v:dt,ch:"ctl",type:"ping"}),ek(),nC().catch(()=>{}),Sf(),h.length&&!v&&Af()},U),Zn.unref?.(),rC(),oC().catch(xe=>N.error("[plane-link] backfill failed:",xe?.message||xe));return}if(S.ch==="ctl"&&S.type==="hello_refused"){let L=typeof S.minNodeVersion=="string"?S.minNodeVersion:null,te=typeof S.latestNodeVersion=="string"?S.latestNodeVersion:null;N.error(`[plane-link] plane REFUSED this node: bostrat-node ${vn??"?"} is below its minimum ${L??"?"} \u2014 ${S.fix||Rp(g)}`),Pe=e$,St=0;try{w?.({current:vn,min:L,latest:te,fix:S.fix||Rp(g),installKind:g})}catch(xe){N.error(`[plane-link] refusal handler failed: ${xe?.message||xe}`)}return}if(S.ch==="ctl"&&S.type==="removed"){ct({v:dt,ch:"ctl",type:"removed_ack",nodeId:n}),kf({reason:typeof S.reason=="string"?S.reason:"removed",at:Number(S.at)||Date.now(),via:"ctl"});return}if(S.ch==="ctl"&&S.type==="update_policy"){try{f?.(typeof S.mode=="string"?S.mode:null)}catch{}return}if(S.ch==="ctl"&&S.type==="usage_caps"){ed(S.caps??{},{source:"plane",updatedAt:S.updatedAt??Date.now()}).then(L=>N.log(`[plane-link] spend caps ${Object.keys(L.caps).length?`updated (${Object.keys(L.caps).join(", ")})`:"cleared"} from plane`)).catch(L=>N.error("[plane-link] spend-caps push rejected:",L?.message||L));return}if(S.ch==="ctl"&&S.type==="transferred"&&Array.isArray(S.tracks)){Promise.resolve().then(()=>a?.(S.tracks)).catch(L=>N.error("[plane-link] transfer notice failed:",L?.message||L));return}if(S.ch==="events"&&S.type==="ack"&&Array.isArray(S.ids)){vf(S.ids);return}if(S.ch==="events"&&S.type==="nack"&&Array.isArray(S.ids)){Zb(S.ids,S.reason,S.permanent===!0,S.retryAfterMs??null);return}if(S.ch==="control"&&S.type==="http_open"){sC(S).catch(L=>ct({v:dt,ch:"control",type:"http_end",reqId:S.reqId,error:L?.message||"tunnel error"}));return}if(S.ch==="control"&&S.type==="http_cancel"){li.get(S.reqId)?.abort();return}if(S.ch==="attach"&&S.type==="open"){let L=new xy(K+S.path,Array.isArray(S.protocols)?S.protocols:[],S.host?{headers:{host:S.host}}:void 0);fe.set(S.streamId,L),Ie.set(S.streamId,[]),L.on("open",()=>{let xe=Ie.get(S.streamId)||[];Ie.delete(S.streamId);for(let{buf:Te,bin:Ke}of xe)L.send(Te,{binary:Ke})}),L.on("message",(xe,Te)=>{let Ke=Te?xe:Buffer.from(String(xe));ct({v:dt,ch:"attach",type:"data",streamId:S.streamId,data:Ke.toString("base64"),...Te?{bin:!0}:{}})});let te=()=>{Ie.delete(S.streamId),fe.delete(S.streamId)&&ct({v:dt,ch:"attach",type:"close",streamId:S.streamId})};L.on("close",te),L.on("error",te);return}if(S.ch==="attach"&&S.type==="data"){let L=fe.get(S.streamId);if(!L)return;let te=Buffer.from(S.data,"base64"),xe=S.bin===!0,Te=Ie.get(S.streamId);Te?Te.push({buf:te,bin:xe}):L.send(te,{binary:xe});return}if(S.ch==="attach"&&S.type==="close"){let L=fe.get(S.streamId);fe.delete(S.streamId),Ie.delete(S.streamId),L?.close();return}});let j=()=>{re&&N.log("[plane-link] disconnected from plane"),re=!1,Zn&&(clearInterval(Zn),Zn=null),Qn&&(clearInterval(Qn),Qn=null),ee.clear(),se={},h=[],v&&(clearTimeout(v),v=null),k.clear();for(let L of fe.values())L.close();fe.clear(),Ie.clear();for(let L of li.values())L.abort();if(li.clear(),ke||tt)return;St==null&&(St=Date.now());let H=Date.now()-St<yW,S=Math.max(H?bW+Math.random()*kW:Pe,Fe-Date.now(),hi());tt=setTimeout(()=>{tt=null,ok()},S),tt.unref?.(),H||(Pe=Math.min(Pe*2,e$))};D.on("close",j),D.on("error",H=>{let S=/Unexpected server response: (\d+)/.exec(H?.message||"")?.[1];if(S==="410"){kf({reason:"removed",via:"410"});return}if(S==="401"||S==="403"){let{tripped:L,holdMs:te}=Ds();L?N.error(`[plane-link] holding every plane call for ${Math.round(te/6e4)} min \u2014 three credential refusals in a row (HTTP ${S}) mean the token is revoked or unknown, not that the plane is down; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN. Next dial in ${Math.round(te/6e4)} min.`):Date.now()-jl>=r$&&(jl=Date.now(),N.error(`[plane-link] plane refused this node's credentials (HTTP ${S}) \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)`))}j()})}Je.on("event",rk),YM().then(ok);function sk({bye:j=!0}={}){ke=!0,Je.off("event",rk),tt&&clearTimeout(tt),At&&clearTimeout(At),Zn&&clearInterval(Zn),Qn&&clearInterval(Qn),v&&clearTimeout(v),j&&ct({v:dt,ch:"ctl",type:"bye",reason:"shutdown"}),D?.close()}return{stop:()=>sk(),status:()=>({connected:re,nodeId:n,cursor:{...Ee},inflight:ee.size,...tk(),auth:hk(),dormant:ai,removed:Kl()}),_tick:()=>{ek(),Sf()}}}vu();var Mp=(()=>{try{return OW(import.meta.url)("../package.json").version||null}catch{return null}})(),MW=process.env.BOSTRAT_STATE_DIR||ht.join(process.env.HOME||$W.tmpdir(),".bostrat"),c$=ht.join(MW,"self-update"),Cp=ht.join(c$,"status.json"),CW=1440*6e4,NW=6e4,sl=new Set(["npm-global","git-checkout"]);function l$({kind:e=xs(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:sl.has(e)?e==="git-checkout"||PW(t)?"auto":"prompt":"off"}function PW(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Gt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function DW({kind:e,to:t,from:n=Mp,statusFile:r=Cp,logFile:o=ht.join(c$,"last.log"),port:s=Number(process.env.PORT)||3362,npmPrefix:a=null,serviceName:i=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:c=typeof process.getuid=="function"?process.getuid():0,liveDir:l=process.env.BOSTRAT_LIVE_CHECKOUT||ht.resolve(ht.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!sl.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 d=(g,y="")=>`write_status ${Gt(g)} ${y}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Gt(i)}`,f=`
|
|
660
660
|
health() {
|
|
661
661
|
for i in $(seq 1 45); do
|
|
662
662
|
sleep 1
|
|
@@ -679,8 +679,8 @@ write_status() { # <status> [error]
|
|
|
679
679
|
"\${err:+,\\"error\\":\\"$err\\"}" > "$STATUS_FILE.tmp" && mv "$STATUS_FILE.tmp" "$STATUS_FILE"
|
|
680
680
|
}
|
|
681
681
|
${f}
|
|
682
|
-
`;if(e==="npm-global"){let g=a?
|
|
683
|
-
`:"",
|
|
682
|
+
`;if(e==="npm-global"){let g=a?ht.join(a,"bin","npm"):"npm",y=a?`export PATH=${Gt(ht.join(a,"bin"))}:"$PATH"
|
|
683
|
+
`:"",x=a?` --prefix ${Gt(a)}`:"",b=I=>`${Gt(g)} install -g "bostrat-node@${I}" --no-audit --no-fund${x}`;return w+y+`
|
|
684
684
|
${d("updating",'"" ')}
|
|
685
685
|
if ! ${b("$TO")}; then
|
|
686
686
|
${d("failed",'"npm install failed"')}
|
|
@@ -703,7 +703,7 @@ if [ -n "$FROM" ] && ${b("$FROM")} && ${p} && health; then
|
|
|
703
703
|
fi
|
|
704
704
|
${d("failed",'"agent did not answer after the update AND the rollback"')}
|
|
705
705
|
exit 1
|
|
706
|
-
`}let
|
|
706
|
+
`}let m=g=>`( cd ${Gt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return w+`
|
|
707
707
|
LIVE=${Gt(l)}
|
|
708
708
|
TMP_SCRIPT="$(mktemp)"
|
|
709
709
|
trap 'rm -f "$TMP_SCRIPT"' EXIT
|
|
@@ -711,75 +711,76 @@ trap 'rm -f "$TMP_SCRIPT"' EXIT
|
|
|
711
711
|
# restart \u2192 health in one call): the agent it restarts settles "done" on boot,
|
|
712
712
|
# and nothing here may write after that boot or the settle would repeat.
|
|
713
713
|
${d("restarting")}
|
|
714
|
-
if ${
|
|
714
|
+
if ${m("$TO")}; then
|
|
715
715
|
exit 0
|
|
716
716
|
fi
|
|
717
717
|
${d("rolling-back",'"deploy-pi.sh v$TO failed"')}
|
|
718
|
-
if [ -n "$FROM" ] && ${
|
|
718
|
+
if [ -n "$FROM" ] && ${m("$FROM")}; then
|
|
719
719
|
${d("rolled-back",'"deploy-pi.sh v$TO failed; rolled back to v$FROM"')}
|
|
720
720
|
exit 1
|
|
721
721
|
fi
|
|
722
722
|
${d("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
|
|
723
723
|
exit 1
|
|
724
|
-
`}async function ol(e=Rp){try{return JSON.parse(await go.readFile(e,"utf8"))}catch{return null}}var xW=new Set(["updating","restarting","rolling-back"]),Op=e=>!!(e&&xW.has(e.status));async function Mp({to:e,from:t=$p,kind:n=ks(),reason:r="manual",statusFile:o=Rp,spawnImpl:s=hW,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!rl.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!nl(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await ol(o);if(Op(l))return{ok:!1,reason:`an update to ${l.to} is already in flight`,status:l};if(l&&l.to===e&&(l.status==="failed"||l.status==="rolled-back"))return{ok:!1,reason:`update to ${e} already ${l.status} (${l.error||"no detail"}) \u2014 retried when a newer release exists`,status:l};await go.mkdir(wt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?gh(await vW())||wt.resolve(wt.dirname(process.execPath),".."):null,d=kW({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=wt.join(wt.dirname(o),`update-${e}.sh`),f=wt.join(wt.dirname(o),"last.log");await go.writeFile(p,d,{mode:448}),await go.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=QI.existsSync("/run/systemd/system")&&await SW("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${Gt(p)} >> ${Gt(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(h){return await go.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${h?.message||h}`})),{ok:!1,reason:`could not spawn updater: ${h?.message||h}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:p,statusFile:o}}async function vW(){try{return await go.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function SW(e){for(let t of String(process.env.PATH||"").split(wt.delimiter))try{return await go.access(wt.join(t,e),QI.constants.X_OK),!0}catch{}return!1}var AW=45*6e4;async function n$({statusFile:e=Rp,current:t=$p,now:n=Date.now,staleMs:r=AW}={}){let o=await ol(e);if(!o)return null;let s=a=>go.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Op(o)){if(t&&o.to===t){let a={...o,status:"done",updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}if(n()-Number(o.updatedAt||o.startedAt||0)>r){let a={...o,status:"failed",error:`updater went silent while ${o.status} (no status change for ${Math.round(r/6e4)} min)`,updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}return null}if(["failed","rolled-back","done"].includes(o.status)&&!o.announced){let a={...o,announced:!0};return await s(a),a}return null}function r$({isBusy:e,start:t=Mp,onStuck:n=null,onStarted:r=null,tickMs:o=yW,stuckMs:s=gW,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,d=()=>{u?.timer&&c(u.timer),u=null},p=async()=>{if(!u)return;let f=!0;try{f=await e()!==!1}catch{f=!0}if(f){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let w=u;d();let h=await t({to:w.to,from:w.from,kind:w.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${h.ok?"started":`not started: ${h.reason}`}`);try{await r?.({...w,result:h})}catch{}};return{arm({to:f,from:w=$p,kind:h=ks()}){return u?.to===f?!1:(d(),u={to:f,from:w,kind:h,since:a(),stuckFired:!1,timer:i(p,o)},u.timer.unref?.(),!0)},tick:p,cancel:d,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}fe();yt();var o$=(...e)=>fetch(...e);function s$(e=process.env){return!!(Ce(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ky(e=process.env){if(!s$(e))throw new Error("no plane configured \u2014 circuits live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await o$(`${Ce(e)}/v1/circuits`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return Array.isArray(o.circuits)?o.circuits:[]}finally{clearTimeout(n)}}async function xy(e=process.env){if(!s$(e))throw new Error("no plane configured \u2014 the roadmap lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await o$(`${Ce(e)}/v1/roadmap`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return{people:Array.isArray(o.people)?o.people:[],slots:Array.isArray(o.slots)?o.slots:[],reservations:Array.isArray(o.reservations)?o.reservations:[],tray:Array.isArray(o.tray)?o.tray:[],circuits:Array.isArray(o.circuits)?o.circuits:[]}}finally{clearTimeout(n)}}async function qa(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await ky(t),o=r.find(c=>c.id===n);if(o)return o;let s=n.toLowerCase(),a=r.filter(c=>c.name.toLowerCase()===s);if(a.length===1)return a[0];if(a.length>1)throw new Error(`"${n}" names ${a.length} circuits \u2014 use an id (bostrat-circuit ls)`);let i=r.filter(c=>c.name.toLowerCase().includes(s)).slice(0,5);throw new Error(i.length?`no circuit named "${n}" \u2014 near matches: ${i.map(c=>`${c.name} (${c.id})`).join(", ")}`:`no circuit named "${n}" \u2014 create it on the Circuits page first (bostrat-circuit ls lists yours)`)}async function Cp(e,t,{source:n="chat"}={}){return C(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}fe();yt();var TW=(...e)=>fetch(...e);async function Np(e,t,n,r=process.env){if(!(Ce(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 blueprints live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await TW(`${Ce(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}function EW(e,t=process.env){return Np("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function a$({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await EW(t,o):await qa(e,o),a=await Np("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function vy(e,t=process.env){let n=await qa(e,t),r=await Np("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function Sy(e,t=process.env){return(await Np("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function i$(e,t,n,r=process.env){let{blueprint:o,items:s}=await vy(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await C(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}fe();yt();var _W=(...e)=>fetch(...e);async function IW(e,t,n,r=process.env){if(!(Ce(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 the decision ledger lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await _W(`${Ce(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}var c$=72,Ay=160;async function l$(e,{title:t,context:n="",decision:r,summary:o,alternatives:s=[],supersedesId:a=null}){let i=String(t??"").trim(),c=String(o??"").trim();if(!i)throw new Error("a title is required");if(i.length>c$)throw new Error(`the title is the choice as a LABEL \u2014 ${c$} chars max (yours is ${i.length}); the full story goes in the decision text`);if(!c)throw new Error(`a summary is required \u2014 one sentence (max ${Ay} chars) a reader can act on without opening the record`);if(c.length>Ay)throw new Error(`the summary is one sentence \u2014 ${Ay} chars max (yours is ${c.length}); the full story goes in the decision text`);if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await C(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:i,context:String(n??"").trim(),decision:String(r).trim(),summary:c,alternatives:(Array.isArray(s)?s:[]).map(l=>typeof l=="string"?{label:l}:l).filter(l=>l?.label),...a?{supersedesId:a}:{}}}),{title:i}}function u$(e,t=process.env){return IW("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}rg();fe();import ul from"node:fs/promises";import Wp from"node:path";import bq from"node:os";Dr();import $W from"node:fs/promises";import d$ from"node:path";import RW from"node:os";var p$=()=>d$.join(process.env.BOSTRAT_STATE_DIR||d$.join(process.env.HOME||RW.tmpdir(),".bostrat"),"integrations.json");async function Ir(){try{return JSON.parse(await $W.readFile(p$(),"utf8"))||{}}catch{return{}}}var Pp=["linked","prOpened","prMerged","create"],Ty=["prompt","auto","off"],OW={create:["prompt","off"]},f$=e=>OW[e]??Ty;function Dp(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Pp){let s=f$(o),a=s.includes(n)?n:"prompt",i=e.ticketFlow?.[o]??t.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function xs(){let e=await Ir(),t=process.env.BOSTRAT_LINEAR_API_KEY||e.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||e.linear?.defaultTeam||null;return t?{apiKey:t,ticketFlow:Dp(e),defaultTeam:n}:null}async function Bp(){let e=await Ir(),t=e.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||t.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||t.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||t.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:t.tokenExpiresAt??null,ticketFlow:Dp(e)}}async function Ey(){return Dp(await Ir())}async function h$(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Pp.join(", ")}`);for(let[r,o]of t){if(!Pp.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Pp.join(", ")}`);let s=f$(r);if(!s.includes(o))throw new Error(s.length<Ty.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${Ty.join(", ")}`)}let n=await Ir();return n.ticketFlow={...Dp(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Ot(p$(),n,{mode:384}),n.ticketFlow}async function sl(){let e=(await Ir()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function MW(){let e=(await Ir()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var CW={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function jp(){let t=(await Ir()).voiceChat||{},n=t.provider||"openai",r=CW[n];if(!r)return null;let o=n==="openai"?await MW():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function m$(){let e=(await Ir()).cedar||{},t=process.env.BOSTRAT_CEDAR_INGEST_KEY||e.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||e.url||"https://cedar-api.fly.dev";return t?{url:n,ingestKey:t}:null}async function vs(){let e=(await Ir()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}fe();jr();zr();$a();import il from"node:fs/promises";import A$ from"node:path";import oq from"node:os";import{randomUUID as T$}from"node:crypto";var Iy={};xf(Iy,{createComment:()=>HW,findIssueUrl:()=>BW,issueStates:()=>KW,mdToAdf:()=>y$,moveIssue:()=>GW,parseIssueRef:()=>DW,resolveIssue:()=>jW,uploadImage:()=>WW,upsertCard:()=>LW,whoami:()=>_y});var Ka=e=>String(e.baseUrl||"").replace(/\/$/,""),g$=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function Ss(e,t,n,r){let o=await fetch(`${Ka(e)}${n}`,{method:t,headers:{authorization:g$(e),accept:"application/json",...r!==void 0?{"content-type":"application/json"}:{}},body:r!==void 0?JSON.stringify(r):void 0}),s=await o.text(),a=null;try{a=s?JSON.parse(s):null}catch{a=null}if(!o.ok){let i=a?.errorMessages?.[0]??Object.values(a?.errors??{})[0]??`HTTP ${o.status}`,c=new Error(`jira: ${i}`);throw c.status=o.status,c}return a}var NW=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,PW=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function DW(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(NW);return r?r[1].toUpperCase():null}let n=t.match(PW);return n?n[1]:null}function BW(e,t=null){let n=null;try{n=t?.baseUrl?new URL(t.baseUrl).host:null}catch{n=null}let r=/https?:\/\/[^\s)]+\/browse\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/g;for(let o of String(e||"").matchAll(r))try{let s=new URL(o[0]).host;if(s===n||/\.atlassian\.net$/i.test(s))return o[0]}catch{}return null}async function jW(e,t){let n;try{n=await Ss(e,"GET",`/rest/api/3/issue/${encodeURIComponent(t)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${t}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${Ka(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function LW(e,t,{url:n,title:r,subtitle:o}){await Ss(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var FW=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function UW(e){let t=[],n=0;for(let r of e.matchAll(FW)){r.index>n&&t.push({type:"text",text:e.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);t.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?t.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):t.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<e.length&&t.push({type:"text",text:e.slice(n)}),t}function y$(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
|
|
725
|
-
`).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...
|
|
724
|
+
`}async function al(e=Cp){try{return JSON.parse(await bo.readFile(e,"utf8"))}catch{return null}}var BW=new Set(["updating","restarting","rolling-back"]),Np=e=>!!(e&&BW.has(e.status));async function Pp({to:e,from:t=Mp,kind:n=xs(),reason:r="manual",statusFile:o=Cp,spawnImpl:s=RW,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!sl.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!ol(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await al(o);if(Np(l))return{ok:!1,reason:`an update to ${l.to} is already in flight`,status:l};if(l&&l.to===e&&(l.status==="failed"||l.status==="rolled-back"))return{ok:!1,reason:`update to ${e} already ${l.status} (${l.error||"no detail"}) \u2014 retried when a newer release exists`,status:l};await bo.mkdir(ht.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?xm(await jW())||ht.resolve(ht.dirname(process.execPath),".."):null,d=DW({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=ht.join(ht.dirname(o),`update-${e}.sh`),f=ht.join(ht.dirname(o),"last.log");await bo.writeFile(p,d,{mode:448}),await bo.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=i$.existsSync("/run/systemd/system")&&await LW("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${Gt(p)} >> ${Gt(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(m){return await bo.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${m?.message||m}`})),{ok:!1,reason:`could not spawn updater: ${m?.message||m}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:p,statusFile:o}}async function jW(){try{return await bo.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function LW(e){for(let t of String(process.env.PATH||"").split(ht.delimiter))try{return await bo.access(ht.join(t,e),i$.constants.X_OK),!0}catch{}return!1}var FW=45*6e4;async function u$({statusFile:e=Cp,current:t=Mp,now:n=Date.now,staleMs:r=FW}={}){let o=await al(e);if(!o)return null;let s=a=>bo.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Np(o)){if(t&&o.to===t){let a={...o,status:"done",updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}if(n()-Number(o.updatedAt||o.startedAt||0)>r){let a={...o,status:"failed",error:`updater went silent while ${o.status} (no status change for ${Math.round(r/6e4)} min)`,updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}return null}if(["failed","rolled-back","done"].includes(o.status)&&!o.announced){let a={...o,announced:!0};return await s(a),a}return null}function d$({isBusy:e,start:t=Pp,onStuck:n=null,onStarted:r=null,tickMs:o=NW,stuckMs:s=CW,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,d=()=>{u?.timer&&c(u.timer),u=null},p=async()=>{if(!u)return;let f=!0;try{f=await e()!==!1}catch{f=!0}if(f){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let w=u;d();let m=await t({to:w.to,from:w.from,kind:w.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${m.ok?"started":`not started: ${m.reason}`}`);try{await r?.({...w,result:m})}catch{}};return{arm({to:f,from:w=Mp,kind:m=xs()}){return u?.to===f?!1:(d(),u={to:f,from:w,kind:m,since:a(),stuckFired:!1,timer:i(p,o)},u.timer.unref?.(),!0)},tick:p,cancel:d,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}me();gt();var p$=(...e)=>fetch(...e);function f$(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ay(e=process.env){if(!f$(e))throw new Error("no plane configured \u2014 circuits live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await p$(`${Ne(e)}/v1/circuits`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return Array.isArray(o.circuits)?o.circuits:[]}finally{clearTimeout(n)}}async function Ty(e=process.env){if(!f$(e))throw new Error("no plane configured \u2014 the roadmap lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await p$(`${Ne(e)}/v1/roadmap`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return{people:Array.isArray(o.people)?o.people:[],slots:Array.isArray(o.slots)?o.slots:[],reservations:Array.isArray(o.reservations)?o.reservations:[],tray:Array.isArray(o.tray)?o.tray:[],circuits:Array.isArray(o.circuits)?o.circuits:[]}}finally{clearTimeout(n)}}async function Ka(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await Ay(t),o=r.find(c=>c.id===n);if(o)return o;let s=n.toLowerCase(),a=r.filter(c=>c.name.toLowerCase()===s);if(a.length===1)return a[0];if(a.length>1)throw new Error(`"${n}" names ${a.length} circuits \u2014 use an id (bostrat-circuit ls)`);let i=r.filter(c=>c.name.toLowerCase().includes(s)).slice(0,5);throw new Error(i.length?`no circuit named "${n}" \u2014 near matches: ${i.map(c=>`${c.name} (${c.id})`).join(", ")}`:`no circuit named "${n}" \u2014 create it on the Circuits page first (bostrat-circuit ls lists yours)`)}async function Dp(e,t,{source:n="chat"}={}){return C(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}me();gt();var UW=(...e)=>fetch(...e);async function Bp(e,t,n,r=process.env){if(!(Ne(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 blueprints live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await UW(`${Ne(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}function HW(e,t=process.env){return Bp("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function m$({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await HW(t,o):await Ka(e,o),a=await Bp("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Ey(e,t=process.env){let n=await Ka(e,t),r=await Bp("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function _y(e,t=process.env){return(await Bp("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function h$(e,t,n,r=process.env){let{blueprint:o,items:s}=await Ey(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await C(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}me();gt();var WW=(...e)=>fetch(...e);async function qW(e,t,n,r=process.env){if(!(Ne(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 the decision ledger lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await WW(`${Ne(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}var w$=72,Iy=160;async function g$(e,{title:t,context:n="",decision:r,summary:o,alternatives:s=[],supersedesId:a=null}){let i=String(t??"").trim(),c=String(o??"").trim();if(!i)throw new Error("a title is required");if(i.length>w$)throw new Error(`the title is the choice as a LABEL \u2014 ${w$} chars max (yours is ${i.length}); the full story goes in the decision text`);if(!c)throw new Error(`a summary is required \u2014 one sentence (max ${Iy} chars) a reader can act on without opening the record`);if(c.length>Iy)throw new Error(`the summary is one sentence \u2014 ${Iy} chars max (yours is ${c.length}); the full story goes in the decision text`);if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await C(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:i,context:String(n??"").trim(),decision:String(r).trim(),summary:c,alternatives:(Array.isArray(s)?s:[]).map(l=>typeof l=="string"?{label:l}:l).filter(l=>l?.label),...a?{supersedesId:a}:{}}}),{title:i}}function y$(e,t=process.env){return qW("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}ig();me();import fl from"node:fs/promises";import Vp from"node:path";import Fq from"node:os";jr();import KW from"node:fs/promises";import b$ from"node:path";import GW from"node:os";var k$=()=>b$.join(process.env.BOSTRAT_STATE_DIR||b$.join(process.env.HOME||GW.tmpdir(),".bostrat"),"integrations.json");async function Rr(){try{return JSON.parse(await KW.readFile(k$(),"utf8"))||{}}catch{return{}}}var jp=["linked","prOpened","prMerged","create"],$y=["prompt","auto","off"],VW={create:["prompt","off"]},x$=e=>VW[e]??$y;function Lp(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of jp){let s=x$(o),a=s.includes(n)?n:"prompt",i=e.ticketFlow?.[o]??t.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function vs(){let e=await Rr(),t=process.env.BOSTRAT_LINEAR_API_KEY||e.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||e.linear?.defaultTeam||null;return t?{apiKey:t,ticketFlow:Lp(e),defaultTeam:n}:null}async function Fp(){let e=await Rr(),t=e.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||t.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||t.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||t.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:t.tokenExpiresAt??null,ticketFlow:Lp(e)}}async function Ry(){return Lp(await Rr())}async function v$(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${jp.join(", ")}`);for(let[r,o]of t){if(!jp.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${jp.join(", ")}`);let s=x$(r);if(!s.includes(o))throw new Error(s.length<$y.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${$y.join(", ")}`)}let n=await Rr();return n.ticketFlow={...Lp(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Mt(k$(),n,{mode:384}),n.ticketFlow}async function il(){let e=(await Rr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function zW(){let e=(await Rr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var JW={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Up(){let t=(await Rr()).voiceChat||{},n=t.provider||"openai",r=JW[n];if(!r)return null;let o=n==="openai"?await zW():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function S$(){let e=(await Rr()).cedar||{},t=process.env.BOSTRAT_CEDAR_INGEST_KEY||e.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||e.url||"https://cedar-api.fly.dev";return t?{url:n,ingestKey:t}:null}async function Ss(){let e=(await Rr()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}me();Fr();Yr();Ra();import ll from"node:fs/promises";import U$ from"node:path";import Sq from"node:os";import{randomUUID as H$}from"node:crypto";var My={};Tf(My,{createComment:()=>oq,findIssueUrl:()=>QW,issueStates:()=>iq,mdToAdf:()=>E$,moveIssue:()=>cq,parseIssueRef:()=>ZW,resolveIssue:()=>eq,uploadImage:()=>sq,upsertCard:()=>tq,whoami:()=>Oy});var Ga=e=>String(e.baseUrl||"").replace(/\/$/,""),T$=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function As(e,t,n,r){let o=await fetch(`${Ga(e)}${n}`,{method:t,headers:{authorization:T$(e),accept:"application/json",...r!==void 0?{"content-type":"application/json"}:{}},body:r!==void 0?JSON.stringify(r):void 0}),s=await o.text(),a=null;try{a=s?JSON.parse(s):null}catch{a=null}if(!o.ok){let i=a?.errorMessages?.[0]??Object.values(a?.errors??{})[0]??`HTTP ${o.status}`,c=new Error(`jira: ${i}`);throw c.status=o.status,c}return a}var YW=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,XW=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function ZW(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(YW);return r?r[1].toUpperCase():null}let n=t.match(XW);return n?n[1]:null}function QW(e,t=null){let n=null;try{n=t?.baseUrl?new URL(t.baseUrl).host:null}catch{n=null}let r=/https?:\/\/[^\s)]+\/browse\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/g;for(let o of String(e||"").matchAll(r))try{let s=new URL(o[0]).host;if(s===n||/\.atlassian\.net$/i.test(s))return o[0]}catch{}return null}async function eq(e,t){let n;try{n=await As(e,"GET",`/rest/api/3/issue/${encodeURIComponent(t)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${t}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${Ga(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function tq(e,t,{url:n,title:r,subtitle:o}){await As(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var nq=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function rq(e){let t=[],n=0;for(let r of e.matchAll(nq)){r.index>n&&t.push({type:"text",text:e.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);t.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?t.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):t.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<e.length&&t.push({type:"text",text:e.slice(n)}),t}function E$(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
|
|
725
|
+
`).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...rq(o))}),{type:"paragraph",content:r.length?r:[{type:"text",text:" "}]}});return{type:"doc",version:1,content:t.length?t:[{type:"paragraph",content:[{type:"text",text:" "}]}]}}async function oq(e,t,n){let r=await As(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:E$(n)});return r?.id?`${Ga(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function Oy(e){let t=await As(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Ga(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function sq(e,{issue:t,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${Ga(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:T$(e),"x-atlassian-token":"no-check",accept:"application/json"},body:s}),i=await a.json().catch(()=>null),c=Array.isArray(i)?i[0]:null;if(!a.ok||!c)throw new Error(`jira: attachment upload failed (HTTP ${a.status})`);return c.content??`${Ga(e)}/rest/api/3/attachment/content/${c.id}`}var aq={new:"unstarted",indeterminate:"started",done:"completed"},A$=e=>aq[e?.key]??"started";async function iq(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([As(e,"GET",`/rest/api/3/issue/${n}?fields=status`),As(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:A$(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:A$(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function cq(e,t,n){await As(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Dy={};Tf(Dy,{createComment:()=>wq,createIssue:()=>Py,createProject:()=>Ny,findIssueUrl:()=>fq,issueStates:()=>yq,moveIssue:()=>bq,parseIssueRef:()=>pq,resolveIssue:()=>mq,teams:()=>Va,uploadImage:()=>gq,upsertCard:()=>hq,whoami:()=>Cy});var lq=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Jn(e,t,n={}){let r=await fetch(lq(),{method:"POST",headers:{"content-type":"application/json",authorization:e.apiKey},body:JSON.stringify({query:t,variables:n})}),o=await r.json().catch(()=>null);if(!r.ok)throw new Error(`linear: HTTP ${r.status}${o?.errors?.[0]?.message?` \u2014 ${o.errors[0].message}`:""}`);if(o?.errors?.length){let s=o.errors[0],a=(s.extensions?.validationErrors??[]).flatMap(i=>Object.values(i?.constraints??{})).join("; ");throw new Error(`linear: ${s.message}${a?` \u2014 ${a}`:""}`)}return o?.data??{}}var uq=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,dq=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function pq(e){let t=String(e||"").trim(),n=t.match(uq);if(n)return n[1].toUpperCase();let r=t.match(dq);return r?r[1]:null}function fq(e){let t=String(e||"").match(/https?:\/\/linear\.app\/[^/\s]+\/issue\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/);return t?t[0]:null}async function mq(e,t){let r=(await Jn(e,"query($id: String!) { issue(id: $id) { id identifier title url state { name } team { key } } }",{id:t})).issue;if(!r)throw new Error(`linear: issue "${t}" not found`);return{issueId:r.id,key:r.identifier,title:r.title,url:r.url,state:r.state?.name??null,team:r.team?.key??null}}async function hq(e,t,{url:n,title:r,subtitle:o}){let s=await Jn(e,"mutation($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }",{input:{issueId:t.issueId,url:n,title:r,subtitle:o}});if(!s.attachmentCreate?.success)throw new Error("linear: attachmentCreate did not succeed");return s.attachmentCreate.attachment?.id??null}async function wq(e,t,n){let r=await Jn(e,"mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { url } } }",{input:{issueId:t.issueId,body:n}});if(!r.commentCreate?.success)throw new Error("linear: commentCreate did not succeed");return r.commentCreate.comment?.url??null}async function Cy(e){let t=await Jn(e,"query { viewer { name email } organization { name urlKey } }");return{user:t.viewer?.name??t.viewer?.email??null,org:t.organization?.name??t.organization?.urlKey??null}}async function gq(e,{filename:t,contentType:n,buffer:r}){let o=await Jn(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
|
|
726
726
|
fileUpload(contentType: $contentType, filename: $filename, size: $size) {
|
|
727
727
|
success
|
|
728
728
|
uploadFile { uploadUrl assetUrl headers { key value } }
|
|
729
729
|
}
|
|
730
|
-
}`,{contentType:n,filename:t,size:r.length}),s=o.fileUpload?.uploadFile;if(!o.fileUpload?.success||!s?.uploadUrl)throw new Error("linear: fileUpload did not succeed");let a={"content-type":n};for(let c of s.headers||[])a[c.key]=c.value;let i=await fetch(s.uploadUrl,{method:"PUT",headers:a,body:r});if(!i.ok)throw new Error(`linear: asset PUT failed (HTTP ${i.status})`);return s.assetUrl}async function nq(e,t){let n=await Jn(e,"query($id: String!) { issue(id: $id) { state { id name type } team { states { nodes { id name type position } } } } }",{id:t.key});if(!n.issue)throw new Error(`linear: issue "${t.key}" not found`);return{current:n.issue.state??null,states:n.issue.team?.states?.nodes??[]}}async function rq(e,t,n){if(!(await Jn(e,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:t.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function Ga(e){return((await Jn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var b$=255;async function Ry(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>b$,a=s?`${o.slice(0,b$-1).trimEnd()}\u2026`:o,i=await Jn(e,"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id url name } } }",{input:{teamIds:[t],name:n,...a?{description:a}:{},...s?{content:o}:{}}}),c=i.projectCreate?.project;if(!i.projectCreate?.success||!c)throw new Error("linear: projectCreate did not succeed");return{id:c.id,url:c.url,name:c.name}}async function Oy(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await Jn(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}mc();var E$={linear:{api:My,config:xs},jira:{api:Iy,config:Bp}};async function Ly(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(E$)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function As(e){let t=E$[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Fy(e,t){if(!e||e.name)return e;let n=t.find(r=>r.id===e.id);return n?{...e,name:n.name}:e}var _$=()=>process.env.BOSTRAT_STATE_DIR||A$.join(process.env.HOME||oq.tmpdir(),".bostrat"),Dy=()=>A$.join(_$(),"tickets.json"),I$=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),Lp=e=>`${I$()}/track/${e}`,yo=null,Cy=null,Ny=Promise.resolve();async function ll(){return yo||(Cy??=il.readFile(Dy(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(yo=e,!t&&Ke()){let{records:n,source:r}=await dt("tickets").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.id)continue;let{id:s,updatedAt:a,...i}=o.data;yo[s]=i}Object.keys(yo).length&&await By().catch(()=>{})}}return yo}).finally(()=>Cy=null),Cy)}async function By(){let e=JSON.stringify({tickets:yo},null,2),t=`${Dy()}.${process.pid}.tmp`;await il.mkdir(_$(),{recursive:!0}),await il.writeFile(t,e),await il.rename(t,Dy())}async function bo(e=null){if(Ny=Ny.then(By,By),await Ny.catch(()=>{}),!e)return;let t=yo?.[e];t?At("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):an("tickets",e).catch(()=>{})}async function Yn(e){return(await ll())[e]??null}async function $$(){return{...await ll()}}async function R$(){return(await Ly()).length>0}async function Va(e,t,{source:n="api"}={}){let r=await Ly();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let d=u.api.parseIssueRef(t);if(d)try{s=await u.api.resolveIssue(u.cfg,d),o=u;break}catch(p){a=p}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await ll())[e.id]=c,await bo(e.id),await C({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await cl(e.id,c);let l=[];return c.track.branch&&l.push(`\`${c.track.branch}\``),c.track.repos?.length&&l.push(`repos ${c.track.repos.join(" + ")}`),c.track.leadAgent&&l.push(`lead ${c.track.leadAgent}`),await al(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await C$(e.id,c,"linked"),c}async function Uy(e){let t=await ll();return t[e]?(delete t[e],await bo(e),!0):!1}var jy=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function O$(e,t){if(!e.track?.cwd)return null;let n=Vr(await q({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function sq(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${jy(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${jy(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function aq(e,t){let n=[];return e.track.leadAgent&&n.push(`lead ${e.track.leadAgent}`),e.track.branch&&n.push(e.track.branch),e.track.repos?.length&&n.push(e.track.repos.join(" + ")),e.pr?.number&&n.push(`PR #${e.pr.number} ${e.pr.change==="merged"?"merged":"open"}`),t&&n.push(jy(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function cl(e,t){let n=await As(t);if(!n)return;let r=await O$(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:Lp(e),title:`Bostrat Track: ${t.track.name}`,subtitle:aq(t,r)})}function Fp(e){let t=new URL(I$());return`${t.protocol}//${e}.${t.host}/`}var iq={linked:"linked",opened:"prOpened",merged:"prMerged"};function cq(e,t,n){let r=o=>t.filter(s=>s.type===o).sort((s,a)=>s.position-a.position);if(n==="linked"){if(["triage","backlog","unstarted"].includes(e?.type))return r("started")[0]??null}else if(n==="opened"){if(e?.type!=="completed")return r("started").find(o=>/review/i.test(o.name))??null}else if(n==="merged"&&e?.type!=="completed")return r("completed")[0]??null;return null}async function M$(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await bo(e),await C({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function C$(e,t,n){let r=await As(t);if(!r)return;let o=r.cfg.ticketFlow?.[iq[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Fy(s,a),c=cq(i,a,n);if(!c||c.id===i?.id)return;let l=i?.name??t.state??null;if(o==="auto"){await r.api.moveIssue(r.cfg,t,c.id),await M$(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await C({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:T$(),provider:t.provider,key:t.key,url:t.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...t.pr?.number?{prNumber:t.pr.number}:{}}}).catch(()=>{})}async function N$(e){let t=await Yn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await As(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Fy(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await bo(e)),{key:t.key,url:t.url,current:s?{id:s.id,name:s.name??null,type:s.type??null}:null,states:[...o].sort((a,i)=>a.position-i.position).map(({id:a,name:i,type:c,position:l})=>({id:a,name:i,type:c,position:l}))}}async function Hy(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Yn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await As(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Fy(s,a),c=a.find(u=>u.id===t);if(!c)throw new Error("unknown state for this ticket's team");let l=i?.name??r.state??null;return i?.id===c.id?(r.state!==c.name&&(r.state=c.name,await bo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await M$(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function P$(e,t){let n=await Yn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await As(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await C({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function D$(e,t,n){if(!t)throw new Error("offerId required");return co(`tkt:${e.id}:${t}`,()=>lq(e,t,n))}async function lq(e,t,n){let r=await q({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await Hy(e.id,o.payload.to?.id,{mode:"offer"})),await C({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var k$=50;async function B$(){let e=await xs();if(!e)throw new Error("no ticketing integration configured");return Ga(e)}function uq(e){let t=e&&typeof e=="object"?e:{},n=(Array.isArray(t.issues)?t.issues:[]).map(o=>o&&typeof o=="object"?o:{title:String(o||"")}).map(o=>({title:String(o.title||"").trim(),description:o.description?String(o.description):null,priority:Number.isInteger(o.priority)&&o.priority>=0&&o.priority<=4?o.priority:null})).filter(o=>o.title),r=t.epic&&String(t.epic.name||"").trim()?{name:String(t.epic.name).trim(),description:t.epic.description?String(t.epic.description):null}:null;if(!n.length&&!r)throw new Error("a plan needs an epic or at least one issue");if(n.length>k$)throw new Error(`too many issues (${n.length}); cap is ${k$} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function dq(e,t,n,r){let o=r??await Ga(e),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(t.team){let i=s(t.team);if(i)return i}let a=await Yn(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(e.defaultTeam){let i=s(e.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function j$(e,t){let n=await xs();if(!n)throw new Error("no ticketing integration configured \u2014 add a linear apiKey to ~/.bostrat/integrations.json");if(n.ticketFlow?.create==="off")throw new Error("ticket creation offers are off (bostrat-ticket flow set create=prompt to re-enable)");let r=uq(t),o=await Ga(n),s=await dq(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=T$();return await C({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function L$(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await q({id:e.id,cwd:e.cwd}),s=o.find(w=>w.type==="ticket.create.offered"&&w.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(w=>w.type==="ticket.create.answered"&&w.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await xs();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await Ga(a)).find(h=>h.id===r);if(!w)throw new Error("unknown team");c={id:w.id,key:w.key,name:w.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let w=await Ry(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=w.id,l.push({kind:"epic",title:w.name,url:w.url})}for(let w of i.issues||[])try{let h=await Oy(a,{teamId:c.id,title:w.title,description:w.description,projectId:d,priority:w.priority});l.push({kind:"issue",key:h.key,title:h.title,url:h.url})}catch(h){u.push({title:w.title,message:h?.message||String(h)})}await C({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await C({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let p=l.filter(w=>w.kind==="issue"),f=null;return i.linkCurrentTrack&&p.length===1&&!await Yn(e.id)&&(f=await Va(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function al(e,t){let n=await As(e);n&&await n.api.createComment(n.cfg,e,t)}async function pq(e,t,n){let r=await As(e);if(!r)return null;let o=await br(t);if(!o)return null;let s=gn(o,n);if(!s)return null;let a=await il.readFile(nn(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:e.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var x$=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Py=new Map;function fq(e,t){if(x$()<=0)return cl(e,t);if(Py.has(e))return;let n=setTimeout(()=>{Py.delete(e),Yn(e).then(r=>r?cl(e,r):null).catch(()=>{})},x$());n.unref?.(),Py.set(e,n)}var v$=new Map;async function S$(e,t,n){let r=v$.get(e)??0;Date.now()-r<600*1e3||(v$.set(e,Date.now()),await C({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function hq(e,{resolveTrack:t=null}={}){let n=await Yn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Ly())if(o=a.api.findIssueUrl(r.text,a.cfg),o)break;if(!o)return;let s=t?await t(e.trackId):null;if(!s)return;try{await Va(s,o,{source:"chat"})}catch(a){await S$(e.trackId,s.cwd,a)}return}if(!n.track.cwd&&t){let o=await t(e.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await bo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await bo(e.trackId),await cl(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await bo(e.trackId),await cl(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await O$(n,e.trackId).catch(()=>null):null;await al(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
|
|
730
|
+
}`,{contentType:n,filename:t,size:r.length}),s=o.fileUpload?.uploadFile;if(!o.fileUpload?.success||!s?.uploadUrl)throw new Error("linear: fileUpload did not succeed");let a={"content-type":n};for(let c of s.headers||[])a[c.key]=c.value;let i=await fetch(s.uploadUrl,{method:"PUT",headers:a,body:r});if(!i.ok)throw new Error(`linear: asset PUT failed (HTTP ${i.status})`);return s.assetUrl}async function yq(e,t){let n=await Jn(e,"query($id: String!) { issue(id: $id) { state { id name type } team { states { nodes { id name type position } } } } }",{id:t.key});if(!n.issue)throw new Error(`linear: issue "${t.key}" not found`);return{current:n.issue.state??null,states:n.issue.team?.states?.nodes??[]}}async function bq(e,t,n){if(!(await Jn(e,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:t.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function Va(e){return((await Jn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var _$=255;async function Ny(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>_$,a=s?`${o.slice(0,_$-1).trimEnd()}\u2026`:o,i=await Jn(e,"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id url name } } }",{input:{teamIds:[t],name:n,...a?{description:a}:{},...s?{content:o}:{}}}),c=i.projectCreate?.project;if(!i.projectCreate?.success||!c)throw new Error("linear: projectCreate did not succeed");return{id:c.id,url:c.url,name:c.name}}async function Py(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await Jn(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}gc();import Hp from"node:fs";import By from"node:path";import kq from"node:os";var xq=()=>process.env.BOSTRAT_STATE_DIR||By.join(process.env.HOME||kq.tmpdir(),".bostrat"),I$=()=>By.join(xq(),"plane-link","public-host.json"),$$="this node has no public host for Views: link it to a plane that sets PLANE_VIEW_BASE (bostrat-node init), or set BOSTRAT_PUBLIC_HOST in node.env for a plane-less node",za=null;function R$(){if(za)return za;try{let e=JSON.parse(Hp.readFileSync(I$(),"utf8"));za={viewBase:typeof e?.viewBase=="string"&&e.viewBase?e.viewBase:null}}catch{za={viewBase:null}}return za}function O$(e,t){let n=String(e||"").trim();if(!n)return null;let r=/^(https?):\/\/(.+?)\/?$/i.exec(n),o=r?r[1].toLowerCase():t,s=(r?r[2]:n).replace(/\/.*$/,"").replace(/:\d+$/,"").toLowerCase();return s?{proto:o,host:s}:null}function M$(e){let t=typeof e=="string"&&e.trim()?O$(e,"https").host:null;if(R$().viewBase===t)return;za={viewBase:t};let r=I$();try{t?(Hp.mkdirSync(By.dirname(r),{recursive:!0}),Hp.writeFileSync(r,JSON.stringify({viewBase:t,learnedAt:new Date().toISOString()})+`
|
|
731
|
+
`)):Hp.rmSync(r,{force:!0})}catch{}}function jy(){return R$().viewBase}function Ly(e=process.env.BOSTRAT_PUBLIC_HOST){return O$(e,"https")}function C$(){let e=jy();if(e)return{proto:"https",host:e,source:"learned"};let t=Ly();return t?{...t,source:"env"}:null}function Wp(e,t){return e?`${e.proto}://${t}.${e.host}/`:null}function vq(e=process.env.BOSTRAT_PLANE_URL){let t=String(e||"").trim();if(!t)return null;let n=/^(wss?|https?):\/\/([^/?#]+)/i.exec(t);return n?`${/^(wss|https)$/i.test(n[1])?"https":"http"}://${n[2]}`:null}function N$(){let e=String(process.env.BOSTRAT_PUBLIC_URL||"").trim().replace(/\/+$/,"");if(e)return{url:e,source:"env"};let t=vq();return t?{url:t,source:"plane"}:null}var P$="this node has no public app URL for Track links: link it to a plane (bostrat-node init) or set BOSTRAT_PUBLIC_URL in node.env";var W$={linear:{api:Dy,config:vs},jira:{api:My,config:Fp}};async function Gy(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(W$)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Ts(e){let t=W$[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Vy(e,t){if(!e||e.name)return e;let n=t.find(r=>r.id===e.id);return n?{...e,name:n.name}:e}var q$=()=>process.env.BOSTRAT_STATE_DIR||U$.join(process.env.HOME||Sq.tmpdir(),".bostrat"),Wy=()=>U$.join(q$(),"tickets.json"),dl=e=>{let t=N$();if(!t)throw new Error(P$);return`${t.url}/track/${e}`},Aq=e=>`http://bostrat.globopi/track/${e}`,D$=e=>{let t=0;for(let[n,r]of Object.entries(e))r&&typeof r=="object"&&!r.cardUrl&&(r.cardUrl=Aq(n),t++);return t},Yn=null,Fy=null,Uy=Promise.resolve();async function pl(){return Yn||(Fy??=ll.readFile(Wy(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{Yn=e;let n=D$(Yn)>0;if(!t&&qe()){let{records:r,source:o}=await lt("tickets").catch(()=>({records:[],source:"error"}));if(o==="plane"){for(let s of r){if(s.deletedAt||!s.data?.id)continue;let{id:a,updatedAt:i,...c}=s.data;Yn[a]=c}D$(Yn),n=n||Object.keys(Yn).length>0}}return n&&await qy().catch(()=>{}),Yn}).finally(()=>Fy=null),Fy)}async function qy(){let e=JSON.stringify({tickets:Yn},null,2),t=`${Wy()}.${process.pid}.tmp`;await ll.mkdir(q$(),{recursive:!0}),await ll.writeFile(t,e),await ll.rename(t,Wy())}async function ko(e=null){if(Uy=Uy.then(qy,qy),await Uy.catch(()=>{}),!e)return;let t=Yn?.[e];t?Tt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):an("tickets",e).catch(()=>{})}async function Xn(e){return(await pl())[e]??null}async function K$(){return{...await pl()}}async function G$(){return(await Gy()).length>0}async function Ja(e,t,{source:n="api"}={}){let r=await Gy();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let d=u.api.parseIssueRef(t);if(d)try{s=await u.api.resolveIssue(u.cfg,d),o=u;break}catch(p){a=p}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),cardUrl:dl(e.id),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await pl())[e.id]=c,await ko(e.id),await C({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await ul(e.id,c);let l=[];return c.track.branch&&l.push(`\`${c.track.branch}\``),c.track.repos?.length&&l.push(`repos ${c.track.repos.join(" + ")}`),c.track.leadAgent&&l.push(`lead ${c.track.leadAgent}`),await cl(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await J$(e.id,c,"linked"),c}async function zy(e){let t=await pl();return t[e]?(delete t[e],await ko(e),!0):!1}var Ky=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function V$(e,t){if(!e.track?.cwd)return null;let n=Jr(await q({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function Tq(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Ky(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Ky(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function Eq(e,t){let n=[];return e.track.leadAgent&&n.push(`lead ${e.track.leadAgent}`),e.track.branch&&n.push(e.track.branch),e.track.repos?.length&&n.push(e.track.repos.join(" + ")),e.pr?.number&&n.push(`PR #${e.pr.number} ${e.pr.change==="merged"?"merged":"open"}`),t&&n.push(Ky(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function ul(e,t){let n=await Ts(t);if(!n)return;let r=await V$(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:t.cardUrl??dl(e),title:`Bostrat Track: ${t.track.name}`,subtitle:Eq(t,r)})}function _q(e){return Wp(C$(),e)}var qp=e=>_q(e)??"(no public URL on this node \u2014 link it to a plane)",Iq={linked:"linked",opened:"prOpened",merged:"prMerged"};function $q(e,t,n){let r=o=>t.filter(s=>s.type===o).sort((s,a)=>s.position-a.position);if(n==="linked"){if(["triage","backlog","unstarted"].includes(e?.type))return r("started")[0]??null}else if(n==="opened"){if(e?.type!=="completed")return r("started").find(o=>/review/i.test(o.name))??null}else if(n==="merged"&&e?.type!=="completed")return r("completed")[0]??null;return null}async function z$(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await ko(e),await C({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function J$(e,t,n){let r=await Ts(t);if(!r)return;let o=r.cfg.ticketFlow?.[Iq[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Vy(s,a),c=$q(i,a,n);if(!c||c.id===i?.id)return;let l=i?.name??t.state??null;if(o==="auto"){await r.api.moveIssue(r.cfg,t,c.id),await z$(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await C({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:H$(),provider:t.provider,key:t.key,url:t.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...t.pr?.number?{prNumber:t.pr.number}:{}}}).catch(()=>{})}async function Y$(e){let t=await Xn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Ts(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Vy(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await ko(e)),{key:t.key,url:t.url,current:s?{id:s.id,name:s.name??null,type:s.type??null}:null,states:[...o].sort((a,i)=>a.position-i.position).map(({id:a,name:i,type:c,position:l})=>({id:a,name:i,type:c,position:l}))}}async function Jy(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Xn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Ts(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Vy(s,a),c=a.find(u=>u.id===t);if(!c)throw new Error("unknown state for this ticket's team");let l=i?.name??r.state??null;return i?.id===c.id?(r.state!==c.name&&(r.state=c.name,await ko(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await z$(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function X$(e,t){let n=await Xn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Ts(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await C({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function Z$(e,t,n){if(!t)throw new Error("offerId required");return uo(`tkt:${e.id}:${t}`,()=>Rq(e,t,n))}async function Rq(e,t,n){let r=await q({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await Jy(e.id,o.payload.to?.id,{mode:"offer"})),await C({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var B$=50;async function Q$(){let e=await vs();if(!e)throw new Error("no ticketing integration configured");return Va(e)}function Oq(e){let t=e&&typeof e=="object"?e:{},n=(Array.isArray(t.issues)?t.issues:[]).map(o=>o&&typeof o=="object"?o:{title:String(o||"")}).map(o=>({title:String(o.title||"").trim(),description:o.description?String(o.description):null,priority:Number.isInteger(o.priority)&&o.priority>=0&&o.priority<=4?o.priority:null})).filter(o=>o.title),r=t.epic&&String(t.epic.name||"").trim()?{name:String(t.epic.name).trim(),description:t.epic.description?String(t.epic.description):null}:null;if(!n.length&&!r)throw new Error("a plan needs an epic or at least one issue");if(n.length>B$)throw new Error(`too many issues (${n.length}); cap is ${B$} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function Mq(e,t,n,r){let o=r??await Va(e),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(t.team){let i=s(t.team);if(i)return i}let a=await Xn(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(e.defaultTeam){let i=s(e.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function eR(e,t){let n=await vs();if(!n)throw new Error("no ticketing integration configured \u2014 add a linear apiKey to ~/.bostrat/integrations.json");if(n.ticketFlow?.create==="off")throw new Error("ticket creation offers are off (bostrat-ticket flow set create=prompt to re-enable)");let r=Oq(t),o=await Va(n),s=await Mq(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=H$();return await C({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function tR(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await q({id:e.id,cwd:e.cwd}),s=o.find(w=>w.type==="ticket.create.offered"&&w.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(w=>w.type==="ticket.create.answered"&&w.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await vs();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await Va(a)).find(m=>m.id===r);if(!w)throw new Error("unknown team");c={id:w.id,key:w.key,name:w.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let w=await Ny(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=w.id,l.push({kind:"epic",title:w.name,url:w.url})}for(let w of i.issues||[])try{let m=await Py(a,{teamId:c.id,title:w.title,description:w.description,projectId:d,priority:w.priority});l.push({kind:"issue",key:m.key,title:m.title,url:m.url})}catch(m){u.push({title:w.title,message:m?.message||String(m)})}await C({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await C({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let p=l.filter(w=>w.kind==="issue"),f=null;return i.linkCurrentTrack&&p.length===1&&!await Xn(e.id)&&(f=await Ja(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function cl(e,t){let n=await Ts(e);n&&await n.api.createComment(n.cfg,e,t)}async function Cq(e,t,n){let r=await Ts(e);if(!r)return null;let o=await xr(t);if(!o)return null;let s=gn(o,n);if(!s)return null;let a=await ll.readFile(nn(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:e.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var j$=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Hy=new Map;function Nq(e,t){if(j$()<=0)return ul(e,t);if(Hy.has(e))return;let n=setTimeout(()=>{Hy.delete(e),Xn(e).then(r=>r?ul(e,r):null).catch(()=>{})},j$());n.unref?.(),Hy.set(e,n)}var L$=new Map;async function F$(e,t,n){let r=L$.get(e)??0;Date.now()-r<600*1e3||(L$.set(e,Date.now()),await C({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function Pq(e,{resolveTrack:t=null}={}){let n=await Xn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Gy())if(o=a.api.findIssueUrl(r.text,a.cfg),o)break;if(!o)return;let s=t?await t(e.trackId):null;if(!s)return;try{await Ja(s,o,{source:"chat"})}catch(a){await F$(e.trackId,s.cwd,a)}return}if(!n.track.cwd&&t){let o=await t(e.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await ko(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await ko(e.trackId),await ul(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await ko(e.trackId),await ul(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await V$(n,e.trackId).catch(()=>null):null;await cl(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
|
|
731
732
|
|
|
732
|
-
Agent cost for this Track: ${
|
|
733
|
+
Agent cost for this Track: ${Tq(o)}.`:"")),await J$(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await Cq(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await cl(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
|
|
733
734
|
|
|
734
|
-
`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await
|
|
735
|
-
_(runs on the Track's branch;
|
|
736
|
-
${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${
|
|
735
|
+
`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await cl(n,`**Bostrat** \u2014 design decision: **${r.name}** picked${o?` over ${o}`:""}.`)}break}case"view.state.changed":{if(r.change!=="created"||r.restarted||!r.slug)break;await cl(n,`**Bostrat** \u2014 live preview **${r.name}**: ${qp(r.slug)}
|
|
736
|
+
_(runs on the Track's branch; a Bostrat-fronted preview, not a public deployment)_`);break}case"cost.recorded":await Nq(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await F$(e.trackId,s?.cwd??null,o)}}function nR({resolveTrack:e}){Je.on("event",t=>{Pq(t,{resolveTrack:e}).catch(()=>{})})}async function rR(){if(!qe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await lt("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await pl(),r=0;for(let[o,s]of Object.entries(n))await Tt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}ts();Ra();import Dq from"ws";var oR=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function Kp(e,t,n={}){let r=await fetch(`${oR()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json; charset=utf-8"},body:JSON.stringify(n)}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}var Yy=(e,t)=>Kp("chat.postMessage",e,t),Es=(e,t)=>Kp("chat.update",e,t);async function It(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function Bq(e,t,n={}){let r=await fetch(`${oR()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/x-www-form-urlencoded; charset=utf-8"},body:new URLSearchParams(n).toString()}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}async function sR(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await Bq("files.getUploadURLExternal",e,{filename:t,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return Kp("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var jq=2200;function aR({getToken:e,onEnvelope:t,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await e();if(!u)throw new Error("app token missing");({url:l}=await Kp("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new Dq(l),o.on("message",u=>{let d;try{d=JSON.parse(u)}catch{return}if(d.type==="hello"){a=1e3,n("socket connected");return}if(d.type==="disconnect"){try{o.close()}catch{}return}if(!d.envelope_id)return;let p=m=>{try{o.send(JSON.stringify(m?{envelope_id:d.envelope_id,payload:m}:{envelope_id:d.envelope_id}))}catch{}},f=!1,w=setTimeout(()=>{f=!0,p()},jq);Promise.resolve().then(()=>t(d)).then(m=>{clearTimeout(w),!f&&(f=!0,p(d.accepts_response_payload?m:void 0))},m=>{clearTimeout(w),f||(f=!0,p()),n(`envelope handler failed: ${m?.message||m}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var lR=()=>process.env.BOSTRAT_STATE_DIR||Vp.join(process.env.HOME||Fq.tmpdir(),".bostrat"),tb=()=>Vp.join(lR(),"slack.json"),Gp=null,Xy=null,Zy=Promise.resolve();async function rb(){return Gp||(Xy??=fl.readFile(tb(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>Gp=e).finally(()=>Xy=null),Xy)}async function iR(){let e=JSON.stringify({threads:Gp},null,2),t=`${tb()}.${process.pid}.tmp`;await fl.mkdir(lR(),{recursive:!0}),await fl.writeFile(t,e),await fl.rename(t,tb())}async function Sn(){Zy=Zy.then(iR,iR),await Zy.catch(()=>{})}async function ob(e){return(await rb())[e]??null}async function Uq(e,t){let n=await rb();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var _e=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");function ml(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function Hq(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return ml(n.replace(/\n+/g," "),t)}function uR(e){let t=`*${_e(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${_e(e.repoLabel)} \xB7 \`${_e(e.branch||"?")}\` \xB7 lead *${_e(e.lead)}*`,r=e.kickoff?`> ${_e(ml(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
|
|
737
|
+
${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${dl(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function nb(e,t){await Es(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:uR(t)})}async function vo(e,t,n,r=void 0){return Yy(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var cR=new Set;function xo(e){cR.add(e),e.catch(()=>{}).finally(()=>cR.delete(e))}var We=e=>({response_type:"ephemeral",text:e}),Wq="*/bostrat* \u2014 `start <name> [repo]` \xB7 `archive <track>` \xB7 `handoff <track> <agent>` \xB7 `stop <track>` \xB7 `list`\n_Reply in a Track's thread to steer its lead; question prompts and ship offers appear there as buttons._",qq=["claude","cursor","codex"];function Qy(e,t){let n=(t||"").toLowerCase(),r=e.filter(s=>!s.archivedAt),o=r.filter(s=>s.name.toLowerCase().startsWith(n));return o.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),{match:o[0]??null,live:r}}var eb=(e,t)=>We(`No live Track matches \u201C${_e(t)}\u201D. Live: ${e.map(n=>`\`${_e(n.name)}\``).join(" \xB7 ")||"none"}`);async function dR(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(d=>!d.archivedAt);if(a.length>=t.maxConcurrent){await It(o,{...We(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await It(o,{...We("No designated channel configured \u2014 set `slack.channel` in integrations.json."),replace_original:!0});return}let i=await s.createTrack({name:n,...r?{repo:r}:{}}),c=i.workspace||{},l={trackId:i.id,channel:t.channel,name:i.name,branch:c.branch||null,repoLabel:c.repo||(c.base?Vp.basename(c.base):"fresh workspace"),lead:"claude"},u=await Yy(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:uR(l),unfurl_links:!1});l.ts=u.ts,(await rb())[i.id]=l,await Sn(),await It(o,{...We(`\u2713 *${_e(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await It(o,{...We(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function Kq(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await ob(n.id);s&&(s.archivedAt=Date.now(),await Sn(),await nb(t,s).catch(()=>{})),await It(r,{...We(`\u2713 *${_e(n.name)}* archived.`),replace_original:!0})}catch(s){await It(r,{...We(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function Gq(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await It(o,{...We(`\u2713 Handing *${_e(n.name)}* to ${_e(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await It(o,{...We(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function Vq(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.interruptLead(n.id);let s=(o.listSubtaskJobs?.(n.id)??[]).filter(a=>!a.finishedAt);for(let a of s)try{o.cancelSubtask(a.id)}catch{}await It(r,{...We(`\u2713 Stopped *${_e(n.name)}*${s.length?` (+ ${s.length} subtask${s.length>1?"s":""} canceled)`:""} \u2014 Track parked, resume from the Track page.`),replace_original:!0})}catch(s){await It(r,{...We(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function zq(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:ml(`${r.name} (${r.branch})`,75)},value:r.path})),{text:{type:"plain_text",text:"fresh workspace"},value:"__fresh__"}];return[{type:"section",block_id:JSON.stringify({name:e}),text:{type:"mrkdwn",text:`Repo for *${_e(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function Jq(e){let t=await e.listTracks(),n=t.filter(s=>!s.archivedAt);if(n.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),!n.length)return"No live Tracks.";let r=n.map(s=>{let a=s.workspace||{},i=a.repo||(a.base?Vp.basename(a.base):"fresh"),c=[...s.boxes||[]].reverse().find(u=>u.role==="lead")?.agent||"?",l=s.prompted?"\u26A0 needs an answer":s.working?"working":"idle";return`\u2022 *${_e(s.name)}* \u2014 ${_e(i)}${a.branch?` \`${_e(a.branch)}\``:""} \xB7 lead ${_e(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
|
|
737
738
|
`)+(o?`
|
|
738
|
-
_${o} archived_`:"")}async function
|
|
739
|
-
\u2713 *${_e(a)}*`}}]}).catch(()=>{})}}catch(c){await
|
|
740
|
-
\u2713 _answered_`}}]})}async function
|
|
741
|
-
_runs on the Track's branch;
|
|
742
|
-
`)){let r=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={input:s.input_tokens||0,output:s.output_tokens||0,cacheWrite:s.cache_creation_input_tokens||0,cacheRead:s.cache_read_input_tokens||0};if(a.input+a.output+a.cacheWrite+a.cacheRead===0)continue;let i=o.message?.id||o.uuid||null;if(!i)continue;let c=s.cache_creation,l=c&&typeof c=="object"?{m5:c.ephemeral_5m_input_tokens||0,h1:c.ephemeral_1h_input_tokens||0}:null,u=typeof s.speed=="string"&&s.speed!=="standard"?s.speed:null;t.set(i,{messageId:i,tokens:a,cacheWriteTtl:l,speed:u,model:o.message?.model||o.model||null})}return[...t.values()]}function
|
|
743
|
-
`)}fe();Om();import c5 from"node:fs/promises";import l5 from"node:path";Au();$u();zr();var Kp=e=>e.payload?.ts??e.ts,n5=12e4,rn=e=>Math.round(e*1e4)/1e4,r5=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function o5(e,{since:t}){let{track:n,events:r,brief:o}=e,s=b=>Kp(b)>=t,a=or([Gi(n?.name),Gi(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let b of r)if(b.type==="subtask.delegated"&&b.boxId&&b.payload?.task){let I=or(b.payload.task);I&&i.set(b.boxId,I)}let c=new Map,l=b=>{let I=b||"unattributed";return c.has(I)||c.set(I,{segments:[u(null)],lastTs:null,provider:null}),c.get(I)},u=(b,{shape:I="initial",continuation:R=!1,text:N=null,ts:D=null}={})=>({textCat:b,shape:I,continuation:R,text:N,ts:D,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((b,I)=>Kp(b)-Kp(I)),p=0,f=0,w=0,h={turns:0};for(let b of d){let I=l(b.boxId),R=I.segments[I.segments.length-1],N=Kp(b);switch(I.lastTs!=null&&N>I.lastTs&&s(b)&&(R.activeMs+=Math.min(N-I.lastTs,n5)),I.lastTs=N,b.provider&&(I.provider=b.provider),b.type){case"turn.user":{let D=b.payload?.text;if(b.source==="hook"||!String(D||"").trim()||b.payload?.note||Ji(D))break;let j=or(D),T=!!b.payload?.kind,$=T||mx(D),F=u(j,{shape:T?"injected":$?"follow-up":"novel-ask",continuation:!j&&$,text:nR(D),ts:N});I.segments.push(F),s(b)&&(F.turns+=1);break}case"peer.message":{let D=b.payload?.text;if(!String(D||"").trim())break;let j=or(D),T=u(j,{shape:"peer",continuation:!j,text:nR(D),ts:N});I.segments.push(T),s(b)&&(T.turns+=1);break}case"tool.called":{if(b.source==="transcript")break;let D=b.payload?.tool;D&&(R.tools[D]=(R.tools[D]||0)+1),s(b)&&(R.toolCalls+=1);break}case"cost.recorded":{if(!s(b))break;let{usd:D,tokens:j,model:T,unpriced:$}=Xt(b);$&&(h.turns+=1),R.usd+=D,j&&(R.tokens.input+=j.input,R.tokens.output+=j.output,R.tokens.cacheRead+=j.cacheRead,R.tokens.cacheWrite+=j.cacheWrite),R.models[T]=(R.models[T]||0)+D,b.provider&&(R.provider=b.provider);break}case"handoff.done":s(b)&&(p+=1);break;case"subtask.merged":s(b)&&(f+=1);break;case"error":s(b)&&b.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},k=!1;for(let[b,I]of c){let R=null;for(let N of I.segments){let D=null,j=null;if(N.textCat)D=N.textCat.category,j="text";else if(i.get(b))D=i.get(b).category,j="boxTask";else if(N.continuation&&R)D=R,j="inherited";else{let M=hx(N.tools);M?(D=M.category,j="toolMix"):a&&(D=a.category,j="hint")}if(D&&(R=D),!(N.usd>0||N.activeMs>0||N.turns>0||N.toolCalls>0))continue;let $=D??"uncategorized";g.has($)||g.set($,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let F=g.get($);F.usd+=N.usd,F.activeMs+=N.activeMs,F.turns+=N.turns,F.toolCalls+=N.toolCalls,j&&(F.provenance[j]=(F.provenance[j]||0)+N.usd);for(let[M,S]of Object.entries(N.models))F.models[M]=(F.models[M]||0)+S;let J=N.provider||I.provider;J&&(F.providers[J]=(F.providers[J]||0)+N.usd),J==="cursor"&&N.usd===0&&(k=!0),D||(y.usd+=N.usd,y.turns+=N.turns,y.byShape[N.shape]=(y.byShape[N.shape]||0)+N.usd,N.usd>0&&N.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:N.shape,usd:rn(N.usd),ts:N.ts,text:N.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:f,failed:w,sawCursorActivity:k,unpricedTurns:h.turns}}function Qy(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:k,events:b}=y;if(!b?.length){a+=1;continue}let{perCategory:I,uncategorized:R,handoffs:N,merged:D,failed:j,sawCursorActivity:T,unpricedTurns:$}=o5(y,{since:r});T&&(i=!0),c+=$,l.usd+=R.usd,l.turns+=R.turns;for(let[J,M]of Object.entries(R.byShape))l.byShape[J]=(l.byShape[J]||0)+M;l.samples.push(...R.samples);let F={trackId:k?.id,name:k?.name||k?.id,archived:!!k?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:N,subtasksMerged:D,subtasksFailed:j};for(let[J,M]of I){F.usd+=M.usd,F.activeMs+=M.activeMs,F.turns+=M.turns,F.categories[J]={usd:rn(M.usd),activeMs:M.activeMs};for(let[H,K]of Object.entries(M.models))F.models[H]=rn((F.models[H]||0)+K);for(let[H,K]of Object.entries(M.providers))F.providers[H]=rn((F.providers[H]||0)+K);o.has(J)||o.set(J,r5());let S=o.get(J);S.usd+=M.usd,S.activeMs+=M.activeMs,S.turns+=M.turns,S.toolCalls+=M.toolCalls;for(let[H,K]of Object.entries(M.models))S.models[H]=(S.models[H]||0)+K;for(let[H,K]of Object.entries(M.providers))S.providers[H]=(S.providers[H]||0)+K;for(let[H,K]of Object.entries(M.provenance))S.provenance[H]=(S.provenance[H]||0)+K;let _=S.byTrack.get(k?.id)||{usd:0,activeMs:0};_.usd+=M.usd,_.activeMs+=M.activeMs,S.byTrack.set(k?.id,_)}(F.usd>0||F.activeMs>0||F.turns>0)&&(F.usd=rn(F.usd),F.dominantCategory=i5(F.categories),s.push(F))}let u=[...o.values()].reduce((y,k)=>y+k.usd,0),d=[...o.values()].reduce((y,k)=>y+k.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),h=[...o.entries()].map(([y,k])=>({category:y,sharePct:f>0?Math.round((p==="usd"?k.usd:k.activeMs)/f*100):0,shareBasis:p,usd:rn(k.usd),activeMs:k.activeMs,turns:k.turns,toolCalls:k.toolCalls,models:fl(k.models),providers:fl(k.providers),provenance:fl(k.provenance),topWorkstreams:[...k.byTrack.entries()].sort((b,I)=>I[1].usd-b[1].usd||I[1].activeMs-b[1].activeMs).slice(0,2).map(([b,I])=>({trackId:b,name:w.get(b),usd:rn(I.usd),activeMs:I.activeMs}))})).sort((y,k)=>k.usd-y.usd||k.activeMs-y.activeMs);s.sort((y,k)=>k.usd-y.usd||k.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[k,b]of Object.entries(y.provenance))g[k]=(g[k]||0)+b;return{since:r,capturedAt:n,totalUsd:rn(u),activeMs:d,turns:[...o.values()].reduce((y,k)=>y+k.turns,0),bullets:h,workstreams:s,provenance:fl(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:rn(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:fl(l.byShape),top:l.samples.sort((y,k)=>k.usd-y.usd).slice(0,s5)}}}}var s5=25,tR=160,nR=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>tR?`${t.slice(0,tR).trimEnd()}\u2026`:t},a5=10;function rR(e,{thresholdPct:t=a5}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:rn(o),totalUsd:rn(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var i5=e=>{let t=null;for(let[n,r]of Object.entries(e))(!t||r.usd>t.v.usd||r.usd===t.v.usd&&r.activeMs>t.v.activeMs)&&(t={cat:n,v:r});return t?.cat??null},fl=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,rn(n)]));var _s={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function u5(e){let t=String(e||"7d");return t in _s?{key:t,ms:_s[t]}:{key:"7d",ms:_s["7d"]}}function d5(e,t){let n=new Set((t||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...t||[]];for(let o of e?.events||[]){let s=nd(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:e.id,boxId:s.boxId??null,ts:o.at,type:s.type,actor:s.actor,provider:s.provider??null,source:s.source,payload:s.payload})}return r}async function p5(e){if(!e?.cwd)return null;try{let n=(await c5.readFile(l5.join(e.cwd,".bostrat","handoff","latest.md"),"utf8")).match(/^##\s*Objective\s*\n([\s\S]*?)(?:\n##\s|\n*$)/m);return n?n[1].trim().slice(0,1e3):null}catch{return null}}async function eb(e,{window:t="7d",from:n,to:r,now:o=Date.now()}={}){let s=Number(n),a=Number(r),i=Number.isFinite(s)&&s>0,c=i&&Number.isFinite(a)&&a>s?Math.min(a,o):o,{key:l,ms:u}=i?{key:"custom",ms:c-s}:u5(t),d=[];for(let w of e||[]){let h=await q(w),g=d5(w,h);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:w,events:g,brief:await p5(w)})}let p=Qy(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:Qy(d,{windowMs:_s["7d"],now:o});return{window:l,...p,categorization:rR(f)}}var hl=e=>`$${Number(e||0).toFixed(2)}`,oR=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},Es=(e,t)=>String(e).padEnd(t);function sR(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${hl(e.totalUsd)} \xB7 ${oR(e.activeMs)} active \xB7 ${e.turns} turn(s) \xB7 as of ${new Date(e.capturedAt).toISOString()}`);let n=e.provenance||{};e.totalUsd>0&&Object.keys(n).length&&t.push("labeled by: "+Object.entries(n).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Math.round(i/e.totalUsd*100)}%`).join(" \xB7 ")),t.push(""),t.push("WHERE IT WENT");for(let a of e.bullets||[])t.push(` ${Es(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${Es(a.category,15)} ${Es(hl(a.usd),10)} ${Es(oR(a.activeMs),6)} ${a.turns} turn(s)`+(a.topWorkstreams?.length?` \xB7 ${a.topWorkstreams.map(i=>i.name).join(", ")}`:""));let r=e.gaps||{};r.tracksWithoutEvents&&t.push(`${r.tracksWithoutEvents} track(s) have no attributed events yet`),r.cursorCostUnknown&&t.push("cursor time counted, cost unavailable"),r.unpricedTurns&&t.push(`WARNING: ${r.unpricedTurns} turn(s) unpriced \u2014 total under-reports`);let o=e.categorization;if(o){t.push(""),t.push((o.ok?"categorization ok: ":"CATEGORIZATION ALARM: ")+`${o.sharePct}% of the last 7d uncategorized (threshold ${o.thresholdPct}%) \xB7 ${o.inheritedPct}% inferred from the previous ask`);for(let a of o.problems||[])t.push(`WARNING: ${a}`)}let s=r.uncategorized;if(s){t.push(""),t.push(`UNCATEGORIZED RESIDUE \xB7 ${hl(s.usd)} (${s.sharePct}%) \xB7 ${s.turns} turn(s) \xB7 by shape: `+(Object.entries(s.byShape||{}).filter(([,a])=>a>0).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${hl(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${Es(hl(a.usd),8)} ${Es(a.shape,10)} ${Es(String(a.track||"").slice(0,26),26)} | ${a.text}`);s.top?.length&&(t.push(""),t.push("novel-ask rows are vocabulary the classifier lacks: add a rule in agent/src/task-classifier.js (and a line in test/uncategorized-corpus.test.mjs). follow-up rows had no prior ask on their box."))}return t.join(`
|
|
744
|
-
`)}
|
|
745
|
-
`).slice(-3).join(" | ").slice(0,300);d!==
|
|
746
|
-
`).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,t.length)&&!/^Current\s/i.test(t[c]);c++){let l=t[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=t[c].match(/^Resets\s+(.+)$/i);u&&i===null&&(i=u[1].trim())}return a===null?null:{pct:a,resets:i||null}},r=s=>{let a=t.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return t.forEach((s,a)=>{let i=s.match(/^Current week \(([^)]+)\)$/i);if(!i||/all models/i.test(i[1]))return;let c=n(a);c&&o.push({model:i[1].trim(),...c})}),{session:r(/^Current session\b/i),week:r(/^Current week \(all models\)/i)||r(/^Current week$/i),weekModels:o.length?o:null}}function
|
|
747
|
-
`).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function
|
|
748
|
-
`),r=!1;for(let o=n.length-1;o>=0;o--){let s=n[o].trim();if(!s||s[0]!=="{"||!s.includes("token_count"))continue;let a;try{a=JSON.parse(s)}catch{continue}let i=a?.payload;if(i?.type!=="token_count")continue;r=!0;let c=i.rate_limits;if(!c)return
|
|
749
|
-
`,{mode:384}),
|
|
739
|
+
_${o} archived_`:"")}async function Yq(e,t){let n=await Ss();if(!n)return We("Slack integration not configured.");let r=e.deps,o=(t.text||"").trim().split(/\s+/).filter(Boolean),s=(o[0]||"help").toLowerCase(),a=o.slice(1);switch(s){case"start":{if(!a.length)return We("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(d=>d.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(xo(dR(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),We(`Starting *${_e(u)}* on ${_e(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:zq(u,i)}}case"archive":{if(!a.length)return We("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Qy(await r.listTracks(),a.join(" "));return i?(xo(Kq(e,n,{track:i,responseUrl:t.response_url})),We(`Archiving *${_e(i.name)}*\u2026`)):eb(c,a.join(" "))}case"handoff":{let i=r.knownAgents??qq,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return We(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=Qy(await r.listTracks(),l);return u?(xo(Gq(e,n,{track:u,agent:c,responseUrl:t.response_url})),We(`Handing *${_e(u.name)}* to ${_e(c)}\u2026`)):eb(d,l)}case"stop":{if(!a.length)return We("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Qy(await r.listTracks(),a.join(" "));return i?(xo(Vq(e,n,{track:i,responseUrl:t.response_url})),We(`Stopping *${_e(i.name)}*\u2026`)):eb(c,a.join(" "))}case"list":return We(await Jq(r));default:return We(Wq)}}async function Xq(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await ob(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await Sn(),await Es(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${_e(l||"question")}~
|
|
740
|
+
\u2713 *${_e(a)}*`}}]}).catch(()=>{})}}catch(c){await It(n.response_url,We(`Couldn't answer: ${c?.message||c}`))}}async function Zq(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(p=>p.type==="pr.offered"&&p.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(p=>p.type==="pr.offer.answered"&&p.payload?.offerId===s))throw new Error("offer already answered");let d=Array.isArray(r.actions)?ro.filter(p=>r.actions.includes(p)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(d?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:d}))return;d&&await i.sayToLead(c.id,ma(d,{branch:u.payload.branch,base:u.payload.base}),{kind:d.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:d?a:"dismiss",actions:d}})}catch(c){await It(n.response_url,We(`Couldn't act on the offer: ${c?.message||c}`))}}async function Qq(e,t,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await e.deps.resolveTrack(o);if(!i)throw new Error("track not found");await e.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await It(n.response_url,We(`Couldn't act on the offer: ${i?.message||i}`))}}async function e5(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await Ss();if(!r)return;if(n.action_id==="bostrat-start-repo"){let s;try{({name:s}=JSON.parse(n.block_id))}catch{return}let a=n.selected_option?.value;await It(t.response_url,{...We(`Starting *${_e(s)}*\u2026`),replace_original:!0}),xo(dR(e,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:t.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?xo(Xq(e,r,t,o)):n.action_id==="bostrat-ship"?xo(Zq(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&xo(Qq(e,r,t,o))}async function t5(e,t){if(!t||t.type!=="message"||t.bot_id||t.subtype||!t.thread_ts||t.thread_ts===t.ts||!t.text?.trim())return;let n=await Uq(t.channel,t.thread_ts);if(!n)return;let r=await Ss();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await vo(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function n5(e){return async t=>{if(t.type==="slash_commands")return Yq(e,t.payload);if(t.type==="interactive"){await e5(e,t.payload);return}if(t.type==="events_api"){await t5(e,t.payload?.event);return}}}var r5=new Set(["turn.user","turn.agent","prompt.raised","prompt.answered","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","pr.state.changed","handoff.done","view.state.changed","mock.state.changed"]);function o5(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${_e(t.question||"The lead needs an answer")}`}}],r=(t.options||[]).slice(0,12);return r.length?n.push({type:"actions",elements:r.map(o=>({type:"button",action_id:"bostrat-prompt",text:{type:"plain_text",text:ml(String(o),75)},value:JSON.stringify({trackId:e,promptId:t.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function s5(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await Es(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${_e(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await vo(e,t,r.question||"The lead needs an answer",o5(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Sn()}async function a5(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await Sn(),await Es(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${_e(s||"question")}~
|
|
741
|
+
\u2713 _answered_`}}]})}async function i5(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(d=>l[d]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await vo(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${_e(ml(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Sn()}async function c5(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Sn();let s=r.action==="dismiss"?"dismissed":r.action==="pr-exists"?`PR${r.existingPr?.number?` #${r.existingPr.number}`:""} already open \u2014 pick how to ship`:r.action==="pr"?"\u2713 opening a PR":"\u2713 pushing";await Es(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function l5(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=r.pr?.number?`#${r.pr.number}`:"a PR",s=(i,c,l)=>({type:"button",action_id:"bostrat-pr-exists",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,choice:i}),...l?{style:l}:{}}),a=await vo(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${_e(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Sn()}async function u5(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Sn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await Es(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function d5(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??p5)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await sR(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${_e(o.name)}*${a}${o.group?` (group \`${_e(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${_e(a.name)}*`).join(", ");await vo(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${_e(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function p5(e,t){let n=await xr(e);if(!n)return null;let r=gn(n,t);if(!r)return null;let o=await fl.readFile(nn(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function f5(e,t){if(!r5.has(t.type))return;let n=await ob(t.trackId);if(!n)return;let r=await Ss();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await Sn(),await nb(r,n);return;case"turn.agent":{if(!o.text)return;let s=Hq(o.text);if(!s)return;await vo(r,n,s,[{type:"section",text:{type:"mrkdwn",text:_e(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${dl(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return s5(r,n,t);case"prompt.answered":return a5(r,n,t);case"pr.offered":return i5(r,n,t);case"pr.offer.answered":return c5(r,n,t);case"pr.exists.offered":return l5(r,n,t);case"pr.exists.answered":return u5(r,n,t);case"pr.state.changed":{if(o.change!=="opened"&&o.change!=="merged")return;let s=o.change==="opened"?"PR opened":"PR merged";await vo(r,n,`${s}${o.url?`: ${o.url}`:o.number?` (#${o.number})`:""}`);return}case"handoff.done":if(!o.toAgent||o.toAgent===n.lead)return;n.lead=o.toAgent,await Sn(),await nb(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await vo(r,n,`Live preview ${o.name}: ${qp(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${_e(o.name)}*: ${qp(o.slug)}
|
|
742
|
+
_runs on the Track's branch; a Bostrat-fronted preview, not a public deployment_`}}]);return}case"mock.state.changed":return d5(r,n,t,e.deps)}}function pR(e){let t={deps:e};Je.on("event",s=>{f5(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Ss()||(r&&clearInterval(r),r=null,n=aR({getToken:async()=>(await Ss())?.appToken,onEnvelope:n5(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}dn();me();In();dw();ir();import m5 from"node:fs/promises";function h5(e){let t=new Map;for(let n of String(e||"").split(`
|
|
743
|
+
`)){let r=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={input:s.input_tokens||0,output:s.output_tokens||0,cacheWrite:s.cache_creation_input_tokens||0,cacheRead:s.cache_read_input_tokens||0};if(a.input+a.output+a.cacheWrite+a.cacheRead===0)continue;let i=o.message?.id||o.uuid||null;if(!i)continue;let c=s.cache_creation,l=c&&typeof c=="object"?{m5:c.ephemeral_5m_input_tokens||0,h1:c.ephemeral_1h_input_tokens||0}:null,u=typeof s.speed=="string"&&s.speed!=="standard"?s.speed:null;t.set(i,{messageId:i,tokens:a,cacheWriteTtl:l,speed:u,model:o.message?.model||o.model||null})}return[...t.values()]}function w5(e){let t=new Set;for(let n of e)if(n.type==="cost.recorded"){n.payload?.messageId&&t.add(n.payload.messageId);for(let r of n.payload?.messageIds||[])t.add(r)}return t}var g5=new Set(["Write","Edit","NotebookEdit"]),y5=220,b5=160;function k5(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(g5.has(n)&&typeof o.file_path=="string"&&o.file_path){let s=o.file_path,a=t?.cwd;a&&s.startsWith(`${a}/`)&&(s=s.slice(a.length+1)),r.path=s.slice(0,y5)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=Do(o.command.trim().replace(/\s+/g," ")).slice(0,b5));return r}function x5(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?un(t.cwd,t.sessionId):t?.cwd?im(t.cwd):null}async function fR(e,t){let n=await t(e?.session_id,e?.cwd);if(!n?.track)return[];let{track:r,box:o}=n,s={boxId:o?.name||null,provider:"claude",source:"hook"},a=[],i=async c=>{a.push(await C(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=Nd(c);await i({type:"turn.user",actor:l?"peer":"user",payload:{promptHead:(l?l.text:c).slice(0,160)||null,...l?{peer:{socket:l.socket,name:l.name,mode:l.mode}}:{}}});break}case"PostToolUse":await i({type:"tool.called",actor:"agent",payload:k5(e,o)});break;case"Stop":await v5(r,o,e,i);break;default:break}return a}async function v5(e,t,n,r){let o=[],s=x5(n,t);if(s)try{o=h5(await m5.readFile(s,"utf8"))}catch{}let a=o.length?o[o.length-1]:null;if(await r({type:"turn.agent",actor:"agent",payload:{model:a?.model??t?.model??null,messageId:a?.messageId??null}}),!o.length)return;let i=w5(await q(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let d of c){let p=`${d.model||"unknown"}\0${d.speed||""}`,f=u.get(p)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let w of Object.keys(f.tokens))f.tokens[w]+=d.tokens[w];d.cacheWriteTtl&&(f.cacheWriteTtl??={m5:0,h1:0},f.cacheWriteTtl.m5+=d.cacheWriteTtl.m5,f.cacheWriteTtl.h1+=d.cacheWriteTtl.h1),f.messageIds.push(d.messageId),f.speed=d.speed||null,u.set(p,f)}for(let[d,p]of u){let f=d.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:Cn(f,p.tokens,void 0,p.speed?{speed:p.speed}:void 0),tokens:p.tokens,...p.speed?{speed:p.speed}:{},cacheWriteTtl:p.cacheWriteTtl,messageId:p.messageIds[p.messageIds.length-1],messageIds:p.messageIds,apiCalls:p.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}Ms();Zf();Md();me();me();Yr();me();Yr();ir();function hl(e){let t={};for(let n of e.boxes||[]){let r=n.role&&n.role!=="lead"?` \xB7 ${n.role}`:"";t[n.name]=`${n.name} (${n.agent||"?"}${r})`}return t}var mR=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),hR=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},zp=e=>Math.round(e*1e4)/1e4;async function sb(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=mR(),d=0,p=[];for(let f of e||[]){let w=await q(f),m=Jr(w,{boxLabels:hl(f)});if(m.turns===0){f.archivedAt?d++:p.push(f.name||f.id);continue}o+=m.totalUsd,s+=m.turns,a+=m.repricedTurns||0,i+=m.asRecordedUsd||0,c+=m.unpricedTurns||0;for(let g of m.unpricedModels||[])l.add(g);hR(u,m.totalTokens);for(let[g,y]of Object.entries(m.byModel))n[g]||={usd:0,events:0,tokens:mR()},n[g].usd=zp(n[g].usd+y.usd),n[g].events+=y.events,hR(n[g].tokens,y.tokens);for(let[g,y]of Object.entries(m.byProvider))r[g]||={usd:0,events:0},r[g].usd=zp(r[g].usd+y.usd),r[g].events+=y.events;t.push({id:f.id,name:f.name,usd:m.totalUsd,rollup:m})}return t.sort((f,w)=>w.usd-f.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:oa(),fleet:{totalUsd:zp(o),asRecordedUsd:zp(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:d+p.length,tracksSilentArchived:d,tracksSilentLive:p},tracks:t}}var So=e=>`$${e.toFixed(4)}`,Ya=(e,t)=>String(e).padEnd(t);function wR(e){let{fleet:t,tracks:n}=e,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${e.generatedAt}`),e.pricingBasis&&r.push(`basis: ${e.pricingBasis}`);let o=t.tracksSilentLive||[];if(r.push(`fleet total ${So(t.totalUsd)} over ${t.turns} turn(s) \xB7 ${t.tracksWithCost} track(s) with cost, ${t.tracksSilentArchived??t.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),t.repricedTurns&&r.push(`${t.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),t.asRecordedUsd!=null&&Math.abs(t.asRecordedUsd-t.totalUsd)>=.005&&r.push(`as-recorded total ${So(t.asRecordedUsd)} \xB7 current-rates total ${So(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${So(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),e.pricing){let a=e.pricing;r.push(`rates verified against vendor pages: ${a.tableVerifiedAt??"never"}`+(a.upcomingChanges?.length?` \xB7 scheduled: ${a.upcomingChanges.map(i=>`${i.model} ${i.from}`).join(", ")}`:""));for(let i of a.problems||[])r.push(`\u26A0 RATE TABLE: ${i}`)}r.push(""),r.push("BY MODEL");let s=Object.entries(t.byModel).sort((a,i)=>i[1].usd-a[1].usd);s.length||r.push(" (no cost events yet \u2014 hooks emit on each turn of a newly started box)");for(let[a,i]of s){let c=i.tokens;r.push(` ${Ya(a,26)} ${Ya(So(i.usd),10)} ${i.events} turn(s) \xB7 in ${c.input} out ${c.output} cacheR ${c.cacheRead} cacheW ${c.cacheCreation}`)}r.push(""),r.push("BY TRACK / TASK");for(let a of n){r.push(` ${Ya(a.name||a.id,30)} ${So(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${Ya(c.label,40)} ${Ya(So(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((d,p)=>Number(d[0])-Number(p[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${Ya(So(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
|
|
744
|
+
`)}me();Ph();import $5 from"node:fs/promises";import R5 from"node:path";_u();Mu();Yr();var Jp=e=>e.payload?.ts??e.ts,S5=12e4,rn=e=>Math.round(e*1e4)/1e4,A5=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function T5(e,{since:t}){let{track:n,events:r,brief:o}=e,s=b=>Jp(b)>=t,a=ar([zi(n?.name),zi(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let b of r)if(b.type==="subtask.delegated"&&b.boxId&&b.payload?.task){let I=ar(b.payload.task);I&&i.set(b.boxId,I)}let c=new Map,l=b=>{let I=b||"unattributed";return c.has(I)||c.set(I,{segments:[u(null)],lastTs:null,provider:null}),c.get(I)},u=(b,{shape:I="initial",continuation:$=!1,text:P=null,ts:F=null}={})=>({textCat:b,shape:I,continuation:$,text:P,ts:F,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((b,I)=>Jp(b)-Jp(I)),p=0,f=0,w=0,m={turns:0};for(let b of d){let I=l(b.boxId),$=I.segments[I.segments.length-1],P=Jp(b);switch(I.lastTs!=null&&P>I.lastTs&&s(b)&&($.activeMs+=Math.min(P-I.lastTs,S5)),I.lastTs=P,b.provider&&(I.provider=b.provider),b.type){case"turn.user":{let F=b.payload?.text;if(b.source==="hook"||!String(F||"").trim()||b.payload?.note||Xi(F))break;let B=ar(F),T=!!b.payload?.kind,_=T||Sx(F),U=u(B,{shape:T?"injected":_?"follow-up":"novel-ask",continuation:!B&&_,text:yR(F),ts:P});I.segments.push(U),s(b)&&(U.turns+=1);break}case"peer.message":{let F=b.payload?.text;if(!String(F||"").trim())break;let B=ar(F),T=u(B,{shape:"peer",continuation:!B,text:yR(F),ts:P});I.segments.push(T),s(b)&&(T.turns+=1);break}case"tool.called":{if(b.source==="transcript")break;let F=b.payload?.tool;F&&($.tools[F]=($.tools[F]||0)+1),s(b)&&($.toolCalls+=1);break}case"cost.recorded":{if(!s(b))break;let{usd:F,tokens:B,model:T,unpriced:_}=Xt(b);_&&(m.turns+=1),$.usd+=F,B&&($.tokens.input+=B.input,$.tokens.output+=B.output,$.tokens.cacheRead+=B.cacheRead,$.tokens.cacheWrite+=B.cacheWrite),$.models[T]=($.models[T]||0)+F,b.provider&&($.provider=b.provider);break}case"handoff.done":s(b)&&(p+=1);break;case"subtask.merged":s(b)&&(f+=1);break;case"error":s(b)&&b.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},x=!1;for(let[b,I]of c){let $=null;for(let P of I.segments){let F=null,B=null;if(P.textCat)F=P.textCat.category,B="text";else if(i.get(b))F=i.get(b).category,B="boxTask";else if(P.continuation&&$)F=$,B="inherited";else{let R=vx(P.tools);R?(F=R.category,B="toolMix"):a&&(F=a.category,B="hint")}if(F&&($=F),!(P.usd>0||P.activeMs>0||P.turns>0||P.toolCalls>0))continue;let _=F??"uncategorized";g.has(_)||g.set(_,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let U=g.get(_);U.usd+=P.usd,U.activeMs+=P.activeMs,U.turns+=P.turns,U.toolCalls+=P.toolCalls,B&&(U.provenance[B]=(U.provenance[B]||0)+P.usd);for(let[R,A]of Object.entries(P.models))U.models[R]=(U.models[R]||0)+A;let J=P.provider||I.provider;J&&(U.providers[J]=(U.providers[J]||0)+P.usd),J==="cursor"&&P.usd===0&&(x=!0),F||(y.usd+=P.usd,y.turns+=P.turns,y.byShape[P.shape]=(y.byShape[P.shape]||0)+P.usd,P.usd>0&&P.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:P.shape,usd:rn(P.usd),ts:P.ts,text:P.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:f,failed:w,sawCursorActivity:x,unpricedTurns:m.turns}}function ab(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:x,events:b}=y;if(!b?.length){a+=1;continue}let{perCategory:I,uncategorized:$,handoffs:P,merged:F,failed:B,sawCursorActivity:T,unpricedTurns:_}=T5(y,{since:r});T&&(i=!0),c+=_,l.usd+=$.usd,l.turns+=$.turns;for(let[J,R]of Object.entries($.byShape))l.byShape[J]=(l.byShape[J]||0)+R;l.samples.push(...$.samples);let U={trackId:x?.id,name:x?.name||x?.id,archived:!!x?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:P,subtasksMerged:F,subtasksFailed:B};for(let[J,R]of I){U.usd+=R.usd,U.activeMs+=R.activeMs,U.turns+=R.turns,U.categories[J]={usd:rn(R.usd),activeMs:R.activeMs};for(let[N,K]of Object.entries(R.models))U.models[N]=rn((U.models[N]||0)+K);for(let[N,K]of Object.entries(R.providers))U.providers[N]=rn((U.providers[N]||0)+K);o.has(J)||o.set(J,A5());let A=o.get(J);A.usd+=R.usd,A.activeMs+=R.activeMs,A.turns+=R.turns,A.toolCalls+=R.toolCalls;for(let[N,K]of Object.entries(R.models))A.models[N]=(A.models[N]||0)+K;for(let[N,K]of Object.entries(R.providers))A.providers[N]=(A.providers[N]||0)+K;for(let[N,K]of Object.entries(R.provenance))A.provenance[N]=(A.provenance[N]||0)+K;let M=A.byTrack.get(x?.id)||{usd:0,activeMs:0};M.usd+=R.usd,M.activeMs+=R.activeMs,A.byTrack.set(x?.id,M)}(U.usd>0||U.activeMs>0||U.turns>0)&&(U.usd=rn(U.usd),U.dominantCategory=I5(U.categories),s.push(U))}let u=[...o.values()].reduce((y,x)=>y+x.usd,0),d=[...o.values()].reduce((y,x)=>y+x.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),m=[...o.entries()].map(([y,x])=>({category:y,sharePct:f>0?Math.round((p==="usd"?x.usd:x.activeMs)/f*100):0,shareBasis:p,usd:rn(x.usd),activeMs:x.activeMs,turns:x.turns,toolCalls:x.toolCalls,models:wl(x.models),providers:wl(x.providers),provenance:wl(x.provenance),topWorkstreams:[...x.byTrack.entries()].sort((b,I)=>I[1].usd-b[1].usd||I[1].activeMs-b[1].activeMs).slice(0,2).map(([b,I])=>({trackId:b,name:w.get(b),usd:rn(I.usd),activeMs:I.activeMs}))})).sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);s.sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[x,b]of Object.entries(y.provenance))g[x]=(g[x]||0)+b;return{since:r,capturedAt:n,totalUsd:rn(u),activeMs:d,turns:[...o.values()].reduce((y,x)=>y+x.turns,0),bullets:m,workstreams:s,provenance:wl(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:rn(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:wl(l.byShape),top:l.samples.sort((y,x)=>x.usd-y.usd).slice(0,E5)}}}}var E5=25,gR=160,yR=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>gR?`${t.slice(0,gR).trimEnd()}\u2026`:t},_5=10;function bR(e,{thresholdPct:t=_5}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:rn(o),totalUsd:rn(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var I5=e=>{let t=null;for(let[n,r]of Object.entries(e))(!t||r.usd>t.v.usd||r.usd===t.v.usd&&r.activeMs>t.v.activeMs)&&(t={cat:n,v:r});return t?.cat??null},wl=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,rn(n)]));var Is={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function O5(e){let t=String(e||"7d");return t in Is?{key:t,ms:Is[t]}:{key:"7d",ms:Is["7d"]}}function M5(e,t){let n=new Set((t||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...t||[]];for(let o of e?.events||[]){let s=sd(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:e.id,boxId:s.boxId??null,ts:o.at,type:s.type,actor:s.actor,provider:s.provider??null,source:s.source,payload:s.payload})}return r}async function C5(e){if(!e?.cwd)return null;try{let n=(await $5.readFile(R5.join(e.cwd,".bostrat","handoff","latest.md"),"utf8")).match(/^##\s*Objective\s*\n([\s\S]*?)(?:\n##\s|\n*$)/m);return n?n[1].trim().slice(0,1e3):null}catch{return null}}async function ib(e,{window:t="7d",from:n,to:r,now:o=Date.now()}={}){let s=Number(n),a=Number(r),i=Number.isFinite(s)&&s>0,c=i&&Number.isFinite(a)&&a>s?Math.min(a,o):o,{key:l,ms:u}=i?{key:"custom",ms:c-s}:O5(t),d=[];for(let w of e||[]){let m=await q(w),g=M5(w,m);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:w,events:g,brief:await C5(w)})}let p=ab(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:ab(d,{windowMs:Is["7d"],now:o});return{window:l,...p,categorization:bR(f)}}var gl=e=>`$${Number(e||0).toFixed(2)}`,kR=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},_s=(e,t)=>String(e).padEnd(t);function xR(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${gl(e.totalUsd)} \xB7 ${kR(e.activeMs)} active \xB7 ${e.turns} turn(s) \xB7 as of ${new Date(e.capturedAt).toISOString()}`);let n=e.provenance||{};e.totalUsd>0&&Object.keys(n).length&&t.push("labeled by: "+Object.entries(n).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Math.round(i/e.totalUsd*100)}%`).join(" \xB7 ")),t.push(""),t.push("WHERE IT WENT");for(let a of e.bullets||[])t.push(` ${_s(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${_s(a.category,15)} ${_s(gl(a.usd),10)} ${_s(kR(a.activeMs),6)} ${a.turns} turn(s)`+(a.topWorkstreams?.length?` \xB7 ${a.topWorkstreams.map(i=>i.name).join(", ")}`:""));let r=e.gaps||{};r.tracksWithoutEvents&&t.push(`${r.tracksWithoutEvents} track(s) have no attributed events yet`),r.cursorCostUnknown&&t.push("cursor time counted, cost unavailable"),r.unpricedTurns&&t.push(`WARNING: ${r.unpricedTurns} turn(s) unpriced \u2014 total under-reports`);let o=e.categorization;if(o){t.push(""),t.push((o.ok?"categorization ok: ":"CATEGORIZATION ALARM: ")+`${o.sharePct}% of the last 7d uncategorized (threshold ${o.thresholdPct}%) \xB7 ${o.inheritedPct}% inferred from the previous ask`);for(let a of o.problems||[])t.push(`WARNING: ${a}`)}let s=r.uncategorized;if(s){t.push(""),t.push(`UNCATEGORIZED RESIDUE \xB7 ${gl(s.usd)} (${s.sharePct}%) \xB7 ${s.turns} turn(s) \xB7 by shape: `+(Object.entries(s.byShape||{}).filter(([,a])=>a>0).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${gl(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${_s(gl(a.usd),8)} ${_s(a.shape,10)} ${_s(String(a.track||"").slice(0,26),26)} | ${a.text}`);s.top?.length&&(t.push(""),t.push("novel-ask rows are vocabulary the classifier lacks: add a rule in agent/src/task-classifier.js (and a line in test/uncategorized-corpus.test.mjs). follow-up rows had no prior ask on their box."))}return t.join(`
|
|
745
|
+
`)}ir();var Ao=36e5,TR=24*Ao,N5=400,P5=12,$s=e=>Math.round(e*1e4)/1e4;function cb({window:e,from:t,to:n,now:r=Date.now()}={}){let o=Number(t),s=Number(n);if(Number.isFinite(o)&&o>0){let c=Number.isFinite(s)&&s>o?Math.min(s,r):r;return{key:"custom",since:o,until:c}}let a=String(e||"7d")in Is?String(e||"7d"):"7d",i=Is[a];return{key:a,since:i==null?null:r-i,until:r}}var D5=(e,t)=>e!=null&&t-e<=48*Ao?Ao:TR;function vR(e,t){if(t===Ao)return Math.floor(e/Ao)*Ao;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function B5(e,t){if(t===Ao)return e+Ao;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var SR=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),AR=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},j5=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,$s(n)]));async function ER(e,t={}){let n=t.now??Date.now(),r=cb({...t,now:n}),o=r.since==null?TR:D5(r.since,r.until),s=T=>(r.since==null||T>=r.since)&&T<r.until,a=r.since!=null?r.until-r.since:null,i=T=>a!=null&&T>=r.since-a&&T<r.since,c={},l={},u=SR(),d=0,p=0,f=0,w=0,m=0,g=0,y=new Set,x=new Map,b=[],I=[],$=[],P=null;for(let T of e||[]){let U=(await q(T)).filter(A=>A.type==="cost.recorded");if(!U.length){T.archivedAt||$.push(T.name||T.id);continue}let J=[];for(let A of U){let M=A.ts??0;s(M)?J.push(A):i(M)&&(g+=Xt(A).usd)}if(!J.length)continue;let R=Jr(J,{boxLabels:hl(T)});d+=R.totalUsd,p+=R.turns,f+=R.repricedTurns||0,w+=R.asRecordedUsd||0,m+=R.unpricedTurns||0;for(let A of R.unpricedModels||[])y.add(A);AR(u,R.totalTokens);for(let[A,M]of Object.entries(R.byModel))c[A]||={usd:0,events:0,tokens:SR()},c[A].usd=$s(c[A].usd+M.usd),c[A].events+=M.events,AR(c[A].tokens,M.tokens);for(let[A,M]of Object.entries(R.byProvider))l[A]||={usd:0,events:0},l[A].usd=$s(l[A].usd+M.usd),l[A].events+=M.events;for(let A of J){let{usd:M}=Xt(A);if(!M)continue;let N=vR(A.ts??0,o),K=x.get(N)??{t:N,total:0,byProvider:{}};K.total+=M;let Y=A.provider||"unknown";K.byProvider[Y]=(K.byProvider[Y]||0)+M,x.set(N,K),(P==null||N<P)&&(P=N)}b.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:R.totalUsd,turns:R.turns,providers:Object.keys(R.byProvider)});for(let[A,M]of Object.entries(R.byBox))I.push({trackId:T.id,trackName:T.name||T.id,boxId:A,...M})}let F=r.since!=null?vR(r.since,o):P,B=[];for(let T=F,_=0;T!=null&&T<r.until&&_<N5;T=B5(T,o),_++){let U=x.get(T);B.push(U?{t:T,total:$s(U.total),byProvider:j5(U.byProvider)}:{t:T,total:0,byProvider:{}})}return b.sort((T,_)=>_.usd-T.usd),I.sort((T,_)=>_.usd-T.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:oa(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:B,fleet:{totalUsd:$s(d),asRecordedUsd:$s(w),turns:p,repricedTurns:f,unpricedTurns:m,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:b.length,tracksSilentLive:$},prior:a!=null?{totalUsd:$s(g),since:r.since-a,until:r.since}:null,tracks:b.slice(0,50),boxes:I.slice(0,P5)}}Rd();var L5=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),F5=20,U5=40;async function _R(e,t={}){let n=t.now??Date.now(),r=cb({...t,now:n}),o=l=>(r.since==null||l>=r.since)&&l<r.until,s=[],a={},i=0;for(let l of e||[]){let u=await q(l),d=0,p=hl(l);for(let f of u){if(!L5.has(f.type))continue;let w=f.type==="code.rework"?f.payload?.ts??f.ts:f.ts;f.type!=="rework.cause.answered"&&!o(w??0)||(f.type==="code.committed"&&d++,s.push(f.trackId?f:{...f,trackId:l.id}))}d&&i++;for(let f of l.boxes||[])a[`${l.id}/${f.name}`]={trackName:l.name||l.id,label:p[f.name]||f.name}}let c=xT(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:lo,decayEndDays:nw,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,intents:c.intents,noCodeDelta:c.noCodeDelta,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,F5),fixes:c.fixes.slice(0,U5)}}import H5 from"node:fs";import IR from"node:fs/promises";import yl from"node:os";import W5 from"node:path";Gw();ft();var q5=1024*1024,Yp=e=>Math.round(e/q5);async function K5(e){try{let t=await IR.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Yp(r),diskTotalMb:Yp(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function G5(){try{return(await cn()).filter(t=>t.isBostrat).length}catch{return null}}async function V5(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await IR.readdir(W5.join(nl,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function $R({stateDir:e=nl,now:t=Date.now}={}){let n=yl.totalmem(),[r,o,s,a]=await Promise.all([Kd().catch(()=>null),K5(H5.existsSync(e)?e:yl.tmpdir()),G5(),V5()]),i=yl.cpus()?.length||null,c=yl.loadavg()?.[0]??null;return{ts:t(),loadavg1:c!=null?Math.round(c*100)/100:null,cpus:i,cpuPct:c!=null&&i?Math.min(100,Math.round(c/i*100)):null,memUsedMb:r!=null?Yp(n-r):null,memTotalMb:Yp(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(yl.uptime())}}_w();me();Om();xi();ir();me();ir();var z5=864e5;function J5(e,{tolerance:t=.005}={}){if(e.type!=="cost.recorded"||e.source==="vendor")return null;let n=e.payload?.tokens,r=Number(e.payload?.usd)||0;if(!(n?(n.input||0)+(n.output||0)+(n.cacheRead||0)+(n.cacheWrite??n.cacheCreation??0):0)||!r)return null;let s=e.payload?.model||"unknown",a=e.payload?.speed||void 0,i={input:n.input||0,output:n.output||0,cacheRead:n.cacheRead||0,cacheWrite:n.cacheWrite??n.cacheCreation??0},c=Cn(s,i,e.ts,a?{speed:a}:void 0);if(!c)return null;let l=r-c,u=Math.abs(l)>Math.max(c*t,.001);return{model:s,speed:a??null,ts:e.ts,asRecorded:r,expected:c,delta:l,divergent:u}}async function RR(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*z5,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await q(u);for(let p of d){if(!p.ts||p.ts<o)continue;let f=J5(p,{tolerance:n});if(!f)continue;a++;let w=f.speed?`${f.model} (${f.speed})`:f.model,m=s[w]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};m.rows++,m.asRecordedUsd+=f.asRecorded,m.expectedUsd+=f.expected,f.divergent&&(i++,m.divergent++,c.length<10&&c.push({track:u.name||u.id,...f}))}}let l=u=>Math.round(u*1e4)/1e4;for(let u of Object.values(s))u.asRecordedUsd=l(u.asRecordedUsd),u.expectedUsd=l(u.expectedUsd);return{sinceMs:o,days:t,tolerance:n,rows:a,divergent:i,byModel:s,examples:c,ok:i===0}}Aw();gg();td();gt();Zt();import Xa from"node:fs/promises";import Y5 from"node:fs";import kt from"node:path";import X5 from"node:os";import{execFile as Z5}from"node:child_process";import{promisify as Q5}from"node:util";var e6=Q5(Z5),OR=process.env.BOSTRAT_STATE_DIR||kt.join(process.env.HOME||X5.tmpdir(),".bostrat"),Xp=!1,lb=null;async function ub(e,t){let n=await Xa.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await Xa.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await Xa.mkdir(kt.dirname(t),{recursive:!0}),await Xa.copyFile(e,t),!0)}var t6=new Set([".claude",".codex",".cursor",".credentials.json","auth.json",".claude.json","api-token","node.env","certs","integrations.json","gcloud","application_default_credentials.json",".gemini"]);async function Zp(e,t,{skip:n=null}={}){let r=0,o=await Xa.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(t6.has(s.name)||n?.has(s.name))continue;let a=kt.join(e,s.name);s.isDirectory()?r+=await Zp(a,kt.join(t,s.name)):s.isFile()&&(r+=await ub(a,kt.join(t,s.name))?1:0)}return r}async function MR({stateDir:e=OR,dest:t=process.env.BOSTRAT_SYNC_DIR||`${OR}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await Xa.mkdir(t,{recursive:!0});let o=0;o+=await ub(kt.join(e,"tracks.json"),kt.join(t,"tracks.json"))?1:0,o+=await ub(kt.join(e,"events.jsonl"),kt.join(t,"events.jsonl"))?1:0,o+=await Zp(kt.join(e,"events"),kt.join(t,"events")),o+=await Zp(kt.join(e,"memory"),kt.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Zp(kt.join(u.cwd,".bostrat"),kt.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>e6("git",["-C",t,...u]);Y5.existsSync(kt.join(t,".git"))||(await a("init","-q"),await a("config","user.email","agent@bostrat.local"),await a("config","user.name","bostrat state sync")),n&&/^https:\/\/github\.com\//i.test(n)&&(await a("config","--get","credential.useHttpPath").then(()=>!0).catch(()=>!1)||await Pf(t).catch(()=>{}));let i=!1,{stdout:c}=await a("status","--porcelain");c.trim()&&(await a("add","-A"),await a("commit","-q","-m",`state sync ${new Date().toISOString()}`),i=!0);let l=!1;if(n&&(i||Xp))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Xp&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Xp=!1,lb=null}catch(u){Xp=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
|
|
746
|
+
`).slice(-3).join(" | ").slice(0,300);d!==lb&&(lb=d,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${d}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}pg();dn();Ho();ft();di();import{execFile as n6}from"node:child_process";import{promisify as r6}from"node:util";import{randomUUID as o6}from"node:crypto";import s6 from"node:fs";import a6 from"node:os";import i6 from"node:path";var Eo=r6(n6),Qp=e=>new Promise(t=>setTimeout(t,e)),_o=tm,db=process.env.BOSTRAT_USAGE_PROBE_CWD||i6.join(a6.homedir(),".bostrat","usage-probe"),c6=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,l6=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,u6=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,CR=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,To=null,bl=null,kl=null;async function d6(){try{return await Eo(ne,oe("has-session","-t",_o)),!0}catch{return!1}}function p6(){To&&clearTimeout(To),To=setTimeout(()=>f6().catch(()=>{}),c6),To.unref&&To.unref()}async function f6(){To&&(clearTimeout(To),To=null);try{await Eo(ne,oe("kill-session","-t",_o))}catch{}}async function m6(){let e=Date.now()+u6;for(;;){let t=await pb().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await Qp(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await Qp(500)}}async function h6(){if(await d6())return;if(!await Hr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");s6.mkdirSync(db,{recursive:!0}),await Cr(db);let e=o6();await Eo(ne,oe("new-session","-d","-s",_o,"-c",db,"-x","200","-y","60",...Ri()));let t=`${em} --session-id ${e}`;await Eo(ne,oe("send-keys","-t",_o,t,"Enter")),await m6()}async function pb(){let{stdout:e}=await Eo(ne,oe("capture-pane","-t",_o,"-p"));return e}async function w6(){await h6(),await Eo(ne,oe("send-keys","-t",_o,"-l","/usage")),await Eo(ne,oe("send-keys","-t",_o,"Enter"));let e=Date.now()+l6,t="";for(;await Qp(400),t=await pb(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await Qp(900),t=await pb(),await Eo(ne,oe("send-keys","-t",_o,"Escape")).catch(()=>{}),p6(),t}function g6(e){let t=String(e||"").split(`
|
|
747
|
+
`).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,t.length)&&!/^Current\s/i.test(t[c]);c++){let l=t[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=t[c].match(/^Resets\s+(.+)$/i);u&&i===null&&(i=u[1].trim())}return a===null?null:{pct:a,resets:i||null}},r=s=>{let a=t.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return t.forEach((s,a)=>{let i=s.match(/^Current week \(([^)]+)\)$/i);if(!i||/all models/i.test(i[1]))return;let c=n(a);c&&o.push({model:i[1].trim(),...c})}),{session:r(/^Current session\b/i),week:r(/^Current week \(all models\)/i)||r(/^Current week$/i),weekModels:o.length?o:null}}function y6(e){let t=String(e||"").split(`
|
|
748
|
+
`).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function NR({fresh:e=!1}={}){return!e&&bl&&Date.now()-bl.at<CR?bl.data:kl||(kl=(async()=>{try{let t=await w6(),n=g6(t),r={...n,contributors:y6(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return bl={at:Date.now(),data:r},r}catch(t){let n={session:null,week:null,contributors:null,subscription:!1,error:t?.message||String(t),capturedAt:Date.now()};return bl={at:Date.now()-(CR-3e3),data:n},n}finally{kl=null}})(),kl)}var b6=262144;function k6(e){let t=Number(e);if(!Number.isFinite(t)||t<0)return null;let n=Math.floor(t/3600),r=Math.round(t%3600/60);return n>=48?`in ${Math.round(n/24)}d`:n>0?`in ${n}h ${r}m`:`in ${Math.max(1,r)}m`}var x6=new Set([300]),v6=new Set([10080]);function S6(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:x6.has(t)?"session":v6.has(t)?"week":"other"}function A6(e){let t=Number(e);return!Number.isFinite(t)||t<=0?"Window":t%1440===0?`Window \xB7 ${t/1440}d`:t%60===0?`Window \xB7 ${t/60}h`:`Window \xB7 ${t}m`}function T6(e,t,n){if(!e||typeof e!="object")return null;let r=Number(e.used_percent);if(!Number.isFinite(r))return null;let o=null,s=Number(e.resets_at),a=Number(e.resets_in_seconds);return Number.isFinite(s)&&s>0?o=s*1e3:Number.isFinite(a)&&a>=0&&(o=(Number.isFinite(t)?t:n)+a*1e3),{pct:Math.round(r),resets:o!=null?k6((o-n)/1e3):null,resetsAt:o}}var xl=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function E6(e,t=Date.now()){let n=String(e||"").split(`
|
|
749
|
+
`),r=!1;for(let o=n.length-1;o>=0;o--){let s=n[o].trim();if(!s||s[0]!=="{"||!s.includes("token_count"))continue;let a;try{a=JSON.parse(s)}catch{continue}let i=a?.payload;if(i?.type!=="token_count")continue;r=!0;let c=i.rate_limits;if(!c)return xl(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=xl(r);[c.primary,c.secondary].forEach((f,w)=>{let m=T6(f,l,t);if(!m)return;let g=S6(f.window_minutes);g===null&&(g=w===0?"session":"week"),g==="session"&&!u.session?u.session=m:g==="week"&&!u.week?u.week=m:(u.other??=[]).push({label:A6(f.window_minutes),...m})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let p=c.credits;return p&&(p.has_credits||p.unlimited)&&(u.credits={balance:String(p.balance??""),unlimited:!!p.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...xl(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return xl(r)}return xl(r)}async function fb(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Fo(e?.cwd,e?.sessionId);if(!n)return{...t,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await Nt(n.file,b6),o=E6(r);return{...t,session:o.session,week:o.week,other:o.other,planType:o.planType,credits:o.credits,limitReached:o.limitReached,subscription:!!(o.session||o.week||o.other?.length),capturedAt:n.mtimeMs||Date.now()}}catch(n){return{...t,session:null,week:null,subscription:!1,error:n?.message||String(n),capturedAt:Date.now()}}}async function PR(e,{fresh:t=!1}={}){let n=new Set;for(let o of e||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await ef({agent:"claude"},{fresh:t})),n.has("codex")){let o=[],s=[...e||[]].sort((i,c)=>(i.archivedAt?1:0)-(c.archivedAt?1:0)||(c.createdAt||0)-(i.createdAt||0));for(let i of s)for(let c of i.boxes||[])c.agent==="codex"&&o.push({...c,cwd:c.cwd||i.cwd});let a=null;for(let i of o.slice(0,8)){let c=await fb(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await fb(null))}return n.has("cursor")&&r.push(await ef({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function ef(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?fb(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await NR({fresh:t})}}Pr();gt();gt();function _6(e=process.env){return!!(Ne(e)&&e.BOSTRAT_PLANE_TOKEN)}var I6=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),tf=(e,t)=>Object.assign(new Error(e),{status:t});async function DR(e,t){if(!_6(t))throw tf("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Ne(t)}${e}`,{headers:I6(t)})}catch(o){throw tf(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw tf(r?.error||`plane replied ${n.status}`,n.status);return r}async function BR(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await DR(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function jR(e,{env:t=process.env}={}){if(!e)throw tf("message id required",400);return(await DR(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}ic();gd();function mb(e){let t=e.split(".");if(t.length!==4)return null;let n=0;for(let r of t){let o=Number(r);if(!Number.isInteger(o)||o<0||o>255)return null;n=n*256+o}return n>>>0}function $6(e){let[t,n]=e.split("/"),r=mb(t);if(r==null)return null;let o=n==null?32:Number(n);if(!Number.isInteger(o)||o<0||o>32)return null;let s=o===0?0:4294967295<<32-o>>>0;return a=>(a&s)===(r&s)}function LR(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map($6).filter(Boolean)}function R6(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function FR(e){let t=LR(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:R6,allowed(r){if(n)return!0;let o=mb((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function UR(e,t){let n=LR(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=mb(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import HR from"node:crypto";import nf from"node:fs";import O6 from"node:path";function WR(e=process.env,{stateDir:t=nl,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=O6.join(t,"api-token");try{let a=nf.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=HR.randomBytes(32).toString("base64url");try{nf.mkdirSync(t,{recursive:!0}),nf.writeFileSync(o,s+`
|
|
750
|
+
`,{mode:384}),nf.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function vl(e){let t=e?.socket?.remoteAddress||"";if(!t)return!1;let n=t.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function qR(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:HR.timingSafeEqual(n,r)}function KR(e,t=null){let n=e?.headers?.["x-bostrat-token"];if(typeof n=="string"&&n.trim())return n.trim();let r=e?.headers?.authorization||"",o=/^Bearer\s+(.+)$/i.exec(r)?.[1];if(o)return o.trim();try{return(t??new URL(e.url,"http://node")).searchParams.get("token")||""}catch{return""}}var M6=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/,/^\/api\/tracks\/adopt\b/,/^\/api\/tracks\/[^/]+\/transfer-out\b/,/^\/api\/node\/self-update\b/,/^\/api\/changelog\/(publish|retract)\b/,/^\/api\/tracks\/[^/]+\/loop-(update|delete)-offer\b/],C6=e=>M6.some(t=>t.test(e));function GR({token:e,enforce:t=!0,log:n=console}={}){return function(o,s,a){let i=o.path||o.url||"";if(!i.startsWith("/api"))return a();let c=KR(o);return qR(c,e)?a():C6(i)?(n.log?.(`[perimeter] refused ${o.method} ${i} \u2014 sensitive route requires the node API token`),s.status(401).json({error:"this route requires the node API token"})):!t||vl(o)?a():(n.log?.(`[perimeter] refused ${o.method} ${i} from ${o.socket?.remoteAddress||"?"} \u2014 no node API token`),s.status(401).json({error:"unauthorized"}))}}function VR(e,t,{enforce:n=!0}={}){return!n||qR(KR(e),t)?!0:vl(e)}In();Wd();Wd();import N6 from"node:http";import P6 from"node:net";function rf(e){if(!e)return null;let t=String(e).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(t)||t.includes(":"))return null;let n=t.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function of(e){let t=rf(e.headers.host);return t?{slug:t,view:Fw(t)}:null}var D6=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),B6=e=>{let t=D6(e.name);return`<!doctype html><meta charset="utf-8">
|
|
750
751
|
<meta http-equiv="refresh" content="3">
|
|
751
752
|
<title>${t} \u2014 starting</title>
|
|
752
753
|
<body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
|
|
753
754
|
<div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
|
|
754
|
-
<p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function
|
|
755
|
+
<p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function zR(e){if(!/[?&]token=/.test(e))return e;try{let t=new URL(e,"http://view");return t.searchParams.delete("token"),t.pathname+t.search}catch{return e}}function JR(e,t,n){let r=of(e);if(!r)return n();let{view:o,slug:s}=r;if(!o)return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return t.statusCode=503,t.setHeader("content-type","text/html"),t.end(B6(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie,delete a["x-bostrat-token"];let i=N6.request({host:"127.0.0.1",port:o.port,method:e.method,path:zR(e.url),headers:a},c=>{t.writeHead(c.statusCode||502,c.headers),c.pipe(t)});i.on("error",()=>{t.headersSent?t.destroy():(t.statusCode=502,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),e.pipe(i),e.on("aborted",()=>i.destroy())}function YR(e,t,n){let r=of(e);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return t.write(`HTTP/1.1 404 Not Found\r
|
|
755
756
|
\r
|
|
756
757
|
bostrat: no live view "${s}"\r
|
|
757
|
-
`),t.destroy(),!0;let a=
|
|
758
|
+
`),t.destroy(),!0;let a=P6.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${zR(e.url)} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||l==="x-bostrat-token"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
|
|
758
759
|
`)+`\r
|
|
759
760
|
\r
|
|
760
|
-
`),n?.length&&a.write(n),t.pipe(a),a.pipe(t)}),i=()=>{a.destroy(),t.destroy()};return a.on("error",i),t.on("error",i),!0}function PR(e,t){let n=typeof t=="string"?{host:t}:t||{},r=n["x-bostrat-view-base"];return typeof r=="string"&&r?`${n["x-forwarded-proto"]==="https"?"https":"http"}://${e.slug}.${r.replace(/:\d+$/,"")}/`:`http://${e.slug}.${g6(n.host)}/`}function g6(e){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let t=String(e||"").replace(/:\d+$/,"").toLowerCase();if(!t||!t.includes(".")||/^[\d.]+$/.test(t))return"bostrat.globopi";let n=t.split(".");return Qp(t)&&Dw(n[0])?n.slice(1).join("."):t}$a();Yw();Vd();Fu();fe();import DR from"node:os";import{randomUUID as lb}from"node:crypto";var y6=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||DR.hostname(),nodeName:e.BOSTRAT_NODE_NAME||DR.hostname()});var BR=32768,jR=120,LR=1e3,FR=new Set(["claude","codex","cursor"]),b6=new Set(["off","transition","nag"]),k6=[[0,59],[0,23],[1,31],[1,12],[0,6]];function x6(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=k6[r];return String(n).split(",").every(a=>{if(!a)return!1;let[i,c]=a.split("/");if(c!==void 0&&!(Number.isInteger(Number(c))&&Number(c)>=1))return!1;if(i==="*")return!0;let[l,u]=i.includes("-")?i.split("-").map(Number):[Number(i),Number(i)];return Number.isInteger(l)&&Number.isInteger(u)&&l>=o&&u<=s&&l<=u})})}var An=e=>String(e??"").trim(),$s={name(e){let t=An(e);if(!t)throw new Error("a loop needs a name");if(t.length>jR)throw new Error(`name is too long (${t.length}); cap is ${jR}`);return t},schedule(e){let t=An(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!x6(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=An(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>BR)throw new Error(`prompt is too long (${t.length} chars); cap is ${BR}`);return t},expectation(e){let t=An(e)||null;if(t&&t.length>LR)throw new Error(`expectation is too long (${t.length}); cap is ${LR}`);return t},notify(e){let t=An(e)||"off";if(!b6.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=An(typeof t=="string"?t:t?.provider)||"claude";if(!FR.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...FR].join(", ")}`);let r=typeof t=="object"&&t&&An(t.model)||null;return r?{provider:n,model:r}:{provider:n}},enabled(e){if(typeof e=="boolean")return e;if(e==="true"||e==="false")return e==="true";throw new Error(`enabled must be true or false, got "${e}"`)}};function v6(e,t){let n=e&&typeof e=="object"?e:{},r=$s.name(n.name),o=$s.schedule(n.schedule),s=$s.prompt(n.prompt),a=$s.expectation(n.expectation),i=$s.notify(n.notify),c=$s.assignment(n.assignment),l=An(t?.workspace?.repo)||An(t?.workspace?.base)||null;if(!l)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:u,nodeName:d}=y6();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function HR(e,t){let n=v6(t,e),r=lb();return await C({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function WR(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await q({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await C({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await C({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var cb=["name","schedule","prompt","expectation","notify","assignment","enabled"],S6=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function qR(e){let t=Array.isArray(e.runs)?e.runs:[],n=t[t.length-1]??null;return{definitionUpdatedAt:Number(e.definitionUpdatedAt??e.updatedAt)||null,name:e.name??"",schedule:e.schedule??"",prompt:e.prompt??"",expectation:e.expectation??null,notify:e.notify??"off",assignment:e.assignment&&typeof e.assignment=="object"?e.assignment:{provider:String(e.assignment||"claude")},enabled:e.enabled!==!1,repo:e.repo??null,nodeId:e.nodeId??null,nodeName:e.nodeName??null,trackId:e.trackId??null,nextFireAt:Number.isFinite(Number(e.nextFireAt))?Number(e.nextFireAt):null,createdAt:Number(e.createdAt)||null,runCount:t.length,lastRun:n?{firedAt:Number(n.firedAt)||null,outcome:n.outcome??(n.error?"errored":null)}:null}}function KR(e,t){let n=An(t);if(!n)throw new Error("which loop? give an id or a name \u2014 see `bostrat-loop ls`");let r=e.find(a=>a.id===n)||e.find(a=>a.name===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(a=>String(a.id).toLowerCase().startsWith(o)||String(a.name).toLowerCase().startsWith(o));if(s.length===1)return s[0];throw s.length>1?new Error(`"${n}" matches ${s.length} loops: ${s.map(a=>`${a.name} (${a.id})`).join(", ")} \u2014 use the id`):new Error(`no loop matching "${n}" \u2014 use \`bostrat-loop ls\``)}function A6(e,t){let n=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!n)throw new Error("a patch must be a JSON object of the fields to change");let r=Object.keys(n).filter(a=>!cb.includes(a));if(r.length){let a=r.filter(i=>["repo","nodeId","cwd","userId","owner","id","trackId"].includes(i));throw a.length?new Error(`a proposal can't change ${a.join(", ")} \u2014 retargeting a loop is a Loops-tab edit (scope D5)`):new Error(`unknown field(s) ${r.join(", ")} \u2014 patchable: ${cb.join(", ")}`)}let o={};for(let a of cb){if(!(a in n))continue;let i=$s[a](n[a]);(a==="assignment"?S6(i,t.assignment):i===(t[a]??(a==="notify"?"off":a==="enabled"?!0:null)))||(o[a]=i)}let s=Object.keys(o);if(!s.length)throw new Error("nothing would change \u2014 the patch equals the loop's current definition");return{patch:o,changed:s}}async function GR(e,t,n){let r=qR(t),{patch:o,changed:s}=A6(n,r),a=lb(),i={ts:Date.now(),proposalId:a,loopId:String(t.id),name:r.name,base:r,patch:o,changed:s,selfEdit:!!(r.trackId&&r.trackId===e.id)};return await C({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var UR=600;async function VR(e,t,n){let r=An(n);if(!r)throw new Error('a delete proposal needs a reason \u2014 bostrat-loop propose-delete <loop> --reason "<why this loop should go>"');if(r.length>UR)throw new Error(`reason is too long (${r.length}); cap is ${UR}`);let o=qR(t),s=lb(),a={ts:Date.now(),proposalId:s,loopId:String(t.id),name:o.name,base:o,reason:r,selfEdit:!!(o.trackId&&o.trackId===e.id)};return await C({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var zR=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await q({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type===t&&a.payload?.proposalId===n);if(!o)throw new Error("unknown proposal");let s=t.replace(".offered",".answered");if(r.some(a=>a.type===s&&a.payload?.proposalId===n))throw new Error("proposal already answered");return o};async function JR(e,t,n,{nextFireAt:r=null}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let s=(await zR(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await C(a,{type:"loop.updated",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:s.loopId,name:s.patch?.name??s.name,changed:s.changed??Object.keys(s.patch||{}),nextFireAt:Number.isFinite(Number(r))?Number(r):null}}),await C(a,{type:"loop.update.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:s.loopId}}),{proposalId:t,action:n,loopId:s.loopId}}async function YR(e,t,n){if(!["delete","pause","keep","moved"].includes(n))throw new Error("action must be one of delete | pause | keep | moved");let o=(await zR(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await C(s,{type:n==="delete"?"loop.deleted":"loop.paused",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:o.loopId,name:o.name,trackId:o.base?.trackId??null}}),await C(s,{type:"loop.delete.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:o.loopId}}),{proposalId:t,action:n,loopId:o.loopId}}fe();import{randomUUID as T6}from"node:crypto";var pb=20,E6=300,ub=120,XR=120,ZR=2e3,tf=new Set(["build","ops","debt","spike"]),QR=new Set(["active","done","abandoned"]),fb=new Set(["circuit.create","circuit.update","circuit.delete"]),_6=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),kl=new Set([...fb,..._6]),I6=["name","description","status","type"],$6=["person","startDate","endDate","estUsd"],R6=["person","label","startDate","endDate"],O6=/^\d{4}-\d{2}-\d{2}$/,Vt=e=>String(e??"").trim(),hb=e=>typeof e=="string"&&e.startsWith("@"),nO=864e5;function rO(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*nO).toISOString().slice(0,10)}function M6(e){return new Date(Date.parse(`${rO(e)}T00:00:00Z`)+6*nO).toISOString().slice(0,10)}var eO=(e,t)=>{let n=Vt(e);if(!O6.test(n))throw new Error(`${t} must be YYYY-MM-DD, got "${e??""}"`);if(!Number.isFinite(Date.parse(`${n}T00:00:00Z`)))throw new Error(`${t} "${n}" is not a real date`);return n};function C6(e,t){let n=eO(e,"startDate"),r=eO(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=rO(n),s=M6(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var tO=e=>{if(e==null||e==="")return null;let t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`estUsd must be a non-negative number, got "${e}"`);return t},_o=(e,t,n)=>{let r=Vt(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function db(e,t){let n=Vt(t);if(!n)throw new Error("a circuit name or id is required");if(hb(n))return{ref:n,id:null,name:n.slice(1)};let r=e.find(i=>i.id===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(i=>String(i.name).toLowerCase()===o);if(s.length===1)return s[0];if(s.length>1)throw new Error(`"${n}" names ${s.length} circuits \u2014 use an id (bostrat-circuit ls)`);let a=e.filter(i=>String(i.name).toLowerCase().includes(o)).slice(0,5);throw new Error(a.length?`no circuit named "${n}" \u2014 near matches: ${a.map(i=>`${i.name} (${i.id})`).join(", ")}`:`no circuit named "${n}" \u2014 propose a circuit.create op if it should exist (bostrat-circuit ls lists yours)`)}function N6(e,t){let n=Vt(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||hb(n))return{ref:n,id:null,label:n==="me"?"you":n.slice(1)};let r=e.find(a=>a.personId===n);if(r)return{...r,id:r.personId};let o=n.toLowerCase(),s=e.filter(a=>String(a.label).toLowerCase()===o);if(s.length===1)return{...s[0],id:s[0].personId};throw s.length>1?new Error(`"${n}" names ${s.length} roadmap rows \u2014 use a person id`):new Error(e.length?`no roadmap row for "${n}" \u2014 rows: ${e.map(a=>`${a.label} (${a.personId})`).join(", ")}, or propose a person.create op`:`no roadmap rows yet \u2014 use "me", or propose a person.create op for "${n}"`)}function P6(e,t,{allow:n=kl}={}){let r=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!r)throw new Error("a plan must be a JSON object with an `ops` array");let o=Array.isArray(r.ops)?r.ops:null;if(!o?.length)throw new Error("a plan needs at least one op in `ops`");if(o.length>pb)throw new Error(`too many ops (${o.length}); cap is ${pb} \u2014 propose one intent at a time`);let s=Array.isArray(t?.circuits)?t.circuits:[],a=Array.isArray(t?.people)?t.people:[],i=Array.isArray(t?.slots)?t.slots:[],c=Array.isArray(t?.reservations)?t.reservations:[],l={circuits:{},slots:{},reservations:{}},u={},d=new Set,p=!1,f=!1,w=b=>{b.id&&(l.circuits[b.id]={name:b.name,status:b.status,type:b.type??"build",updatedAt:b.updatedAt??null},u[b.id]=b.name)},h=b=>{b.id&&(u[b.id]=b.label)},g=(b,I)=>{let R=Vt(b);if(!R)return null;if(d.has(R))throw new Error(`ref "${R}" is used by two ops \u2014 each ref names one thing`);return d.add(R),u[`@${R}`]=I,R},y=o.map((b,I)=>{let R=b&&typeof b=="object"?b:{},N=Vt(R.op),D=`op ${I+1}`;if(!kl.has(N))throw new Error(`${D}: unknown op "${N}" \u2014 one of ${[...kl].join(", ")}`);if(!n.has(N))throw new Error(`${D}: "${N}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let j=M=>{throw new Error(`${D} (${N}): ${M}`)},T=M=>{let S=R.set&&typeof R.set=="object"&&!Array.isArray(R.set)?R.set:null;S||j("needs a `set` object naming the fields to change");let _=Object.keys(S).filter(H=>!M.includes(H));return _.length&&j(`unknown field(s) ${_.join(", ")} \u2014 settable: ${M.join(", ")}`),Object.keys(S).length||j("`set` names no fields"),S},$=M=>{let{startDate:S,endDate:_,snapped:H}=C6(M.startDate,M.endDate);return H&&(p=!0),{startDate:S,endDate:_,snapped:H}},F=M=>{let S=N6(a,M);return Vt(M)==="me"&&(f=!0),h(S),{key:S.id??Vt(M),label:S.label}},J=(M,S,_,H,K)=>{let X=Vt(M);X||j(`needs a ${H} id`);let pe=S.find(Oe=>Oe[_]===X);return pe||j(`no ${H} "${X}" \u2014 see \`bostrat-roadmap ls\``),K[X]={...pe},pe};switch(N){case"circuit.create":{let M=_o(R.name,XR,"name");M||j("a circuit needs a name");let S=Vt(R.type)||"build";tf.has(S)||j(`bad type "${S}" (${[...tf].join(" | ")})`);let _=s.find(K=>String(K.name).toLowerCase()===M.toLowerCase());_&&j(`a circuit named "${_.name}" already exists (${_.id}) \u2014 update it instead of making a twin`);let H=g(R.ref,M);return{op:N,...H?{ref:H}:{},name:M,description:_o(R.description,ZR,"description"),type:S}}case"circuit.update":{let M=db(s,R.circuit);M.id||j("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(M);let S=T(I6),_={};if(S.name!==void 0){let H=_o(S.name,XR,"name");H||j("name can't be blank"),H!==M.name&&(_.name=H)}return S.description!==void 0&&(_.description=_o(S.description,ZR,"description")),S.status!==void 0&&(QR.has(S.status)||j(`bad status "${S.status}" (${[...QR].join(" | ")})`),S.status!==M.status&&(_.status=S.status)),S.type!==void 0&&(tf.has(S.type)||j(`bad type "${S.type}" (${[...tf].join(" | ")})`),S.type!==(M.type??"build")&&(_.type=S.type)),Object.keys(_).length||j("nothing would change \u2014 the set equals the circuit's current values"),{op:N,circuit:M.id,name:M.name,set:_}}case"circuit.delete":{let M=db(s,R.circuit);M.id||j("can't delete a circuit created in the same plan"),w(M);let S=o.some((_,H)=>H<I&&Vt(_?.op)==="circuit.update"&&_?.set?.status&&_.set.status!=="active"&&Vt(_?.circuit)===Vt(R.circuit));return M.status==="active"&&!S&&j(`\u201C${M.name}\u201D is active \u2014 an active circuit can't be deleted; propose a circuit.update to done/abandoned first (both can ride one card)`),{op:N,circuit:M.id,name:M.name,status:M.status}}case"person.create":{let M=_o(R.label,ub,"label");M||j("a person row needs a label");let S=a.find(H=>String(H.label).toLowerCase()===M.toLowerCase());S&&j(`a roadmap row labelled "${S.label}" already exists (${S.personId})`);let _=g(R.ref,M);return{op:N,..._?{ref:_}:{},label:M}}case"slot.create":{let M=db(s,R.circuit);w(M);let S=F(R.person),_=$(R);return{op:N,circuit:M.id??M.ref,circuitName:M.name,person:S.key,personLabel:S.label,..._,estUsd:tO(R.estUsd)}}case"slot.update":{let M=J(R.slot,i,"slotId","slot",l.slots),S=T($6),_={};if(S.person!==void 0){let K=F(S.person);_.person=K.key,_.personLabel=K.label}if(S.startDate!==void 0||S.endDate!==void 0){let K=$({startDate:S.startDate??M.startDate,endDate:S.endDate??M.endDate});K.startDate!==M.startDate&&(_.startDate=K.startDate),K.endDate!==M.endDate&&(_.endDate=K.endDate)}S.estUsd!==void 0&&(_.estUsd=tO(S.estUsd)),Object.keys(_).length||j("nothing would change");let H=s.find(K=>K.id===M.circuitId);return{op:N,slot:M.slotId,circuitName:H?.name??null,set:_}}case"slot.delete":{let M=J(R.slot,i,"slotId","slot",l.slots),S=s.find(_=>_.id===M.circuitId);return{op:N,slot:M.slotId,circuitName:S?.name??null,startDate:M.startDate,endDate:M.endDate}}case"reservation.create":{let M=F(R.person),S=_o(R.label,ub,"label");return S||j("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:N,person:M.key,personLabel:M.label,label:S,...$(R)}}case"reservation.update":{let M=J(R.reservation,c,"reservationId","reservation",l.reservations),S=T(R6),_={};if(S.person!==void 0){let H=F(S.person);_.person=H.key,_.personLabel=H.label}if(S.label!==void 0){let H=_o(S.label,ub,"label");H||j("label can't be blank"),H!==M.label&&(_.label=H)}if(S.startDate!==void 0||S.endDate!==void 0){let H=$({startDate:S.startDate??M.startDate,endDate:S.endDate??M.endDate});H.startDate!==M.startDate&&(_.startDate=H.startDate),H.endDate!==M.endDate&&(_.endDate=H.endDate)}return Object.keys(_).length||j("nothing would change"),{op:N,reservation:M.reservationId,label:M.label,set:_}}case"reservation.delete":{let M=J(R.reservation,c,"reservationId","reservation",l.reservations);return{op:N,reservation:M.reservationId,label:M.label,startDate:M.startDate,endDate:M.endDate}}default:return j("unhandled op")}});y.forEach((b,I)=>{for(let R of[b.circuit,b.person,b.set?.person])if(hb(R)&&!d.has(String(R).slice(1)))throw new Error(`op ${I+1} (${b.op}): unknown ref "${R}" \u2014 no earlier op in this plan creates it`)});let k=a.some(b=>b.kind==="user"&&b.userId);return{why:_o(r.why,E6,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:f&&!k}}async function oO(e,t,n,r={}){let o=P6(t,n,r),s=T6(),a={ts:Date.now(),proposalId:s,...o};return await C({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var D6=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await q({id:e.id,cwd:e.cwd}),r=n.find(o=>o.type==="planning.change.offered"&&o.payload?.proposalId===t);if(!r)throw new Error("unknown proposal");if(n.some(o=>o.type==="planning.change.answered"&&o.payload?.proposalId===t))throw new Error("proposal already answered");return r};async function sO(e,t,n,{results:r=[]}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let o=await D6(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await C(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,pb+1):[]}}),await C(s,{type:"planning.change.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,ops:a.ops?.length??0}}),{proposalId:t,action:n}}Cd();fe();jr();fe();Dn();Vd();var aO=10,iO=200,B6=120,j6=24,lO=/^\d{4}-\d{2}-\d{2}$/;function mb(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var L6=(e=Date.now())=>new Date(e).toISOString().slice(0,10),vt=(e,t="i")=>new RegExp(e,t),F6=[{re:vt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:vt("\\bSPC\\b",""),reason:"business (SPC)"},{re:vt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:vt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:vt("\\bReplicas\\b",""),reason:"competitor research"},{re:vt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:vt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:vt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],U6=[vt("\\bSPC\\b",""),vt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),vt("competitor|cloudcli|\\bkiro\\b"),vt("\\bReplicas\\b",""),vt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),vt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),vt("(^|[^\\w&])#\\d+\\b"),vt("\\btrack/[\\w.-]+")];function H6({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of F6)if(o.test(n)||o.test(r))return s;return null}function cO(e){let t=String(e||"");for(let n of U6){let r=n.exec(t);if(r)return r[0].trim()}return null}function uO(e,t=Date.now()){if(!e)return t-24*36e5;let n=/^(\d+)\s*([hd])$/.exec(String(e).trim());if(n)return t-Number(n[1])*(n[2]==="h"?36e5:24*36e5);let r=Date.parse(e);if(!Number.isNaN(r))return r;throw new Error(`unparseable since "${e}" \u2014 use 24h, 7d, or an ISO date`)}var W6=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function q6(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Mc(e);if(t.length)throw new Error(`changelog entry appears to contain a secret VALUE (${t.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of e.split(`
|
|
761
|
-
`)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,B6)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${j6}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=W6.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let d=cO(i);if(d)throw new Error(`bullet ${r.length+1} mentions "${d}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>iO)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${iO}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=cO(n);if(o)throw new Error(`headline mentions "${o}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items; rewrite it and re-publish.`)}if(!r.length)throw new Error("no `- ` bullets found \u2014 an entry is a bullet list, optionally under a `# headline`");if(r.length>aO)throw new Error(`${r.length} bullets \u2014 over the ${aO}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function K6(e,{repos:t=mb()}={}){let n=new Set(t);return(await hn()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=e&&n.has(r.repo)).sort((r,o)=>(r.resolvedAt??0)-(o.resolvedAt??0)).map(r=>({repo:r.repo,number:r.number,title:r.title||null,url:r.url||null,headRef:r.headRef||null,mergedAt:r.resolvedAt??null,excluded:H6({title:r.title,headRef:r.headRef})}))}async function dO(e,t){let n=await K6(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function pO(e,{md:t,day:n=null}){let r=q6(t),o=n==null||n===""?L6():String(n);if(!lO.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await C({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function fO(e,{day:t}){let n=String(t||"");if(!lO.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await C({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}ss();Dn();is();fe();ss();yt();mr();Dn();sc();$d();hd();dc();Zt();import{execFile as rK}from"node:child_process";import{promisify as oK}from"node:util";var G6=new Set(["pull_request","check_suite","workflow_run","push"]),V6=/^[^/\s]+\/[^/\s]+$/,z6=500,wb=new Set,gb=[],nf=new Map,on={hourStart:0,byEvent:{},duplicates:0,rejected:0};function yb(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==on.hourStart&&(on.hourStart=r,on.byEvent={},on.duplicates=0,on.rejected=0),t==="accepted"?on.byEvent[n]=(on.byEvent[n]||0)+1:on[t]+=1}function J6(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!G6.has(e.event)||typeof e.repo!="string"||!V6.test(e.repo))return null;let t=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(r=>Number.isInteger(r)&&r>0),n=Number.isInteger(e.number)&&e.number>0?e.number:t[0]??null;return{forge:"github",deliveryId:typeof e.deliveryId=="string"&&e.deliveryId?e.deliveryId.slice(0,128):null,event:e.event,action:typeof e.action=="string"?e.action.slice(0,64):null,repo:e.repo,number:n,numbers:n&&!t.includes(n)?[n,...t]:t,headSha:typeof e.headSha=="string"?e.headSha.slice(0,64):null,headRef:typeof e.headRef=="string"?e.headRef.slice(0,256):null,baseRef:typeof e.baseRef=="string"?e.baseRef.slice(0,256):null,merged:typeof e.merged=="boolean"?e.merged:null,draft:typeof e.draft=="boolean"?e.draft:null,conclusion:typeof e.conclusion=="string"?e.conclusion.slice(0,64):null,deleted:e.deleted===!0,senderLogin:typeof e.senderLogin=="string"?e.senderLogin.slice(0,128):null,ts:Number.isFinite(e.ts)?e.ts:null}}function hO(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=J6(e);if(!o)return yb(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(wb.has(o.deliveryId))return yb(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(wb.add(o.deliveryId),gb.push(o.deliveryId);gb.length>z6;)wb.delete(gb.shift())}let s=o.repo.toLowerCase(),a=nf.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,nf.set(s,a),yb(t,"accepted",o.event),r.log?.(`[github-event] ${o.event}${o.action?` ${o.action}`:""} ${o.repo}${o.number?` #${o.number}`:o.headRef?` ${o.headRef}`:""}${o.conclusion?` (${o.conclusion})`:""}${o.deliveryId?` delivery ${o.deliveryId.slice(0,8)}`:""}`);try{n?.(o)}catch(i){r.error?.("[github-event] onAccept failed:",i?.message||i)}return{ok:!0,duplicate:!1,envelope:o}}function Y6(e,t=Date.now()){let n=nf.get(String(e||"").toLowerCase());return n?{covered:!0,lastDeliveryAt:n.lastDeliveryAt,ageMs:t-n.lastDeliveryAt,count:n.count}:{covered:!1,lastDeliveryAt:null,ageMs:null,count:0}}var mO=1440*6e4;function bb(e,t=Date.now()){let n=Y6(e,t);return n.covered&&n.ageMs<mO}function wO(e=Date.now()){let t={};for(let[n,r]of nf)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<mO};return{hourStart:on.hourStart,byEvent:{...on.byEvent},duplicates:on.duplicates,rejected:on.rejected,repos:t}}fe();Dn();Cr();mr();Zt();function gO(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function X6(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var Z6=new Set(["merged","closed","lost"]);function Q6(e,t){if(!e?.blocked)return null;let n=gO(t);if(e.blocked==="red")return t.checks.failed===0&&t.checks.total>0?{change:"ci-fixed",reason:"red"}:null;if(e.blocked==="conflict")return t.mergeable==="MERGEABLE"&&n!=="red"?{change:"reconciled",reason:"conflict"}:null;if(e.blocked==="behind"){let r=t.headSha??null;return n===null&&r&&e.sha&&r!==e.sha?{change:"reconciled",reason:"behind"}:null}return null}function eK(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function tK(e,t,n,r,o){return(await q(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function nK(e,t,n){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function rf(e,t={}){let{now:n=Date.now(),slugOf:r=$e,lookup:o=pt,note:s=xA,tracks:a=async()=>(await we()).filter(d=>!je(d)),asked:i=tK,emitChange:c=nK}=t,l=[],u=null;for(let d of e??[]){if(!d?.prs?.length)continue;let p=await r(d.path).catch(()=>null);if(p)for(let f of d.prs)try{if(!X6(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||Z6.has(w.state))continue;let{prev:h}=await s(p,f.number,{blocked:gO(f),sha:f.headSha??null,at:n});if(!h)continue;let g=Q6(h,f);if(!g||eK(w,g.change))continue;u??=new Map((await a()).map(I=>[I.id,I]));let y=u.get(w.trackId);if(!y)continue;let k=f.headSha??null;if(await i(y,g.change,f.number,k,h.at||0))continue;let b={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:k,delegated:!1,reason:g.reason};g.change==="ci-fixed"?b.passed=f.checks.passed:b.base=f.baseRefName||null,await c(y,g.change,b),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var vb=oK(rK),EO=3e4,sK=30*6e4,aK=EO,iK=10*6e4,cK=10080*6e4,lK=60*6e4,yO=8,_O=1440*6e4,uK=3,IO="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",xb=60*6e4,dK=15*6e4,pK=9e4,fK=1440*6e4,xl=new Map,vl=new Map,hK=360*6e4,mK=e=>e.reduce((t,n)=>({misses:Math.max(t.misses,n.brokerRefused?.misses||0),until:Math.max(t.until,n.brokerRefused?.until||0)}),{misses:0,until:0}),wK=/could not resolve|not found|no pull requests?/i,gK=e=>wK.test(String(e?.message||e||""));function yK(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<xb)}var bO={fast:aK,slow:iK,decay:lK};function kO(e,t,n=bb){return $O(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<sK||yK(e,t))?"fast":t-(e.firstSeen||0)>cK?"decay":"slow"}function Al(e,t,n,r){let o=e.lanes?.get(ae(t.repo,t.number))||{};return fd({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function bK(e,t){ur("watch");try{let{stdout:n}=await vb("gh",["pr","view",String(t),"--repo",e,"--json",IO],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await En({slug:e})}});return JSON.parse(n||"null")}catch(n){throw oo(n)&&so(n),n}}async function kK(e){ur("watch");try{let{stdout:t}=await vb("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",IO],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await En({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw oo(t)&&so(t),t}}async function xK(){let e=new Map;for(let t of await we().catch(()=>[]))e.set(t.id,t);return e}async function vK(e,t){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await Id(e,t).catch(()=>{})}async function SK(e,t){let n=await os(e);return n?ga(n,t):null}async function AK(e,t,n){let r=await os(e);if(!r)throw new Error(`no local checkout for ${e}`);return ya(r,t,{method:n})}async function TK(e,t){let n=await os(e);if(!n)throw new Error(`no local checkout for ${e}`);return cc(n,t)}async function EK(e,t){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function Ya(e,t,n,r,o){if(!await r.disarm(e.repo,e.number).catch(()=>null))return;let a=n.get(e.trackId);a&&await r.emitDisarmed(a,{number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo,reason:o}).catch(()=>{})}var _K=10*6e4;async function IK(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>_O){await Ya(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(e.repo,e.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await Ya(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Ya(e,o,t,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(e.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<_K)return;await Ya(e,o,t,n,o.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(o.checks.pending>0||o.mergeable==="UNKNOWN"||o.mergeStateStatus==="UNKNOWN"||o.isDraft)return;let s=await n.lookup(e.repo,e.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(e.repo,e.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await Ya(e,o,t,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(e.repo,e.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await Ya(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await RO(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Xa(e,t,n){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function $K(e,t){try{return await vb("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Sl(e,t,n,r=()=>!0){return(await q(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Za=(e,t)=>({number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo});function $O(e,t,{grace:n=pK}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=fK}async function RK(e,t,n,r){let o=r.now??Date.now();if(!$O(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||je(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??as)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await q(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??cr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??cr)(e.repo,e.number).catch(()=>null)?(await Xa(s,"opened",{...Za(e,t),announcedBy:"watch"}).catch(()=>{}),console.log(`[pr-watch] announced passive link ${e.repo}#${e.number} \u2192 track ${s.id} (no active door claimed it)`),!0):!1}async function OK(e,t,n,r){let o=r.now??Date.now(),s=t.headRefOid||null,a=n.get(e.trackId)||null;if(s&&(e.ciFix?.headSha&&s!==e.ciFix.headSha&&await sd(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await id(e.repo,e.number,{headSha:s}).catch(()=>{})),s&&s!==e.lastHeadSha){let i=!e.lastHeadSha,c=!!(e.ciFix||e.reconcile||e.ciFixAwait||e.reconcileAwait),l=!!e.baseFoldAt&&o-e.baseFoldAt<dK;await kA(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await bA(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Sl(a,"pushed",e.number,d=>d.payload?.sha===s)&&await Xa(a,"pushed",{...Za(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>xb)await ad(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await ad(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Al(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await Sl(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Xa(a,"ci-fixed",{...Za(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await ad(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>xb)await cd(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await cd(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Al(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Sl(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Xa(a,"reconciled",{...Za(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await cd(e.repo,e.number).catch(()=>{})}}}}async function MK(e,t,n,r){let o=Al(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Sl(s,"closed",e.number)&&await Xa(s,"closed",{...Za(e,t),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(e.repo,e.number,"closed").catch(()=>{}),await r.mark(e.repo,e.number,"closed").catch(()=>{})}async function xO(e,t,n){Al(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Sl(r,"lost",e.number)&&await Xa(r,"lost",Za(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function RO(e,t,n,r,o={}){let s=Al(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await q(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.followupsIfMerged(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function vO(e={}){let{now:t=Date.now(),auth:n=Fm,view:r=bK,list:o=kK,links:s=AA,trackMap:a=xK,emitMerged:i=vK,mark:c=no,archiveIfArmed:l=fr,notifyIfArmed:u=hr,notifyIfResolved:d=wp,followupsIfMerged:p=ys,batchThreshold:f=uK,detail:w=SK,merge:h=AK,updateBranch:g=TK,lookup:y=pt,disarm:k=oc,emitDisarmed:b=EK,localHasCommit:I=$K,claim:R=cr,midTurn:N=as,only:D=null,wantDetail:j=null,covered:T=bb,verdicts:$=null,tokenFor:F=z=>Bs(z),noteRefusal:J=gA,clearRefusal:M=yA}=e;if(!(await n().catch(()=>null))?.authenticated||dd()>0)return 0;let _=await s().catch(()=>[]),H=zA(_),K=z=>{try{return!!j?.(z)}catch{return!1}},X=D?_.filter(z=>{try{return D(z)}catch{return!1}}):_.filter(z=>t-(xl.get(ae(z.repo,z.number))||0)>=bO[kO(z,t,T)]);if(!X.length)return 0;let pe=Date.now(),Oe=new Map,Me=new Map;for(let z of[...X].sort(lc)){let ge=D?"event":kO(z,t,T);Oe.set(ae(z.repo,z.number),{lane:ge,intervalMs:bO[ge]??null}),xl.set(ae(z.repo,z.number),t),Me.has(z.repo)||Me.set(z.repo,[]),Me.get(z.repo).push(z)}let Q=await a().catch(()=>new Map),qe=new Map,Ae=(z,ge)=>{let Ge=ae(z,ge);if(!qe.has(Ge)){let O=Promise.resolve().then(()=>w(z,ge));O.catch(()=>{}),qe.set(Ge,O)}return qe.get(Ge)},Z=$??((z,ge)=>rf([{path:z,prs:[ge]}],{now:t,slugOf:async()=>z,tracks:async()=>[...Q.values()].filter(Ge=>!je(Ge))}).catch(()=>{})),me={now:t,lanes:Oe,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Ae,merge:h,updateBranch:g,lookup:y,disarm:k,emitDisarmed:b,localHasCommit:I,claim:R,midTurn:N};for(let[z,ge]of Me){let Ge=mK(ge);if(Ge.until>t)continue;let O=!1;try{if(await F(z),Ge.misses)for(let oe of ge)await M(oe.repo,oe.number).catch(()=>{})}catch(oe){O=fk(oe)}if(O){let oe=Ge.misses+1;if(oe>=yO){console.log(`[pr-watch] ${z}: not granted ${oe}\xD7 \u2014 retiring ${ge.length} link(s) as lost`);for(let ye of ge){await xO(ye,Q,me);let Fe=ae(ye.repo,ye.number);vl.delete(Fe),xl.delete(Fe)}}else for(let ye of ge)await J(ye.repo,ye.number,{misses:oe,until:t+hK}).catch(()=>{});continue}let Y,Le=new Set,Qe=oe=>oe.ciFixAwait||oe.reconcileAwait||K(oe)?!0:!oe.autoMerge||oe.trackId&&H.get(oe.trackId)!==ae(oe.repo,oe.number)?!1:t-(oe.autoMerge.armedAt||0)<=_O;if(ge.length>f)Y=await o(z).catch(()=>null);else{Y=new Map;for(let oe of ge){if(Qe(oe)){let ye=await Ae(z,oe.number).catch(()=>null);if(ye?.state){Y.set(Number(oe.number),{number:Number(oe.number),url:ye.url,title:ye.title,headRefName:ye.headRefName,headRefOid:ye.headSha??null,state:ye.state,mergedAt:ye.mergedAt??null,closedAt:ye.closedAt??null});continue}}try{let ye=await r(z,oe.number);ye?.number!=null&&Y.set(Number(ye.number),ye)}catch(ye){gK(ye)&&Le.add(ae(oe.repo,oe.number))}}}if(Y)for(let oe of ge){let ye=ae(oe.repo,oe.number),Fe=Y.get(Number(oe.number));if(!Fe){if(Le.has(ye)){let jt=(vl.get(ye)||0)+1;vl.set(ye,jt),jt>=yO&&(await xO(oe,Q,me),vl.delete(ye),xl.delete(ye))}continue}if(vl.delete(ye),Fe.state==="MERGED"||Fe.state==="CLOSED")Fe.state==="MERGED"?await RO(oe,Fe,Q,me):await MK(oe,Fe,Q,me),xl.delete(ye);else{await RK(oe,Fe,Q,me).catch(()=>{}),await OK(oe,Fe,Q,me).catch(()=>{});let jt=!oe.trackId||H.get(oe.trackId)===ye;oe.autoMerge&&jt&&await IK(oe,Q,me).catch(()=>{});try{if(K(oe)&&!qe.has(ye)&&Ae(oe.repo,oe.number),qe.has(ye)){let x=await qe.get(ye).catch(()=>null);x?.checks&&await Z(oe.repo,x)}}catch{}}}}let Te={};for(let{lane:z}of Oe.values())Te[z]=(Te[z]||0)+1;return console.log(`[pr-watch] probed ${X.length} link(s) (${Object.entries(Te).map(([z,ge])=>`${z} ${ge}`).join(", ")}) in ${Date.now()-pe}ms`),X.length}function SO(e,t){return!e||!t?!1:e.all?!0:String(t.repo||"").toLowerCase()!==e.repo?!1:e.numbers?.length?e.numbers.includes(Number(t.number)):e.event==="push"?!!e.branch&&t.headRef===e.branch||!!t.autoMerge:e.branch?t.headRef===e.branch:!0}var kb=!1,of=!1,sf=[],AO=Promise.resolve();async function CK(){for(;of||sf.length;){if(of){of=!1;try{await vO()}catch{}continue}let e=sf;sf=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await vO({...n,only:r=>t.some(o=>SO(o,r)),wantDetail:r=>t.some(o=>o.detail&&SO(o,r))})}catch{}}}function af(e,t){return e===null?of=!0:sf.push({spec:e,deps:t}),kb||(kb=!0,AO=CK().finally(()=>{kb=!1})),AO}function OO(e,t=void 0){let n=String(e?.repo||"").toLowerCase();if(!/^[^/\s]+\/[^/\s]+$/.test(n))return Promise.resolve();let r=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(o=>Number.isInteger(o)&&o>0);return af({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var NK=6e4,TO=0;function MO(e=void 0){let t=e?.now??Date.now();return t-TO<NK?Promise.resolve():(TO=t,af({all:!0},e))}function CO(){af(null),setInterval(()=>af(null),EO)}ss();Rd();Ic();mr();Zt();var PK=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function DK({tracks:e=we,reconcile:t=Ud}={}){for(let n of(await e().catch(()=>[])).filter(r=>!je(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function NO(e,t={}){let{invalidate:n=en,probe:r=OO,poke:o=OT,reconcileOpened:s=DK}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&PK.has(e.action)){if(e.action==="opened"||e.action==="reopened"){a.poked=!0,a.reconciled=!0;try{o()}catch{}s()}a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event}}else(e.event==="check_suite"||e.event==="workflow_run")&&e.action==="completed"?a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(a.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return a.probe&&r(a.probe),a}ht();fe();mr();Zt();import{randomUUID as BK}from"node:crypto";var jK=2e4,PO=3,Qa=new Map,Sb=new Set;async function DO(e,t,n){let r=await n(e).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===t?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function LK(e={}){let{sessions:t=null,tracks:n=null,append:r=C,read:o=q,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await cn(),i=n??await we()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(je(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(f=>f.name===u.leadBox);if(!d||d.agent!=="claude"||d.state!=="live")continue;let p=c.get(d.name);if(p)if(l.add(d.name),p.alternateOn){let f=(Qa.get(d.name)||0)+1;Qa.set(d.name,f),f===PO&&(Sb.add(d.name),await DO(u,d.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:BK(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(Qa.get(d.name)||0)>=PO;if(Qa.delete(d.name),f||!Sb.has(d.name)){Sb.add(d.name);let w=await DO(u,d.name,o);w&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:w,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Qa.keys()])l.has(u)||Qa.delete(u)}var Tl=null,Ab=!1;function BO(){return Tl?()=>{}:(Tl=setInterval(()=>{Ab||(Ab=!0,LK().catch(()=>{}).finally(()=>{Ab=!1}))},jK),Tl.unref?.(),()=>{clearInterval(Tl),Tl=null})}es();Ic();fe();ss();is();es();mc();import{randomUUID as FK}from"node:crypto";async function UK(){let e=await Promise.resolve().then(()=>(mr(),MI));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var Tb={listRepoPrs:Bn,readEvents:q,appendEvent:C,sayDeps:UK,currentBranch:ao};async function HK(e,t=Tb,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??ao)(e.workspace?.kind==="multi"?null:e.cwd).catch(()=>null)||e?.workspace?.branch;if(!r)return null;let o;try{o=await t.listRepoPrs(e.cwd,{caller:"pr-exists"})}catch{return null}let s=(o||[]).find(a=>a.headRefName===r);return s?{number:s.number,url:s.url??null,title:s.title??null}:null}async function Eb(e,t,{actions:n,notify:r=!1}={},o=Tb){let s=t?.payload||{};if(!Array.isArray(n)||!n.includes("pr")||s.toPr||Array.isArray(s.repos)&&s.repos.length||!s.branch)return null;let a=await HK(e,o,{branch:s.branch});if(!a)return null;let i={id:e.id,cwd:e.cwd};await o.appendEvent(i,{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:s.offerId,action:"pr-exists",actions:n,...r?{notify:!0}:{},existingPr:{number:a.number}}});let c=FK();return await o.appendEvent(i,{type:"pr.exists.offered",actor:"system",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:c,srcOfferId:s.offerId??null,branch:s.branch,base:s.base??null,pr:a,actions:n,...r?{notify:!0}:{},offeredRebase:Array.isArray(s.offered)&&s.offered.includes("rebase")}}),{offerId:c,pr:a}}async function _b(e,{offerId:t,choice:n}={},r=Tb){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return co(`prx:${e.id}:${t}`,()=>WK(e,{offerId:t,choice:n},r))}async function WK(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=to.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,fa(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:u}=await r.sayDeps();l=i,c=await u(e.id,oA(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}mc();import $r from"node:fs/promises";import ei from"node:path";import qO from"node:os";import jO from"node:fs/promises";import cf from"node:path";import{execFile as qK}from"node:child_process";import{promisify as KK}from"node:util";import{fileURLToPath as GK}from"node:url";var VK=KK(qK),FO=cf.dirname(GK(import.meta.url)),zK=cf.resolve(FO,"..","..","client","dist"),JK="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",YK=new Map([...JK].map((e,t)=>[e,t]));function XK(e){let t=[],n=0,r=0;for(let o of e){let s=YK.get(o);if(s===void 0)return t;n+=(s&31)<<r,s&32?r+=5:(t.push(n&1?-(n>>>1):n>>>1),n=0,r=0)}return t}function ZK(e){let t=[],n=0,r=0,o=0;for(let s of e.split(";")){let a=[],i=0;if(s)for(let c of s.split(",")){let l=XK(c);l.length!==0&&(i+=l[0],l.length>=4&&(n+=l[1],r+=l[2],o+=l[3],a.push([i,n,r,o])))}t.push(a)}return t}function QK(e,t){if(!e||e.length===0||e[0][0]>t)return null;let n=0,r=e.length-1;for(;n<r;){let o=n+r+1>>1;e[o][0]<=t?n=o:r=o-1}return e[n]}var LO=new Map;async function eG(e){let t;try{t=await jO.stat(e)}catch{return null}let n=LO.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await jO.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:ZK(r.mappings||"")};return LO.set(e,o),o}catch{return null}}var Ib=null;function tG(){return Ib||(Ib=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):VK("git",["rev-parse","--short","HEAD"],{cwd:cf.resolve(FO,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Ib}var nG=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function rG(e,{distDir:t=zK}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(nG)){let[a,i,c,l]=s,u=await eG(cf.join(t,"assets",`${i}.map`)),d=u?QK(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),d&&u.sources[d[1]]){let p=u.sources[d[1]].replace(/^(\.\.\/)+/,"");n.push(`${p}:${d[2]+1}:${d[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function UO(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await tG();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await rG(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var oG=()=>process.env.BOSTRAT_STATE_DIR||ei.join(process.env.HOME||qO.tmpdir(),".bostrat"),Io=()=>ei.join(oG(),"telemetry"),KO=()=>ei.join(Io(),".relay-offsets.json"),sG=50,aG=14,iG=3e4,HO=500,zt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function cG(e,t){if(!e||typeof e!="object")return null;let n=zt(e.name,64);if(!n)return null;let r=Number.isFinite(e.ts)?e.ts:t,o={name:n,ts:Math.abs(r-t)<168*3600*1e3?r:t,receivedAt:t,anonId:zt(e.anonId,64),sessionId:zt(e.sessionId,64),userId:zt(e.userId,64),release:zt(e.release,64),appVersion:zt(e.appVersion,32),route:zt(e.route,128),deviceClass:e.deviceClass==="phone"||e.deviceClass==="desktop"?e.deviceClass:""};return e.props&&typeof e.props=="object"&&!Array.isArray(e.props)&&(JSON.stringify(e.props).length<=8192?o.props=e.props:o.props={clamped:!0}),e.error&&typeof e.error=="object"&&(o.error={kind:zt(e.error.kind,256),message:zt(e.error.message,8192),stack:zt(e.error.stack,32768),fingerprint:zt(e.error.fingerprint,64)}),Array.isArray(e.breadcrumbs)&&(o.breadcrumbs=e.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:zt(s?.n,64),r:zt(s?.r,128)}))),o}var GO=e=>new Date(e).toISOString().slice(0,10),WO=0;async function VO(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,sG):[]).map(s=>cG(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await UO(s);await $r.mkdir(Io(),{recursive:!0});let o=ei.join(Io(),`${GO(t)}.ndjson`);return await $r.appendFile(o,r.map(s=>JSON.stringify(s)+`
|
|
762
|
-
`).join(""),"utf8"),t-
|
|
763
|
-
`).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=HO){let f=d.slice(p,p+HO).map(h=>uG(h)),w=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:f})}).catch(()=>null);if(!w||!w.ok)return{sent:o,disabled:!1};o+=f.length}r[s]=i+l+1,await YO(r)}return{sent:o,disabled:!1}}var $b=null,Rb=!1;function XO(){$b||($b=setInterval(async()=>{if(!Rb){Rb=!0;try{await dG()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Rb=!1}}},iG),$b.unref?.())}import df from"node:fs/promises";import nM from"node:path";import pG from"node:os";var rM=()=>process.env.BOSTRAT_STATE_DIR||nM.join(process.env.HOME||pG.tmpdir(),".bostrat"),oM=()=>nM.join(rM(),"dictation-glossary.json"),fG=100,hG=500,mG=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],pf=null,Ob=null,Mb=Promise.resolve();function ZO(){let e={},t=Date.now();for(let n of mG)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function sM(){return pf||(Ob??=df.readFile(oM(),"utf8").then(e=>JSON.parse(e)?.terms??ZO()).catch(()=>ZO()).then(e=>pf=e).finally(()=>Ob=null),Ob)}async function QO(){let e=JSON.stringify({terms:pf},null,2),t=oM(),n=`${t}.${process.pid}.tmp`;await df.mkdir(rM(),{recursive:!0}),await df.writeFile(n,e),await df.rename(n,t)}function wG(){return Mb=Mb.then(QO,QO),Mb.catch(()=>{})}async function Cb(){return Object.values(await sM()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var gG=e=>Math.max(1,Math.ceil(e.length/4));async function yG(){let e=[],t=0;for(let{term:n}of await Cb()){let r=gG(n);if(!(t+r>hG)&&(e.push(n),t+=r,e.length>=fG))break}return e}async function bG(e,t){let n=await sM(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var eM=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),uf=e=>e.toLowerCase();function tM(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function aM(e,t){let n=eM(e),r=eM(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let d=s-1;d>=0;d--)a[u][d]=uf(n[u])===uf(r[d])?a[u+1][d+1]+1:Math.max(a[u+1][d],a[u][d+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)uf(n[c])===uf(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(tM(r[l])&&i.add(r[l]),l++);for(;l<s;l++)tM(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await bG(u,"learned");return await wG(),[...i]}var El=null;function kG(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.err_code||n?.error_code||n?.category||"";return e===402||/PAYMENT_REQUIRED/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"Deepgram credits are exhausted \u2014 dictation is down until you top up at console.deepgram.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"Deepgram rejected the API key (revoked, or missing ASR scope) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"transcription_failed",persistent:!1,message:`Deepgram error ${e}: ${t.slice(0,300)}`}}async function iM(){if(!El)return null;let e=await sl();if(!e||e.apiKey.slice(-6)!==El.keyTail)return null;let{keyTail:t,...n}=El;return n}async function cM(e,t){let n=await sl();if(!n){let i=new Error("Deepgram is not configured \u2014 add deepgram.apiKey to ~/.bostrat/integrations.json");throw i.status=503,i.code="not_configured",i}let r=new URL("https://api.deepgram.com/v1/listen");r.searchParams.set("model","nova-3"),r.searchParams.set("smart_format","true");for(let i of await yG())r.searchParams.append("keyterm",i);let o=await fetch(r,{method:"POST",headers:{Authorization:`Token ${n.apiKey}`,"Content-Type":t||"application/octet-stream"},body:e});if(!o.ok){let i=await o.text().catch(()=>""),c=kG(o.status,i);c.persistent&&(El={code:c.code,message:c.message,at:Date.now(),keyTail:n.apiKey.slice(-6)});let l=new Error(c.message);throw l.status=c.status,l.code=c.code,l}return El=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}fe();var Nb={"gpt-realtime-2.1":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime":{textIn:4,textInCached:.4,textOut:16,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2.1-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20},"gpt-realtime-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20}};function xG(e){if(!e)return null;let t=String(e).trim();if(Nb[t])return t;let n=null;for(let r of Object.keys(Nb))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function vG(e,t={}){let n=Nb[xG(e)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(t[o])||0)*n[o];return r/1e6}function SG(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.error?.code||n?.error?.type||"";return e===429&&/insufficient_quota/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"The OpenAI account is out of credit \u2014 voice chat is down until you top up at platform.openai.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"OpenAI rejected the API key (revoked, or missing Realtime access) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"mint_failed",persistent:!1,message:`OpenAI realtime session mint failed (${e}): ${t.slice(0,300)}`}}var _l=null;async function AG(){if(!_l)return null;let e=await jp();if(!e||e.apiKey.slice(-6)!==_l.keyTail)return null;let{keyTail:t,...n}=_l;return n}async function TG(e){let t=await fetch("https://api.openai.com/v1/realtime/client_secrets",{method:"POST",headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({session:{type:"realtime",model:e.model,audio:{output:{voice:e.voice}}}})});if(!t.ok){let o=await t.text().catch(()=>""),s=SG(t.status,o);s.persistent&&(_l={code:s.code,message:s.message,at:Date.now(),keyTail:e.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}_l=null;let n=await t.json(),r=n?.value??n?.client_secret?.value;if(!r){let o=new Error("OpenAI returned no client secret");throw o.status=502,o.code="mint_failed",o}return{clientSecret:{value:r,expiresAt:n?.expires_at??n?.client_secret?.expires_at??null}}}var EG={openai:TG};async function lM(){let e=await jp();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await AG()}:{configured:!1}}async function uM(){let e=await jp();if(!e){let n=new Error("Voice chat is not configured \u2014 add openai.apiKey to ~/.bostrat/integrations.json");throw n.status=503,n.code="not_configured",n}let t=await EG[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function dM(e,{model:t,usage:n={},seconds:r}={}){let o=c=>Math.max(0,Math.round(Number(c)||0)),s={textIn:o(n.textIn),textInCached:o(n.textInCached),textOut:o(n.textOut),audioIn:o(n.audioIn),audioInCached:o(n.audioInCached),audioOut:o(n.audioOut)},a=vG(t,s),i=await C(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}Zt();pA(async()=>new Set((await we()).map(e=>e.id)));var bM=Ie.dirname(IG(import.meta.url)),pM=Number(process.env.PORT)||3362,ff=wy(process.env),kM=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,ti=AR(process.env.BOSTRAT_ALLOW_IPS),Lb=TR(process.env.BOSTRAT_VIEW_FRONT_CIDRS,ef),Fb=_R(),xM=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",E=Jt();E.disable("x-powered-by");E.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),Qp(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});E.use((e,t,n)=>{if(bl(e)||ti.allowed(ti.clientIp(e))||Lb.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});E.use(CR);E.use(RR({token:Fb,enforce:xM}));E.use("/api/mocks",Jt.json({limit:"1mb"}));E.use("/api/mocks",Jt.raw({type:"image/png",limit:"24mb"}));E.use("/api/mocks",Jt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));E.use("/api/runbooks",Jt.json({limit:"1mb"}));E.use("/api/tracks/adopt",Jt.json({limit:"1mb"}));E.use("/api/telemetry",Jt.json({limit:"256kb"}));E.use("/api/hook",Jt.json({limit:"2mb"}));E.use("/api/dictation",Jt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));E.use("/api/tracks/:id/upload",Jt.raw({type:()=>!0,limit:"25mb"}));E.use(Jt.json({limit:"64kb"}));E.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:Ft,hostTmuxAlive:await Fr(),autoTriggerPct:kM,plane:ni?ni.status():null})});E.get("/api/sessions",async(e,t)=>{t.json({sessions:await cn()})});E.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await $n(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});E.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});if(!await ke(n))return t.status(404).json({error:"session not found"});try{await Mt(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});E.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});let r=await ke(n);if(!r)return t.status(404).json({error:"session not found"});let o=await Ci(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});E.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});try{let r=await mv(n);t.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){t.status(409).json({error:r?.message||String(r)})}});E.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Nu(n);if(!r)return t.json({running:!1});t.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var fM=10;async function vM(){let e=await we(),[t,n]=await Promise.all([LI(e),UI(e)]);return{tracks:e,views:await Pw(),queuedOf:r=>hs(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}E.get("/api/idle-guard",async(e,t)=>{try{t.json(py(await vM()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var sn=ks(),NG=t$({kind:sn}),$l=null,It=()=>$l&&["auto","prompt","off"].includes($l)?$l:NG,jb=null,PG=rl.has(sn),SM=async({to:e,from:t})=>!PG||Op(await ol())?!1:(Ol.arm({to:e,from:t,kind:sn}),!0);async function DG(e){let t=It();$l=e??null;let n=It();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){Ol.cancel();return}jb&&await SM(jb)}}var AM=(()=>{try{return CG(import.meta.url)("../package.json").version||null}catch{return null}})(),Ol=r$({isBusy:async()=>py(await vM()).busy,onStuck:({to:e,from:t})=>zn({current:t,latest:e,installKind:sn,policy:It(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?zn({current:t,latest:e,installKind:sn,policy:It(),status:"updating",reason:"auto"}):zn({current:t,latest:e,installKind:sn,policy:It(),status:"failed",error:n?.reason})).catch(()=>{})});E.get("/api/node/self-update",async(e,t)=>{t.json({installKind:sn,policy:It(),policySource:$l?"plane":"node",current:AM,status:await ol(),armed:Ol.armed})});E.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await Mp({to:n,kind:sn,reason:"manual"});if(r.ok)return Ol.cancel(),zn({current:r.from,latest:n,installKind:sn,policy:It(),status:"updating",reason:"manual"}).catch(()=>{}),t.json({ok:!0,...r});t.status(409).json({ok:!1,error:r.reason,status:r.status??null})});async function TM(){try{let e=await n$();e&&await zn({current:e.from,latest:e.to,installKind:e.kind||sn,policy:It(),status:e.status,error:e.error,reason:e.reason}),await Ig({current:AM,installKind:sn,policy:It()})}catch{}}TM();setInterval(TM,3e4).unref();E.get("/api/tracks",async(e,t)=>{let n=(await we()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>fM){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,fM).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Vc,agentAvailability:await cp(),tickets:await $$()})});E.get("/api/cost",async(e,t)=>{try{let n=await we();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Zy(n);if(r.cursorUsage=bw(),e.query.format==="text")return t.type("text/plain").send(eR(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/roundup",async(e,t)=>{try{let n=await eb(await we(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(sR(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/spend",async(e,t)=>{try{let n=await uR(await we(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=bw(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=tc(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/caps",(e,t)=>{t.json(tc())});E.post("/api/usage/caps",async(e,t)=>{try{t.json(await Xu(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await bR(await we(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await tk(e.get(Qn),{byToken:zc,legacy:()=>yc(e.body?.session_id,e.body?.cwd)});if(n==="refused")return ci("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return ci("legacy-denied",{reason:"tokenless-denied",hook:e.body?.hook_event_name}),t.status(401).json({ok:!1,error:"tokenless hook ingest is disabled (BOSTRAT_HOOK_LEGACY_DENY)"});n==="token"&&e.body?.session_id&&r.box?.sessionId&&e.body.session_id!==r.box.sessionId&&ci("mismatch",{track:r.track.id,box:r.box.name}),ci(n,{track:r?.track?.id,hook:e.body?.hook_event_name,...n==="legacy"?{reason:"tokenless-body-resolved",deny_with:"BOSTRAT_HOOK_LEGACY_DENY=1"}:{}});let o=await X$(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&Zl(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await zc(e.get(Qn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await mT(n.track,n.box)).join(`
|
|
761
|
+
`),n?.length&&a.write(n),t.pipe(a),a.pipe(t)}),i=()=>{a.destroy(),t.destroy()};return a.on("error",i),t.on("error",i),!0}function hb(e){let t=typeof e=="string"?{host:e}:e||{},n=t["x-bostrat-view-base"];if(typeof n=="string"&&n)return{proto:t["x-forwarded-proto"]==="https"?"https":"http",host:n.replace(/:\d+$/,"").toLowerCase(),source:"header"};let r=jy();if(r)return{proto:"https",host:r,source:"learned"};let o=Ly();if(o)return{...o,source:"env"};let s=String(t.host||"").replace(/:\d+$/,"").toLowerCase();if(!s||!s.includes(".")||/^[\d.]+$/.test(s))return null;let a=s.split(".");return{proto:"http",host:rf(s)&&Fw(a[0])?a.slice(1).join("."):s,source:"request"}}function XR(e,t){return Wp(hb(t),e.slug)}Ra();eg();Yd();Wu();me();import ZR from"node:os";import{randomUUID as gb}from"node:crypto";var j6=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||ZR.hostname(),nodeName:e.BOSTRAT_NODE_NAME||ZR.hostname()});var QR=32768,eO=120,tO=1e3,nO=new Set(["claude","codex","cursor"]),L6=new Set(["off","transition","nag"]),F6=[[0,59],[0,23],[1,31],[1,12],[0,6]];function U6(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=F6[r];return String(n).split(",").every(a=>{if(!a)return!1;let[i,c]=a.split("/");if(c!==void 0&&!(Number.isInteger(Number(c))&&Number(c)>=1))return!1;if(i==="*")return!0;let[l,u]=i.includes("-")?i.split("-").map(Number):[Number(i),Number(i)];return Number.isInteger(l)&&Number.isInteger(u)&&l>=o&&u<=s&&l<=u})})}var An=e=>String(e??"").trim(),Rs={name(e){let t=An(e);if(!t)throw new Error("a loop needs a name");if(t.length>eO)throw new Error(`name is too long (${t.length}); cap is ${eO}`);return t},schedule(e){let t=An(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!U6(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=An(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>QR)throw new Error(`prompt is too long (${t.length} chars); cap is ${QR}`);return t},expectation(e){let t=An(e)||null;if(t&&t.length>tO)throw new Error(`expectation is too long (${t.length}); cap is ${tO}`);return t},notify(e){let t=An(e)||"off";if(!L6.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=An(typeof t=="string"?t:t?.provider)||"claude";if(!nO.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...nO].join(", ")}`);let r=typeof t=="object"&&t&&An(t.model)||null;return r?{provider:n,model:r}:{provider:n}},enabled(e){if(typeof e=="boolean")return e;if(e==="true"||e==="false")return e==="true";throw new Error(`enabled must be true or false, got "${e}"`)}};function H6(e,t){let n=e&&typeof e=="object"?e:{},r=Rs.name(n.name),o=Rs.schedule(n.schedule),s=Rs.prompt(n.prompt),a=Rs.expectation(n.expectation),i=Rs.notify(n.notify),c=Rs.assignment(n.assignment),l=An(t?.workspace?.repo)||An(t?.workspace?.base)||null;if(!l)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:u,nodeName:d}=j6();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function oO(e,t){let n=H6(t,e),r=gb();return await C({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function sO(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await q({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await C({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await C({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var wb=["name","schedule","prompt","expectation","notify","assignment","enabled"],W6=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function aO(e){let t=Array.isArray(e.runs)?e.runs:[],n=t[t.length-1]??null;return{definitionUpdatedAt:Number(e.definitionUpdatedAt??e.updatedAt)||null,name:e.name??"",schedule:e.schedule??"",prompt:e.prompt??"",expectation:e.expectation??null,notify:e.notify??"off",assignment:e.assignment&&typeof e.assignment=="object"?e.assignment:{provider:String(e.assignment||"claude")},enabled:e.enabled!==!1,repo:e.repo??null,nodeId:e.nodeId??null,nodeName:e.nodeName??null,trackId:e.trackId??null,nextFireAt:Number.isFinite(Number(e.nextFireAt))?Number(e.nextFireAt):null,createdAt:Number(e.createdAt)||null,runCount:t.length,lastRun:n?{firedAt:Number(n.firedAt)||null,outcome:n.outcome??(n.error?"errored":null)}:null}}function iO(e,t){let n=An(t);if(!n)throw new Error("which loop? give an id or a name \u2014 see `bostrat-loop ls`");let r=e.find(a=>a.id===n)||e.find(a=>a.name===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(a=>String(a.id).toLowerCase().startsWith(o)||String(a.name).toLowerCase().startsWith(o));if(s.length===1)return s[0];throw s.length>1?new Error(`"${n}" matches ${s.length} loops: ${s.map(a=>`${a.name} (${a.id})`).join(", ")} \u2014 use the id`):new Error(`no loop matching "${n}" \u2014 use \`bostrat-loop ls\``)}function q6(e,t){let n=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!n)throw new Error("a patch must be a JSON object of the fields to change");let r=Object.keys(n).filter(a=>!wb.includes(a));if(r.length){let a=r.filter(i=>["repo","nodeId","cwd","userId","owner","id","trackId"].includes(i));throw a.length?new Error(`a proposal can't change ${a.join(", ")} \u2014 retargeting a loop is a Loops-tab edit (scope D5)`):new Error(`unknown field(s) ${r.join(", ")} \u2014 patchable: ${wb.join(", ")}`)}let o={};for(let a of wb){if(!(a in n))continue;let i=Rs[a](n[a]);(a==="assignment"?W6(i,t.assignment):i===(t[a]??(a==="notify"?"off":a==="enabled"?!0:null)))||(o[a]=i)}let s=Object.keys(o);if(!s.length)throw new Error("nothing would change \u2014 the patch equals the loop's current definition");return{patch:o,changed:s}}async function cO(e,t,n){let r=aO(t),{patch:o,changed:s}=q6(n,r),a=gb(),i={ts:Date.now(),proposalId:a,loopId:String(t.id),name:r.name,base:r,patch:o,changed:s,selfEdit:!!(r.trackId&&r.trackId===e.id)};return await C({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var rO=600;async function lO(e,t,n){let r=An(n);if(!r)throw new Error('a delete proposal needs a reason \u2014 bostrat-loop propose-delete <loop> --reason "<why this loop should go>"');if(r.length>rO)throw new Error(`reason is too long (${r.length}); cap is ${rO}`);let o=aO(t),s=gb(),a={ts:Date.now(),proposalId:s,loopId:String(t.id),name:o.name,base:o,reason:r,selfEdit:!!(o.trackId&&o.trackId===e.id)};return await C({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var uO=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await q({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type===t&&a.payload?.proposalId===n);if(!o)throw new Error("unknown proposal");let s=t.replace(".offered",".answered");if(r.some(a=>a.type===s&&a.payload?.proposalId===n))throw new Error("proposal already answered");return o};async function dO(e,t,n,{nextFireAt:r=null}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let s=(await uO(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await C(a,{type:"loop.updated",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:s.loopId,name:s.patch?.name??s.name,changed:s.changed??Object.keys(s.patch||{}),nextFireAt:Number.isFinite(Number(r))?Number(r):null}}),await C(a,{type:"loop.update.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:s.loopId}}),{proposalId:t,action:n,loopId:s.loopId}}async function pO(e,t,n){if(!["delete","pause","keep","moved"].includes(n))throw new Error("action must be one of delete | pause | keep | moved");let o=(await uO(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await C(s,{type:n==="delete"?"loop.deleted":"loop.paused",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:o.loopId,name:o.name,trackId:o.base?.trackId??null}}),await C(s,{type:"loop.delete.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:o.loopId}}),{proposalId:t,action:n,loopId:o.loopId}}me();import{randomUUID as K6}from"node:crypto";var kb=20,G6=300,yb=120,fO=120,mO=2e3,sf=new Set(["build","ops","debt","spike"]),hO=new Set(["active","done","abandoned"]),xb=new Set(["circuit.create","circuit.update","circuit.delete"]),V6=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),Sl=new Set([...xb,...V6]),z6=["name","description","status","type"],J6=["person","startDate","endDate","estUsd"],Y6=["person","label","startDate","endDate"],X6=/^\d{4}-\d{2}-\d{2}$/,Vt=e=>String(e??"").trim(),vb=e=>typeof e=="string"&&e.startsWith("@"),yO=864e5;function bO(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*yO).toISOString().slice(0,10)}function Z6(e){return new Date(Date.parse(`${bO(e)}T00:00:00Z`)+6*yO).toISOString().slice(0,10)}var wO=(e,t)=>{let n=Vt(e);if(!X6.test(n))throw new Error(`${t} must be YYYY-MM-DD, got "${e??""}"`);if(!Number.isFinite(Date.parse(`${n}T00:00:00Z`)))throw new Error(`${t} "${n}" is not a real date`);return n};function Q6(e,t){let n=wO(e,"startDate"),r=wO(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=bO(n),s=Z6(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var gO=e=>{if(e==null||e==="")return null;let t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`estUsd must be a non-negative number, got "${e}"`);return t},Io=(e,t,n)=>{let r=Vt(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function bb(e,t){let n=Vt(t);if(!n)throw new Error("a circuit name or id is required");if(vb(n))return{ref:n,id:null,name:n.slice(1)};let r=e.find(i=>i.id===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(i=>String(i.name).toLowerCase()===o);if(s.length===1)return s[0];if(s.length>1)throw new Error(`"${n}" names ${s.length} circuits \u2014 use an id (bostrat-circuit ls)`);let a=e.filter(i=>String(i.name).toLowerCase().includes(o)).slice(0,5);throw new Error(a.length?`no circuit named "${n}" \u2014 near matches: ${a.map(i=>`${i.name} (${i.id})`).join(", ")}`:`no circuit named "${n}" \u2014 propose a circuit.create op if it should exist (bostrat-circuit ls lists yours)`)}function eK(e,t){let n=Vt(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||vb(n))return{ref:n,id:null,label:n==="me"?"you":n.slice(1)};let r=e.find(a=>a.personId===n);if(r)return{...r,id:r.personId};let o=n.toLowerCase(),s=e.filter(a=>String(a.label).toLowerCase()===o);if(s.length===1)return{...s[0],id:s[0].personId};throw s.length>1?new Error(`"${n}" names ${s.length} roadmap rows \u2014 use a person id`):new Error(e.length?`no roadmap row for "${n}" \u2014 rows: ${e.map(a=>`${a.label} (${a.personId})`).join(", ")}, or propose a person.create op`:`no roadmap rows yet \u2014 use "me", or propose a person.create op for "${n}"`)}function tK(e,t,{allow:n=Sl}={}){let r=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!r)throw new Error("a plan must be a JSON object with an `ops` array");let o=Array.isArray(r.ops)?r.ops:null;if(!o?.length)throw new Error("a plan needs at least one op in `ops`");if(o.length>kb)throw new Error(`too many ops (${o.length}); cap is ${kb} \u2014 propose one intent at a time`);let s=Array.isArray(t?.circuits)?t.circuits:[],a=Array.isArray(t?.people)?t.people:[],i=Array.isArray(t?.slots)?t.slots:[],c=Array.isArray(t?.reservations)?t.reservations:[],l={circuits:{},slots:{},reservations:{}},u={},d=new Set,p=!1,f=!1,w=b=>{b.id&&(l.circuits[b.id]={name:b.name,status:b.status,type:b.type??"build",updatedAt:b.updatedAt??null},u[b.id]=b.name)},m=b=>{b.id&&(u[b.id]=b.label)},g=(b,I)=>{let $=Vt(b);if(!$)return null;if(d.has($))throw new Error(`ref "${$}" is used by two ops \u2014 each ref names one thing`);return d.add($),u[`@${$}`]=I,$},y=o.map((b,I)=>{let $=b&&typeof b=="object"?b:{},P=Vt($.op),F=`op ${I+1}`;if(!Sl.has(P))throw new Error(`${F}: unknown op "${P}" \u2014 one of ${[...Sl].join(", ")}`);if(!n.has(P))throw new Error(`${F}: "${P}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let B=R=>{throw new Error(`${F} (${P}): ${R}`)},T=R=>{let A=$.set&&typeof $.set=="object"&&!Array.isArray($.set)?$.set:null;A||B("needs a `set` object naming the fields to change");let M=Object.keys(A).filter(N=>!R.includes(N));return M.length&&B(`unknown field(s) ${M.join(", ")} \u2014 settable: ${R.join(", ")}`),Object.keys(A).length||B("`set` names no fields"),A},_=R=>{let{startDate:A,endDate:M,snapped:N}=Q6(R.startDate,R.endDate);return N&&(p=!0),{startDate:A,endDate:M,snapped:N}},U=R=>{let A=eK(a,R);return Vt(R)==="me"&&(f=!0),m(A),{key:A.id??Vt(R),label:A.label}},J=(R,A,M,N,K)=>{let Y=Vt(R);Y||B(`needs a ${N} id`);let fe=A.find(Ie=>Ie[M]===Y);return fe||B(`no ${N} "${Y}" \u2014 see \`bostrat-roadmap ls\``),K[Y]={...fe},fe};switch(P){case"circuit.create":{let R=Io($.name,fO,"name");R||B("a circuit needs a name");let A=Vt($.type)||"build";sf.has(A)||B(`bad type "${A}" (${[...sf].join(" | ")})`);let M=s.find(K=>String(K.name).toLowerCase()===R.toLowerCase());M&&B(`a circuit named "${M.name}" already exists (${M.id}) \u2014 update it instead of making a twin`);let N=g($.ref,R);return{op:P,...N?{ref:N}:{},name:R,description:Io($.description,mO,"description"),type:A}}case"circuit.update":{let R=bb(s,$.circuit);R.id||B("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(R);let A=T(z6),M={};if(A.name!==void 0){let N=Io(A.name,fO,"name");N||B("name can't be blank"),N!==R.name&&(M.name=N)}return A.description!==void 0&&(M.description=Io(A.description,mO,"description")),A.status!==void 0&&(hO.has(A.status)||B(`bad status "${A.status}" (${[...hO].join(" | ")})`),A.status!==R.status&&(M.status=A.status)),A.type!==void 0&&(sf.has(A.type)||B(`bad type "${A.type}" (${[...sf].join(" | ")})`),A.type!==(R.type??"build")&&(M.type=A.type)),Object.keys(M).length||B("nothing would change \u2014 the set equals the circuit's current values"),{op:P,circuit:R.id,name:R.name,set:M}}case"circuit.delete":{let R=bb(s,$.circuit);R.id||B("can't delete a circuit created in the same plan"),w(R);let A=o.some((M,N)=>N<I&&Vt(M?.op)==="circuit.update"&&M?.set?.status&&M.set.status!=="active"&&Vt(M?.circuit)===Vt($.circuit));return R.status==="active"&&!A&&B(`\u201C${R.name}\u201D is active \u2014 an active circuit can't be deleted; propose a circuit.update to done/abandoned first (both can ride one card)`),{op:P,circuit:R.id,name:R.name,status:R.status}}case"person.create":{let R=Io($.label,yb,"label");R||B("a person row needs a label");let A=a.find(N=>String(N.label).toLowerCase()===R.toLowerCase());A&&B(`a roadmap row labelled "${A.label}" already exists (${A.personId})`);let M=g($.ref,R);return{op:P,...M?{ref:M}:{},label:R}}case"slot.create":{let R=bb(s,$.circuit);w(R);let A=U($.person),M=_($);return{op:P,circuit:R.id??R.ref,circuitName:R.name,person:A.key,personLabel:A.label,...M,estUsd:gO($.estUsd)}}case"slot.update":{let R=J($.slot,i,"slotId","slot",l.slots),A=T(J6),M={};if(A.person!==void 0){let K=U(A.person);M.person=K.key,M.personLabel=K.label}if(A.startDate!==void 0||A.endDate!==void 0){let K=_({startDate:A.startDate??R.startDate,endDate:A.endDate??R.endDate});K.startDate!==R.startDate&&(M.startDate=K.startDate),K.endDate!==R.endDate&&(M.endDate=K.endDate)}A.estUsd!==void 0&&(M.estUsd=gO(A.estUsd)),Object.keys(M).length||B("nothing would change");let N=s.find(K=>K.id===R.circuitId);return{op:P,slot:R.slotId,circuitName:N?.name??null,set:M}}case"slot.delete":{let R=J($.slot,i,"slotId","slot",l.slots),A=s.find(M=>M.id===R.circuitId);return{op:P,slot:R.slotId,circuitName:A?.name??null,startDate:R.startDate,endDate:R.endDate}}case"reservation.create":{let R=U($.person),A=Io($.label,yb,"label");return A||B("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:P,person:R.key,personLabel:R.label,label:A,..._($)}}case"reservation.update":{let R=J($.reservation,c,"reservationId","reservation",l.reservations),A=T(Y6),M={};if(A.person!==void 0){let N=U(A.person);M.person=N.key,M.personLabel=N.label}if(A.label!==void 0){let N=Io(A.label,yb,"label");N||B("label can't be blank"),N!==R.label&&(M.label=N)}if(A.startDate!==void 0||A.endDate!==void 0){let N=_({startDate:A.startDate??R.startDate,endDate:A.endDate??R.endDate});N.startDate!==R.startDate&&(M.startDate=N.startDate),N.endDate!==R.endDate&&(M.endDate=N.endDate)}return Object.keys(M).length||B("nothing would change"),{op:P,reservation:R.reservationId,label:R.label,set:M}}case"reservation.delete":{let R=J($.reservation,c,"reservationId","reservation",l.reservations);return{op:P,reservation:R.reservationId,label:R.label,startDate:R.startDate,endDate:R.endDate}}default:return B("unhandled op")}});y.forEach((b,I)=>{for(let $ of[b.circuit,b.person,b.set?.person])if(vb($)&&!d.has(String($).slice(1)))throw new Error(`op ${I+1} (${b.op}): unknown ref "${$}" \u2014 no earlier op in this plan creates it`)});let x=a.some(b=>b.kind==="user"&&b.userId);return{why:Io(r.why,G6,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:f&&!x}}async function kO(e,t,n,r={}){let o=tK(t,n,r),s=K6(),a={ts:Date.now(),proposalId:s,...o};return await C({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var nK=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await q({id:e.id,cwd:e.cwd}),r=n.find(o=>o.type==="planning.change.offered"&&o.payload?.proposalId===t);if(!r)throw new Error("unknown proposal");if(n.some(o=>o.type==="planning.change.answered"&&o.payload?.proposalId===t))throw new Error("proposal already answered");return r};async function xO(e,t,n,{results:r=[]}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let o=await nK(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await C(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,kb+1):[]}}),await C(s,{type:"planning.change.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,ops:a.ops?.length??0}}),{proposalId:t,action:n}}Dd();me();Fr();me();Dn();Yd();var vO=10,SO=200,rK=120,oK=24,TO=/^\d{4}-\d{2}-\d{2}$/;function Sb(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var sK=(e=Date.now())=>new Date(e).toISOString().slice(0,10),xt=(e,t="i")=>new RegExp(e,t),aK=[{re:xt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:xt("\\bSPC\\b",""),reason:"business (SPC)"},{re:xt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:xt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:xt("\\bReplicas\\b",""),reason:"competitor research"},{re:xt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:xt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:xt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],iK=[xt("\\bSPC\\b",""),xt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),xt("competitor|cloudcli|\\bkiro\\b"),xt("\\bReplicas\\b",""),xt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),xt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),xt("(^|[^\\w&])#\\d+\\b"),xt("\\btrack/[\\w.-]+")];function cK({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of aK)if(o.test(n)||o.test(r))return s;return null}function AO(e){let t=String(e||"");for(let n of iK){let r=n.exec(t);if(r)return r[0].trim()}return null}function EO(e,t=Date.now()){if(!e)return t-24*36e5;let n=/^(\d+)\s*([hd])$/.exec(String(e).trim());if(n)return t-Number(n[1])*(n[2]==="h"?36e5:24*36e5);let r=Date.parse(e);if(!Number.isNaN(r))return r;throw new Error(`unparseable since "${e}" \u2014 use 24h, 7d, or an ISO date`)}var lK=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function uK(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Nc(e);if(t.length)throw new Error(`changelog entry appears to contain a secret VALUE (${t.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of e.split(`
|
|
762
|
+
`)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,rK)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${oK}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=lK.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let d=AO(i);if(d)throw new Error(`bullet ${r.length+1} mentions "${d}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>SO)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${SO}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=AO(n);if(o)throw new Error(`headline mentions "${o}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items; rewrite it and re-publish.`)}if(!r.length)throw new Error("no `- ` bullets found \u2014 an entry is a bullet list, optionally under a `# headline`");if(r.length>vO)throw new Error(`${r.length} bullets \u2014 over the ${vO}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function dK(e,{repos:t=Sb()}={}){let n=new Set(t);return(await mn()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=e&&n.has(r.repo)).sort((r,o)=>(r.resolvedAt??0)-(o.resolvedAt??0)).map(r=>({repo:r.repo,number:r.number,title:r.title||null,url:r.url||null,headRef:r.headRef||null,mergedAt:r.resolvedAt??null,excluded:cK({title:r.title,headRef:r.headRef})}))}async function _O(e,t){let n=await dK(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function IO(e,{md:t,day:n=null}){let r=uK(t),o=n==null||n===""?sK():String(n);if(!TO.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await C({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function $O(e,{day:t}){let n=String(t||"");if(!TO.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await C({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}as();Dn();cs();me();as();gt();gr();Dn();ic();Md();gd();fc();Zt();import{execFile as SK}from"node:child_process";import{promisify as AK}from"node:util";var pK=new Set(["pull_request","check_suite","workflow_run","push"]),fK=/^[^/\s]+\/[^/\s]+$/,mK=500,Ab=new Set,Tb=[],af=new Map,on={hourStart:0,byEvent:{},duplicates:0,rejected:0};function Eb(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==on.hourStart&&(on.hourStart=r,on.byEvent={},on.duplicates=0,on.rejected=0),t==="accepted"?on.byEvent[n]=(on.byEvent[n]||0)+1:on[t]+=1}function hK(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!pK.has(e.event)||typeof e.repo!="string"||!fK.test(e.repo))return null;let t=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(r=>Number.isInteger(r)&&r>0),n=Number.isInteger(e.number)&&e.number>0?e.number:t[0]??null;return{forge:"github",deliveryId:typeof e.deliveryId=="string"&&e.deliveryId?e.deliveryId.slice(0,128):null,event:e.event,action:typeof e.action=="string"?e.action.slice(0,64):null,repo:e.repo,number:n,numbers:n&&!t.includes(n)?[n,...t]:t,headSha:typeof e.headSha=="string"?e.headSha.slice(0,64):null,headRef:typeof e.headRef=="string"?e.headRef.slice(0,256):null,baseRef:typeof e.baseRef=="string"?e.baseRef.slice(0,256):null,merged:typeof e.merged=="boolean"?e.merged:null,draft:typeof e.draft=="boolean"?e.draft:null,conclusion:typeof e.conclusion=="string"?e.conclusion.slice(0,64):null,deleted:e.deleted===!0,senderLogin:typeof e.senderLogin=="string"?e.senderLogin.slice(0,128):null,ts:Number.isFinite(e.ts)?e.ts:null}}function RO(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=hK(e);if(!o)return Eb(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(Ab.has(o.deliveryId))return Eb(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(Ab.add(o.deliveryId),Tb.push(o.deliveryId);Tb.length>mK;)Ab.delete(Tb.shift())}let s=o.repo.toLowerCase(),a=af.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,af.set(s,a),Eb(t,"accepted",o.event),r.log?.(`[github-event] ${o.event}${o.action?` ${o.action}`:""} ${o.repo}${o.number?` #${o.number}`:o.headRef?` ${o.headRef}`:""}${o.conclusion?` (${o.conclusion})`:""}${o.deliveryId?` delivery ${o.deliveryId.slice(0,8)}`:""}`);try{n?.(o)}catch(i){r.error?.("[github-event] onAccept failed:",i?.message||i)}return{ok:!0,duplicate:!1,envelope:o}}function wK(e,t=Date.now()){let n=af.get(String(e||"").toLowerCase());return n?{covered:!0,lastDeliveryAt:n.lastDeliveryAt,ageMs:t-n.lastDeliveryAt,count:n.count}:{covered:!1,lastDeliveryAt:null,ageMs:null,count:0}}var OO=1440*6e4;function _b(e,t=Date.now()){let n=wK(e,t);return n.covered&&n.ageMs<OO}function MO(e=Date.now()){let t={};for(let[n,r]of af)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<OO};return{hourStart:on.hourStart,byEvent:{...on.byEvent},duplicates:on.duplicates,rejected:on.rejected,repos:t}}me();Dn();Pr();gr();Zt();function CO(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function gK(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var yK=new Set(["merged","closed","lost"]);function bK(e,t){if(!e?.blocked)return null;let n=CO(t);if(e.blocked==="red")return t.checks.failed===0&&t.checks.total>0?{change:"ci-fixed",reason:"red"}:null;if(e.blocked==="conflict")return t.mergeable==="MERGEABLE"&&n!=="red"?{change:"reconciled",reason:"conflict"}:null;if(e.blocked==="behind"){let r=t.headSha??null;return n===null&&r&&e.sha&&r!==e.sha?{change:"reconciled",reason:"behind"}:null}return null}function kK(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function xK(e,t,n,r,o){return(await q(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function vK(e,t,n){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function cf(e,t={}){let{now:n=Date.now(),slugOf:r=Re,lookup:o=ut,note:s=$A,tracks:a=async()=>(await ye()).filter(d=>!Le(d)),asked:i=xK,emitChange:c=vK}=t,l=[],u=null;for(let d of e??[]){if(!d?.prs?.length)continue;let p=await r(d.path).catch(()=>null);if(p)for(let f of d.prs)try{if(!gK(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||yK.has(w.state))continue;let{prev:m}=await s(p,f.number,{blocked:CO(f),sha:f.headSha??null,at:n});if(!m)continue;let g=bK(m,f);if(!g||kK(w,g.change))continue;u??=new Map((await a()).map(I=>[I.id,I]));let y=u.get(w.trackId);if(!y)continue;let x=f.headSha??null;if(await i(y,g.change,f.number,x,m.at||0))continue;let b={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:x,delegated:!1,reason:g.reason};g.change==="ci-fixed"?b.passed=f.checks.passed:b.base=f.baseRefName||null,await c(y,g.change,b),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var Rb=AK(SK),HO=3e4,TK=30*6e4,EK=HO,_K=10*6e4,IK=10080*6e4,$K=60*6e4,NO=8,WO=1440*6e4,RK=3,qO="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",$b=60*6e4,OK=15*6e4,MK=9e4,CK=1440*6e4,Al=new Map,Tl=new Map,NK=360*6e4,PK=e=>e.reduce((t,n)=>({misses:Math.max(t.misses,n.brokerRefused?.misses||0),until:Math.max(t.until,n.brokerRefused?.until||0)}),{misses:0,until:0}),DK=/could not resolve|not found|no pull requests?/i,BK=e=>DK.test(String(e?.message||e||""));function jK(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<$b)}var PO={fast:EK,slow:_K,decay:$K};function DO(e,t,n=_b){return KO(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<TK||jK(e,t))?"fast":t-(e.firstSeen||0)>IK?"decay":"slow"}function _l(e,t,n,r){let o=e.lanes?.get(ie(t.repo,t.number))||{};return wd({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function LK(e,t){pr("watch");try{let{stdout:n}=await Rb("gh",["pr","view",String(t),"--repo",e,"--json",qO],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await En({slug:e})}});return JSON.parse(n||"null")}catch(n){throw ao(n)&&io(n),n}}async function FK(e){pr("watch");try{let{stdout:t}=await Rb("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",qO],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await En({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw ao(t)&&io(t),t}}async function UK(){let e=new Map;for(let t of await ye().catch(()=>[]))e.set(t.id,t);return e}async function HK(e,t){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await Od(e,t).catch(()=>{})}async function WK(e,t){let n=await ss(e);return n?ya(n,t):null}async function qK(e,t,n){let r=await ss(e);if(!r)throw new Error(`no local checkout for ${e}`);return ba(r,t,{method:n})}async function KK(e,t){let n=await ss(e);if(!n)throw new Error(`no local checkout for ${e}`);return uc(n,t)}async function GK(e,t){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function Za(e,t,n,r,o){if(!await r.disarm(e.repo,e.number).catch(()=>null))return;let a=n.get(e.trackId);a&&await r.emitDisarmed(a,{number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo,reason:o}).catch(()=>{})}var VK=10*6e4;async function zK(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>WO){await Za(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(e.repo,e.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await Za(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Za(e,o,t,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(e.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<VK)return;await Za(e,o,t,n,o.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(o.checks.pending>0||o.mergeable==="UNKNOWN"||o.mergeStateStatus==="UNKNOWN"||o.isDraft)return;let s=await n.lookup(e.repo,e.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(e.repo,e.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await Za(e,o,t,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(e.repo,e.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await Za(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await GO(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Qa(e,t,n){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function JK(e,t){try{return await Rb("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function El(e,t,n,r=()=>!0){return(await q(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var ei=(e,t)=>({number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo});function KO(e,t,{grace:n=MK}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=CK}async function YK(e,t,n,r){let o=r.now??Date.now();if(!KO(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Le(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??is)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await q(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??ur)(e.repo,e.number).catch(()=>null),!1):await(r.claim??ur)(e.repo,e.number).catch(()=>null)?(await Qa(s,"opened",{...ei(e,t),announcedBy:"watch"}).catch(()=>{}),console.log(`[pr-watch] announced passive link ${e.repo}#${e.number} \u2192 track ${s.id} (no active door claimed it)`),!0):!1}async function XK(e,t,n,r){let o=r.now??Date.now(),s=t.headRefOid||null,a=n.get(e.trackId)||null;if(s&&(e.ciFix?.headSha&&s!==e.ciFix.headSha&&await cd(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await ud(e.repo,e.number,{headSha:s}).catch(()=>{})),s&&s!==e.lastHeadSha){let i=!e.lastHeadSha,c=!!(e.ciFix||e.reconcile||e.ciFixAwait||e.reconcileAwait),l=!!e.baseFoldAt&&o-e.baseFoldAt<OK;await IA(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await _A(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await El(a,"pushed",e.number,d=>d.payload?.sha===s)&&await Qa(a,"pushed",{...ei(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>$b)await ld(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await ld(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=_l(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await El(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Qa(a,"ci-fixed",{...ei(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await ld(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>$b)await dd(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await dd(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){_l(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await El(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Qa(a,"reconciled",{...ei(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await dd(e.repo,e.number).catch(()=>{})}}}}async function ZK(e,t,n,r){let o=_l(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await El(s,"closed",e.number)&&await Qa(s,"closed",{...ei(e,t),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(e.repo,e.number,"closed").catch(()=>{}),await r.mark(e.repo,e.number,"closed").catch(()=>{})}async function BO(e,t,n){_l(n,e,"lost",null);let r=t.get(e.trackId);r&&!await El(r,"lost",e.number)&&await Qa(r,"lost",ei(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function GO(e,t,n,r,o={}){let s=_l(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await q(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.followupsIfMerged(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function jO(e={}){let{now:t=Date.now(),auth:n=qh,view:r=LK,list:o=FK,links:s=MA,trackMap:a=UK,emitMerged:i=HK,mark:c=oo,archiveIfArmed:l=hr,notifyIfArmed:u=wr,notifyIfResolved:d=bp,followupsIfMerged:p=bs,batchThreshold:f=RK,detail:w=WK,merge:m=qK,updateBranch:g=KK,lookup:y=ut,disarm:x=ac,emitDisarmed:b=GK,localHasCommit:I=JK,claim:$=ur,midTurn:P=is,only:F=null,wantDetail:B=null,covered:T=_b,verdicts:_=null,tokenFor:U=z=>js(z),noteRefusal:J=TA,clearRefusal:R=EA}=e;if(!(await n().catch(()=>null))?.authenticated||md()>0)return 0;let M=await s().catch(()=>[]),N=nT(M),K=z=>{try{return!!B?.(z)}catch{return!1}},Y=F?M.filter(z=>{try{return F(z)}catch{return!1}}):M.filter(z=>t-(Al.get(ie(z.repo,z.number))||0)>=PO[DO(z,t,T)]);if(!Y.length)return 0;let fe=Date.now(),Ie=new Map,Ce=new Map;for(let z of[...Y].sort(dc)){let we=F?"event":DO(z,t,T);Ie.set(ie(z.repo,z.number),{lane:we,intervalMs:PO[we]??null}),Al.set(ie(z.repo,z.number),t),Ce.has(z.repo)||Ce.set(z.repo,[]),Ce.get(z.repo).push(z)}let X=await a().catch(()=>new Map),et=new Map,Ee=(z,we)=>{let Fe=ie(z,we);if(!et.has(Fe)){let O=Promise.resolve().then(()=>w(z,we));O.catch(()=>{}),et.set(Fe,O)}return et.get(Fe)},se=_??((z,we)=>cf([{path:z,prs:[we]}],{now:t,slugOf:async()=>z,tracks:async()=>[...X.values()].filter(Fe=>!Le(Fe))}).catch(()=>{})),ee={now:t,lanes:Ie,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Ee,merge:m,updateBranch:g,lookup:y,disarm:x,emitDisarmed:b,localHasCommit:I,claim:$,midTurn:P};for(let[z,we]of Ce){let Fe=PK(we);if(Fe.until>t)continue;let O=!1;try{if(await U(z),Fe.misses)for(let Q of we)await R(Q.repo,Q.number).catch(()=>{})}catch(Q){O=xk(Q)}if(O){let Q=Fe.misses+1;if(Q>=NO){console.log(`[pr-watch] ${z}: not granted ${Q}\xD7 \u2014 retiring ${we.length} link(s) as lost`);for(let ge of we){await BO(ge,X,ee);let pt=ie(ge.repo,ge.number);Tl.delete(pt),Al.delete(pt)}}else for(let ge of we)await J(ge.repo,ge.number,{misses:Q,until:t+NK}).catch(()=>{});continue}let ce,ve=new Set,wt=Q=>Q.ciFixAwait||Q.reconcileAwait||K(Q)?!0:!Q.autoMerge||Q.trackId&&N.get(Q.trackId)!==ie(Q.repo,Q.number)?!1:t-(Q.autoMerge.armedAt||0)<=WO;if(we.length>f)ce=await o(z).catch(()=>null);else{ce=new Map;for(let Q of we){if(wt(Q)){let ge=await Ee(z,Q.number).catch(()=>null);if(ge?.state){ce.set(Number(Q.number),{number:Number(Q.number),url:ge.url,title:ge.title,headRefName:ge.headRefName,headRefOid:ge.headSha??null,state:ge.state,mergedAt:ge.mergedAt??null,closedAt:ge.closedAt??null});continue}}try{let ge=await r(z,Q.number);ge?.number!=null&&ce.set(Number(ge.number),ge)}catch(ge){BK(ge)&&ve.add(ie(Q.repo,Q.number))}}}if(ce)for(let Q of we){let ge=ie(Q.repo,Q.number),pt=ce.get(Number(Q.number));if(!pt){if(ve.has(ge)){let rt=(Tl.get(ge)||0)+1;Tl.set(ge,rt),rt>=NO&&(await BO(Q,X,ee),Tl.delete(ge),Al.delete(ge))}continue}if(Tl.delete(ge),pt.state==="MERGED"||pt.state==="CLOSED")pt.state==="MERGED"?await GO(Q,pt,X,ee):await ZK(Q,pt,X,ee),Al.delete(ge);else{await YK(Q,pt,X,ee).catch(()=>{}),await XK(Q,pt,X,ee).catch(()=>{});let rt=!Q.trackId||N.get(Q.trackId)===ge;Q.autoMerge&&rt&&await zK(Q,X,ee).catch(()=>{});try{if(K(Q)&&!et.has(ge)&&Ee(Q.repo,Q.number),et.has(ge)){let k=await et.get(ge).catch(()=>null);k?.checks&&await se(Q.repo,k)}}catch{}}}}let Oe={};for(let{lane:z}of Ie.values())Oe[z]=(Oe[z]||0)+1;return console.log(`[pr-watch] probed ${Y.length} link(s) (${Object.entries(Oe).map(([z,we])=>`${z} ${we}`).join(", ")}) in ${Date.now()-fe}ms`),Y.length}function LO(e,t){return!e||!t?!1:e.all?!0:String(t.repo||"").toLowerCase()!==e.repo?!1:e.numbers?.length?e.numbers.includes(Number(t.number)):e.event==="push"?!!e.branch&&t.headRef===e.branch||!!t.autoMerge:e.branch?t.headRef===e.branch:!0}var Ib=!1,lf=!1,uf=[],FO=Promise.resolve();async function QK(){for(;lf||uf.length;){if(lf){lf=!1;try{await jO()}catch{}continue}let e=uf;uf=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await jO({...n,only:r=>t.some(o=>LO(o,r)),wantDetail:r=>t.some(o=>o.detail&&LO(o,r))})}catch{}}}function df(e,t){return e===null?lf=!0:uf.push({spec:e,deps:t}),Ib||(Ib=!0,FO=QK().finally(()=>{Ib=!1})),FO}function VO(e,t=void 0){let n=String(e?.repo||"").toLowerCase();if(!/^[^/\s]+\/[^/\s]+$/.test(n))return Promise.resolve();let r=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(o=>Number.isInteger(o)&&o>0);return df({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var eG=6e4,UO=0;function zO(e=void 0){let t=e?.now??Date.now();return t-UO<eG?Promise.resolve():(UO=t,df({all:!0},e))}function JO(){df(null),setInterval(()=>df(null),HO)}as();Cd();Rc();gr();Zt();var tG=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function nG({tracks:e=ye,reconcile:t=qd}={}){for(let n of(await e().catch(()=>[])).filter(r=>!Le(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function YO(e,t={}){let{invalidate:n=en,probe:r=VO,poke:o=LT,reconcileOpened:s=nG}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&tG.has(e.action)){if(e.action==="opened"||e.action==="reopened"){a.poked=!0,a.reconciled=!0;try{o()}catch{}s()}a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event}}else(e.event==="check_suite"||e.event==="workflow_run")&&e.action==="completed"?a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(a.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return a.probe&&r(a.probe),a}ft();me();gr();Zt();import{randomUUID as rG}from"node:crypto";var oG=2e4,XO=3,ti=new Map,Ob=new Set;async function ZO(e,t,n){let r=await n(e).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===t?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function sG(e={}){let{sessions:t=null,tracks:n=null,append:r=C,read:o=q,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await cn(),i=n??await ye()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Le(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(f=>f.name===u.leadBox);if(!d||d.agent!=="claude"||d.state!=="live")continue;let p=c.get(d.name);if(p)if(l.add(d.name),p.alternateOn){let f=(ti.get(d.name)||0)+1;ti.set(d.name,f),f===XO&&(Ob.add(d.name),await ZO(u,d.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:rG(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(ti.get(d.name)||0)>=XO;if(ti.delete(d.name),f||!Ob.has(d.name)){Ob.add(d.name);let w=await ZO(u,d.name,o);w&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:w,action:"cleared"}}).catch(()=>{})}}}for(let u of[...ti.keys()])l.has(u)||ti.delete(u)}var Il=null,Mb=!1;function QO(){return Il?()=>{}:(Il=setInterval(()=>{Mb||(Mb=!0,sG().catch(()=>{}).finally(()=>{Mb=!1}))},oG),Il.unref?.(),()=>{clearInterval(Il),Il=null})}ts();Rc();me();as();cs();ts();gc();import{randomUUID as aG}from"node:crypto";async function iG(){let e=await Promise.resolve().then(()=>(gr(),FI));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var Cb={listRepoPrs:Bn,readEvents:q,appendEvent:C,sayDeps:iG,currentBranch:co};async function cG(e,t=Cb,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??co)(e.workspace?.kind==="multi"?null:e.cwd).catch(()=>null)||e?.workspace?.branch;if(!r)return null;let o;try{o=await t.listRepoPrs(e.cwd,{caller:"pr-exists"})}catch{return null}let s=(o||[]).find(a=>a.headRefName===r);return s?{number:s.number,url:s.url??null,title:s.title??null}:null}async function Nb(e,t,{actions:n,notify:r=!1}={},o=Cb){let s=t?.payload||{};if(!Array.isArray(n)||!n.includes("pr")||s.toPr||Array.isArray(s.repos)&&s.repos.length||!s.branch)return null;let a=await cG(e,o,{branch:s.branch});if(!a)return null;let i={id:e.id,cwd:e.cwd};await o.appendEvent(i,{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:s.offerId,action:"pr-exists",actions:n,...r?{notify:!0}:{},existingPr:{number:a.number}}});let c=aG();return await o.appendEvent(i,{type:"pr.exists.offered",actor:"system",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:c,srcOfferId:s.offerId??null,branch:s.branch,base:s.base??null,pr:a,actions:n,...r?{notify:!0}:{},offeredRebase:Array.isArray(s.offered)&&s.offered.includes("rebase")}}),{offerId:c,pr:a}}async function Pb(e,{offerId:t,choice:n}={},r=Cb){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return uo(`prx:${e.id}:${t}`,()=>lG(e,{offerId:t,choice:n},r))}async function lG(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=ro.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,ma(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:u}=await r.sayDeps();l=i,c=await u(e.id,pA(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}gc();import Or from"node:fs/promises";import ni from"node:path";import aM from"node:os";import eM from"node:fs/promises";import pf from"node:path";import{execFile as uG}from"node:child_process";import{promisify as dG}from"node:util";import{fileURLToPath as pG}from"node:url";var fG=dG(uG),nM=pf.dirname(pG(import.meta.url)),mG=pf.resolve(nM,"..","..","client","dist"),hG="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",wG=new Map([...hG].map((e,t)=>[e,t]));function gG(e){let t=[],n=0,r=0;for(let o of e){let s=wG.get(o);if(s===void 0)return t;n+=(s&31)<<r,s&32?r+=5:(t.push(n&1?-(n>>>1):n>>>1),n=0,r=0)}return t}function yG(e){let t=[],n=0,r=0,o=0;for(let s of e.split(";")){let a=[],i=0;if(s)for(let c of s.split(",")){let l=gG(c);l.length!==0&&(i+=l[0],l.length>=4&&(n+=l[1],r+=l[2],o+=l[3],a.push([i,n,r,o])))}t.push(a)}return t}function bG(e,t){if(!e||e.length===0||e[0][0]>t)return null;let n=0,r=e.length-1;for(;n<r;){let o=n+r+1>>1;e[o][0]<=t?n=o:r=o-1}return e[n]}var tM=new Map;async function kG(e){let t;try{t=await eM.stat(e)}catch{return null}let n=tM.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await eM.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:yG(r.mappings||"")};return tM.set(e,o),o}catch{return null}}var Db=null;function xG(){return Db||(Db=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):fG("git",["rev-parse","--short","HEAD"],{cwd:pf.resolve(nM,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Db}var vG=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function SG(e,{distDir:t=mG}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(vG)){let[a,i,c,l]=s,u=await kG(pf.join(t,"assets",`${i}.map`)),d=u?bG(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),d&&u.sources[d[1]]){let p=u.sources[d[1]].replace(/^(\.\.\/)+/,"");n.push(`${p}:${d[2]+1}:${d[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function rM(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await xG();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await SG(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var AG=()=>process.env.BOSTRAT_STATE_DIR||ni.join(process.env.HOME||aM.tmpdir(),".bostrat"),$o=()=>ni.join(AG(),"telemetry"),iM=()=>ni.join($o(),".relay-offsets.json"),TG=50,EG=14,_G=3e4,oM=500,zt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function IG(e,t){if(!e||typeof e!="object")return null;let n=zt(e.name,64);if(!n)return null;let r=Number.isFinite(e.ts)?e.ts:t,o={name:n,ts:Math.abs(r-t)<168*3600*1e3?r:t,receivedAt:t,anonId:zt(e.anonId,64),sessionId:zt(e.sessionId,64),userId:zt(e.userId,64),release:zt(e.release,64),appVersion:zt(e.appVersion,32),route:zt(e.route,128),deviceClass:e.deviceClass==="phone"||e.deviceClass==="desktop"?e.deviceClass:""};return e.props&&typeof e.props=="object"&&!Array.isArray(e.props)&&(JSON.stringify(e.props).length<=8192?o.props=e.props:o.props={clamped:!0}),e.error&&typeof e.error=="object"&&(o.error={kind:zt(e.error.kind,256),message:zt(e.error.message,8192),stack:zt(e.error.stack,32768),fingerprint:zt(e.error.fingerprint,64)}),Array.isArray(e.breadcrumbs)&&(o.breadcrumbs=e.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:zt(s?.n,64),r:zt(s?.r,128)}))),o}var cM=e=>new Date(e).toISOString().slice(0,10),sM=0;async function lM(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,TG):[]).map(s=>IG(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await rM(s);await Or.mkdir($o(),{recursive:!0});let o=ni.join($o(),`${cM(t)}.ndjson`);return await Or.appendFile(o,r.map(s=>JSON.stringify(s)+`
|
|
763
|
+
`).join(""),"utf8"),t-sM>6*3600*1e3&&(sM=t,$G(t).catch(()=>{})),r.length}async function $G(e=Date.now()){let t=cM(e-EG*24*3600*1e3),n=[];try{n=await Or.readdir($o())}catch{return}let r=n.filter(s=>s.endsWith(".ndjson")&&s.slice(0,10)<t);if(!r.length)return;for(let s of r)await Or.rm(ni.join($o(),s),{force:!0});let o=await dM();for(let s of r)delete o[s];await pM(o)}var ff=new Map;function uM(e,t=Date.now()){let n=e||"unknown",r=ff.get(n);return r||(ff.size>512&&ff.clear(),r={tokens:40,at:t},ff.set(n,r)),r.tokens=Math.min(40,r.tokens+(t-r.at)/6e4*20),r.at=t,r.tokens<1?!1:(r.tokens-=1,!0)}async function dM(){try{return JSON.parse(await Or.readFile(iM(),"utf8"))||{}}catch{return{}}}async function pM(e){await Or.mkdir($o(),{recursive:!0}),await Or.writeFile(iM(),JSON.stringify(e),"utf8")}function RG(e,{env:t,host:n}={}){let r=e.name==="app.error"&&e.error,o={};for(let[a,i]of[["event",e.name],["route",e.route],["session",e.sessionId],["anon",e.anonId],["user",e.userId],["release",e.release],["appVersion",e.appVersion],["device",e.deviceClass]])i&&(o[a]=i);let s={timestamp:new Date(e.ts).toISOString(),service:"bostrat-client",source:"treetop-js",env:t||process.env.BOSTRAT_ENV||"pi",host:n||aM.hostname(),level:r?"error":"info",message:r?`${e.error.kind||"Error"}: ${e.error.message||"(no message)"}`.slice(0,8192):e.name,tags:o,attributes:{...e.props?{props:e.props}:{},receivedAt:e.receivedAt}};return r&&(s.error={kind:e.error.kind,message:e.error.message,stack:e.error.stack},e.error.fingerprint&&(s.fingerprint=e.error.fingerprint),e.error.symbolicated&&(s.attributes.symbolicated=!0),e.breadcrumbs&&(s.attributes.breadcrumbs=e.breadcrumbs)),s}async function OG({fetchImpl:e=fetch}={}){let t=await S$();if(!t)return{sent:0,disabled:!0};let n;try{n=(await Or.readdir($o())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await dM(),o=0;for(let s of n){let a=ni.join($o(),s),i=r[s]||0,c;try{let p=await Or.open(a,"r");try{let f=(await p.stat()).size;if(f<=i)continue;c=Buffer.alloc(f-i),await p.read(c,0,c.length,i)}finally{await p.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
|
|
764
|
+
`).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=oM){let f=d.slice(p,p+oM).map(m=>RG(m)),w=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:f})}).catch(()=>null);if(!w||!w.ok)return{sent:o,disabled:!1};o+=f.length}r[s]=i+l+1,await pM(r)}return{sent:o,disabled:!1}}var Bb=null,jb=!1;function fM(){Bb||(Bb=setInterval(async()=>{if(!jb){jb=!0;try{await OG()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{jb=!1}}},_G),Bb.unref?.())}import hf from"node:fs/promises";import yM from"node:path";import MG from"node:os";var bM=()=>process.env.BOSTRAT_STATE_DIR||yM.join(process.env.HOME||MG.tmpdir(),".bostrat"),kM=()=>yM.join(bM(),"dictation-glossary.json"),CG=100,NG=500,PG=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],wf=null,Lb=null,Fb=Promise.resolve();function mM(){let e={},t=Date.now();for(let n of PG)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function xM(){return wf||(Lb??=hf.readFile(kM(),"utf8").then(e=>JSON.parse(e)?.terms??mM()).catch(()=>mM()).then(e=>wf=e).finally(()=>Lb=null),Lb)}async function hM(){let e=JSON.stringify({terms:wf},null,2),t=kM(),n=`${t}.${process.pid}.tmp`;await hf.mkdir(bM(),{recursive:!0}),await hf.writeFile(n,e),await hf.rename(n,t)}function DG(){return Fb=Fb.then(hM,hM),Fb.catch(()=>{})}async function Ub(){return Object.values(await xM()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var BG=e=>Math.max(1,Math.ceil(e.length/4));async function jG(){let e=[],t=0;for(let{term:n}of await Ub()){let r=BG(n);if(!(t+r>NG)&&(e.push(n),t+=r,e.length>=CG))break}return e}async function LG(e,t){let n=await xM(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var wM=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),mf=e=>e.toLowerCase();function gM(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function vM(e,t){let n=wM(e),r=wM(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let d=s-1;d>=0;d--)a[u][d]=mf(n[u])===mf(r[d])?a[u+1][d+1]+1:Math.max(a[u+1][d],a[u][d+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)mf(n[c])===mf(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(gM(r[l])&&i.add(r[l]),l++);for(;l<s;l++)gM(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await LG(u,"learned");return await DG(),[...i]}var $l=null;function FG(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.err_code||n?.error_code||n?.category||"";return e===402||/PAYMENT_REQUIRED/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"Deepgram credits are exhausted \u2014 dictation is down until you top up at console.deepgram.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"Deepgram rejected the API key (revoked, or missing ASR scope) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"transcription_failed",persistent:!1,message:`Deepgram error ${e}: ${t.slice(0,300)}`}}async function SM(){if(!$l)return null;let e=await il();if(!e||e.apiKey.slice(-6)!==$l.keyTail)return null;let{keyTail:t,...n}=$l;return n}async function AM(e,t){let n=await il();if(!n){let i=new Error("Deepgram is not configured \u2014 add deepgram.apiKey to ~/.bostrat/integrations.json");throw i.status=503,i.code="not_configured",i}let r=new URL("https://api.deepgram.com/v1/listen");r.searchParams.set("model","nova-3"),r.searchParams.set("smart_format","true");for(let i of await jG())r.searchParams.append("keyterm",i);let o=await fetch(r,{method:"POST",headers:{Authorization:`Token ${n.apiKey}`,"Content-Type":t||"application/octet-stream"},body:e});if(!o.ok){let i=await o.text().catch(()=>""),c=FG(o.status,i);c.persistent&&($l={code:c.code,message:c.message,at:Date.now(),keyTail:n.apiKey.slice(-6)});let l=new Error(c.message);throw l.status=c.status,l.code=c.code,l}return $l=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}me();var Hb={"gpt-realtime-2.1":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime":{textIn:4,textInCached:.4,textOut:16,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2.1-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20},"gpt-realtime-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20}};function UG(e){if(!e)return null;let t=String(e).trim();if(Hb[t])return t;let n=null;for(let r of Object.keys(Hb))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function HG(e,t={}){let n=Hb[UG(e)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(t[o])||0)*n[o];return r/1e6}function WG(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.error?.code||n?.error?.type||"";return e===429&&/insufficient_quota/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"The OpenAI account is out of credit \u2014 voice chat is down until you top up at platform.openai.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"OpenAI rejected the API key (revoked, or missing Realtime access) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"mint_failed",persistent:!1,message:`OpenAI realtime session mint failed (${e}): ${t.slice(0,300)}`}}var Rl=null;async function qG(){if(!Rl)return null;let e=await Up();if(!e||e.apiKey.slice(-6)!==Rl.keyTail)return null;let{keyTail:t,...n}=Rl;return n}async function KG(e){let t=await fetch("https://api.openai.com/v1/realtime/client_secrets",{method:"POST",headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({session:{type:"realtime",model:e.model,audio:{output:{voice:e.voice}}}})});if(!t.ok){let o=await t.text().catch(()=>""),s=WG(t.status,o);s.persistent&&(Rl={code:s.code,message:s.message,at:Date.now(),keyTail:e.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}Rl=null;let n=await t.json(),r=n?.value??n?.client_secret?.value;if(!r){let o=new Error("OpenAI returned no client secret");throw o.status=502,o.code="mint_failed",o}return{clientSecret:{value:r,expiresAt:n?.expires_at??n?.client_secret?.expires_at??null}}}var GG={openai:KG};async function TM(){let e=await Up();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await qG()}:{configured:!1}}async function EM(){let e=await Up();if(!e){let n=new Error("Voice chat is not configured \u2014 add openai.apiKey to ~/.bostrat/integrations.json");throw n.status=503,n.code="not_configured",n}let t=await GG[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function _M(e,{model:t,usage:n={},seconds:r}={}){let o=c=>Math.max(0,Math.round(Number(c)||0)),s={textIn:o(n.textIn),textInCached:o(n.textInCached),textOut:o(n.textOut),audioIn:o(n.audioIn),audioInCached:o(n.audioInCached),audioOut:o(n.audioOut)},a=HG(t,s),i=await C(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}Zt();kA(async()=>new Set((await ye()).map(e=>e.id)));var PM=$e.dirname(zG(import.meta.url)),IM=Number(process.env.PORT)||3362,gf=ky(process.env),DM=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,ri=FR(process.env.BOSTRAT_ALLOW_IPS),Vb=UR(process.env.BOSTRAT_VIEW_FRONT_CIDRS,of),zb=WR(),BM=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",E=Jt();E.disable("x-powered-by");E.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),rf(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});E.use((e,t,n)=>{if(vl(e)||ri.allowed(ri.clientIp(e))||Vb.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});E.use(JR);E.use(GR({token:zb,enforce:BM}));E.use("/api/mocks",Jt.json({limit:"1mb"}));E.use("/api/mocks",Jt.raw({type:"image/png",limit:"24mb"}));E.use("/api/mocks",Jt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));E.use("/api/runbooks",Jt.json({limit:"1mb"}));E.use("/api/tracks/adopt",Jt.json({limit:"1mb"}));E.use("/api/telemetry",Jt.json({limit:"256kb"}));E.use("/api/hook",Jt.json({limit:"2mb"}));E.use("/api/dictation",Jt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));E.use("/api/tracks/:id/upload",Jt.raw({type:()=>!0,limit:"25mb"}));E.use(Jt.json({limit:"64kb"}));E.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:Ft,hostTmuxAlive:await Hr(),autoTriggerPct:DM,plane:oi?oi.status():null})});E.get("/api/sessions",async(e,t)=>{t.json({sessions:await cn()})});E.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await $n(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});E.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Be(n))return t.status(400).json({error:"invalid session name"});if(!await be(n))return t.status(404).json({error:"session not found"});try{await Ct(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});E.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Be(n))return t.status(400).json({error:"invalid session name"});let r=await be(n);if(!r)return t.status(404).json({error:"session not found"});let o=await Pi(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});E.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Be(n))return t.status(400).json({error:"invalid session name"});try{let r=await Sv(n);t.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){t.status(409).json({error:r?.message||String(r)})}});E.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Bu(n);if(!r)return t.json({running:!1});t.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var $M=10;async function jM(){let e=await ye(),[t,n]=await Promise.all([VI(e),JI(e)]);return{tracks:e,views:await Lw(),queuedOf:r=>hs(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}E.get("/api/idle-guard",async(e,t)=>{try{t.json(wy(await jM()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var sn=xs(),eV=l$({kind:sn}),Ml=null,$t=()=>Ml&&["auto","prompt","off"].includes(Ml)?Ml:eV,Gb=null,tV=sl.has(sn),LM=async({to:e,from:t})=>!tV||Np(await al())?!1:(Nl.arm({to:e,from:t,kind:sn}),!0);async function nV(e){let t=$t();Ml=e??null;let n=$t();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){Nl.cancel();return}Gb&&await LM(Gb)}}var FM=(()=>{try{return QG(import.meta.url)("../package.json").version||null}catch{return null}})(),Nl=d$({isBusy:async()=>wy(await jM()).busy,onStuck:({to:e,from:t})=>zn({current:t,latest:e,installKind:sn,policy:$t(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?zn({current:t,latest:e,installKind:sn,policy:$t(),status:"updating",reason:"auto"}):zn({current:t,latest:e,installKind:sn,policy:$t(),status:"failed",error:n?.reason})).catch(()=>{})});E.get("/api/node/self-update",async(e,t)=>{t.json({installKind:sn,policy:$t(),policySource:Ml?"plane":"node",current:FM,status:await al(),armed:Nl.armed})});E.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await Pp({to:n,kind:sn,reason:"manual"});if(r.ok)return Nl.cancel(),zn({current:r.from,latest:n,installKind:sn,policy:$t(),status:"updating",reason:"manual"}).catch(()=>{}),t.json({ok:!0,...r});t.status(409).json({ok:!1,error:r.reason,status:r.status??null})});async function UM(){try{let e=await u$();e&&await zn({current:e.from,latest:e.to,installKind:e.kind||sn,policy:$t(),status:e.status,error:e.error,reason:e.reason}),await Mg({current:FM,installKind:sn,policy:$t()})}catch{}}UM();setInterval(UM,3e4).unref();E.get("/api/tracks",async(e,t)=>{let n=(await ye()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>$M){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,$M).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Jc,agentAvailability:await dp(),tickets:await K$()})});E.get("/api/cost",async(e,t)=>{try{let n=await ye();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await sb(n);if(r.cursorUsage=Sw(),e.query.format==="text")return t.type("text/plain").send(wR(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/roundup",async(e,t)=>{try{let n=await ib(await ye(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(xR(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/spend",async(e,t)=>{try{let n=await ER(await ye(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Sw(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=rc(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/caps",(e,t)=>{t.json(rc())});E.post("/api/usage/caps",async(e,t)=>{try{t.json(await ed(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await PR(await ye(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await lk(e.get(tr),{byToken:Yc,legacy:()=>kc(e.body?.session_id,e.body?.cwd)});if(n==="refused")return ui("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return ui("legacy-denied",{reason:"tokenless-denied",hook:e.body?.hook_event_name}),t.status(401).json({ok:!1,error:"tokenless hook ingest is disabled (BOSTRAT_HOOK_LEGACY_DENY)"});n==="token"&&e.body?.session_id&&r.box?.sessionId&&e.body.session_id!==r.box.sessionId&&ui("mismatch",{track:r.track.id,box:r.box.name}),ui(n,{track:r?.track?.id,hook:e.body?.hook_event_name,...n==="legacy"?{reason:"tokenless-body-resolved",deny_with:"BOSTRAT_HOOK_LEGACY_DENY=1"}:{}});let o=await fR(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&tu(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await Yc(e.get(tr));if(!n?.track||!n?.box)return t.status(204).end();t.send((await ST(n.track,n.box)).join(`
|
|
764
765
|
`)+`
|
|
765
|
-
`)}catch{t.status(204).end()}});E.post("/api/git/committed",async(e,t)=>{try{let n=await zc(e.get(Qn));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});let r=String(e.body?.sha||"").trim();if(!/^[0-9a-f]{7,40}$/i.test(r))return t.json({ok:!1,error:"sha required"});t.json({ok:!0});let o=n.box.cwd?Ie.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Ie.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Ie.sep))?s:o;wT(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`))}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await le(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{sha:r,cause:o}=e.body||{};t.json({ok:!0,event:await yT(n,String(r||""),String(o||""))})}catch(n){let r=n?.message||String(n);t.status(/unknown rework/i.test(r)?404:/already answered/i.test(r)?409:400).json({error:r})}});E.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await le(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await bT(n,String(e.body?.sha||""))})}catch(n){let r=n?.message||String(n);t.status(/no standing answer/i.test(r)?409:400).json({error:r})}});E.get("/api/usage/rework",async(e,t)=>{try{t.json(await dR(await we(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/telemetry",async(e,t)=>{try{if(!zO(ti.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await VO(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/repos",async(e,t)=>{try{let n=await er(),r=new Set((await Promise.all(n.map(a=>$e(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await mi()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/github/token",async(e,t)=>{try{t.json(await Bs(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/github/status",(e,t)=>{t.json({configured:Wl(),calls:NA(),latency:jA(),webhook:wO()})});E.post("/api/github/event",Jt.json({limit:"64kb"}),(e,t)=>{let n=hO(e.body,{onAccept:r=>NO(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});E.post("/api/github/refresh",(e,t)=>{hk(),t.json({ok:!0})});E.get("/api/gmail/search",async(e,t)=>{try{let n=await xR(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await vR(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function Rl({repo:e=null,number:t=null,branch:n=null}){let r=e?await $e(e):null;if(r&&t!=null){let s=await pt(r,t),a=s&&await le(s.trackId);if(a)return a}if(!n)return null;let o=await we();return kd(o,n,s=>xd(s,{branch:n,repo:e,slug:r}))}async function EM({repo:e=null,number:t=null,branch:n=null}){let r=await Rl({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!je(r))return r;if(!n)return null;let o=e?await $e(e).catch(()=>null):null,s=await we();return kd(s,n,a=>!je(a)&&xd(a,{branch:n,repo:e,slug:o}))}async function Tn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Rl({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await $e(s).catch(()=>null):null);await C({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function BG(e){let t=(await we()).filter(n=>!je(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await $e(n.path);if(r)for(let o of n.prs){if(await pt(r,o.number))continue;let s=await kd(t,o.headRefName,a=>xd(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Ut({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}E.get("/api/git/prs",async(e,t)=>{try{let n=await KA();await BG(n.repos).catch(()=>{}),await rf(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:d}=e.body||{},p=null,f=null,w=null;try{if(s){let k=o||"merge";if(!ic.has(k))throw new Error(`invalid merge method: ${k}`);let b=Number(r);if(!Number.isInteger(b)||b<=0)throw new Error("invalid PR number");let I=await $e((await dr(n)).path);if(!I)throw new Error("repo has no GitHub remote");let R=await Rl({repo:n,number:b,branch:l}).catch(()=>null);if(!R)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=R,f=await Xd(R,"merge",{count:1,summary:`arming auto-merge on PR #${b}`}),a&&await cc(n,b),await Ut({repo:I,number:b,trackId:R.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await rc(I,b,{merge:{method:k}}))throw new Error("couldn't record the auto-merge arm");return await ts(I,b,i===!0),await ns(I,b,c===!0&&i!==!0),en(),await Tn("auto-armed",{number:b,url:d,title:u,branch:l,repo:n,track:R,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:b,auto:!0})}p=await Rl({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await Xd(p,"merge",{count:1,summary:`merging PR #${r}`}));let h=await ya(n,r,{method:o||"squash"});await Tn("merged",{number:h.number,url:d,title:u,branch:l,repo:n});let g=await $e(n).catch(()=>null),y=!1;if(g&&(i===!0&&await ts(g,h.number,!0).catch(()=>{}),c===!0&&i!==!0&&await ns(g,h.number,!0).catch(()=>{}),await hr(g,h.number).catch(()=>{}),await ys(g,h.number).catch(()=>{}),y=await fr(g,h.number).catch(()=>!1),await no(g,h.number,"merged").catch(()=>{})),i===!0&&!y){let k=await Rl({repo:n,number:h.number,branch:l}).catch(()=>null);k&&!k.archivedAt&&await gs(k.id).catch(()=>{})}t.json(h)}catch(h){w=h;let g=h?.message||String(h),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&f&&await pg(p,f,w?"failed":"completed",w).catch(()=>{})}});E.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await $e((await dr(n)).path).catch(()=>null),l=c?await oc(c,i).catch(()=>null):null;try{await Wm(n,i)}catch(u){if(!l)throw u}en(),await Tn("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});E.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await $e(n).catch(()=>null),s=await YA(n,{method:r||"merge",onMerged:a=>{Tn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&hr(o,a.number).catch(()=>{}).then(()=>ys(o,a.number)).catch(()=>{}).then(()=>fr(o,a.number)).catch(()=>{}).then(()=>no(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});E.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:JA()})});E.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{},i=null,c=null,l=null;try{let u=a||"merge";if(!ic.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await le(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await hn()).filter(h=>h.trackId===d.id&&h.state!=="merged"&&h.state!=="closed").sort(lc);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await Xd(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let h of p)await ts(h.repo,h.number,o===!0).catch(()=>{}),await ns(h.repo,h.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let h of p){let g={repo:h.repo,number:h.number,ok:!0,action:"armed"};f.push(g);try{let y=await os(h.repo);if(!y)throw new Error(`no local checkout for ${h.repo}`);let k=await ga(y,h.number);w.push({r:g,l:h,repoPath:y,pr:k,plan:GA(k,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:h,l:g,repoPath:y,pr:k,plan:b}of VA(w))try{if(b.action==="skip")h.action="skipped",h.reason=b.reason;else if(b.action==="merge")await ya(y,g.number,{method:u}),await Tn("merged",{number:g.number,url:k.url,title:k.title,branch:k.headRefName,repo:y,track:d}),await hr(g.repo,g.number).catch(()=>{}),await ys(g.repo,g.number).catch(()=>{}),await fr(g.repo,g.number).catch(()=>{}),await no(g.repo,g.number,"merged").catch(()=>{}),h.action="merged";else{if(b.action==="update-arm"&&(await cc(y,g.number).catch(()=>{}),h.action="updated-armed"),!await rc(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await Tn("auto-armed",{number:g.number,url:k.url,title:k.title,branch:k.headRefName,repo:y,track:d,...h.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(I){h.ok=!1,h.action="failed",h.reason=I?.message||String(I)}if(en(),!f.some(h=>h.ok)){if(o===!0)for(let h of p)await ts(h.repo,h.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let h of p)await ns(h.repo,h.number,!1).catch(()=>{});return t.status(502).json({error:f.map(h=>`${h.repo}#${h.number}: ${h.reason}`).join("; "),results:f})}t.json({ok:!0,trackId:d.id,results:f})}catch(u){l=u;let d=u?.message||String(u),p=/invalid|required/i.test(d)?400:502;t.status(p).json({error:d})}finally{i&&c&&await pg(i,c,l?"failed":"completed",l).catch(()=>{})}});E.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await le(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await hn()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await oc(a.repo,a.number).catch(()=>null),c=await os(a.repo).catch(()=>null);c&&await Wm(c,a.number).catch(()=>{}),i&&(await Tn("auto-canceled",{number:a.number,url:a.url,title:a.title,branch:a.headRef,repo:c,track:r}),s.push({repo:a.repo,number:a.number}))}en(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.post("/api/git/prs/open",async(e,t)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let i=await le(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Bt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(h=>{let g=u.find(y=>y.name===h||y.repo===h||y.base===h||y.dir===h);if(!g)throw new Error(`invalid repo "${h}" \u2014 not tagged on this Track`);return g});else if(d=await ls(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let f=[];for(let h of d)try{let g=await Km(h.dir,{title:r,body:o,base:s}),y=h.repo||await $e(h.dir).catch(()=>null);y&&g.number&&await Ut({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Tn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??h.name}}),f.push({repo:h.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){f.push({repo:h.name,slug:h.repo??null,ok:!1,error:g?.message||String(g)})}let w=f.filter(h=>h.ok);return w.length?t.json({ok:!0,multi:!0,results:f,url:w[0].url,number:w[0].number}):t.status(502).json({error:f.map(h=>`${h.repo}: ${h.error}`).join("; "),results:f})}let c=await Km(i.cwd,{title:r,body:o,base:s}),l=await $e(i.cwd).catch(()=>null);l&&c.number&&await Ut({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Tn("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});E.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await le(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await ls(n),o=new Map(r.map(a=>[a.base,a])),s=Bt(n.workspace).map(a=>{let i=o.get(a.base);return{name:a.name,base:a.base,baseRef:a.baseRef??null,repo:a.repo??null,dirty:i?.dirty??!1,ahead:i?.ahead??0,changed:!!i}});t.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await fp(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await hp(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});E.post("/api/tracks/:id/reshape",async(e,t)=>{let{repos:n,skipPermissions:r}=e.body||{};try{let o=await Wg(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...Ub(o)})}catch(o){let s=o?.message||String(o),a=o?.status||(/not found/i.test(s)?404:/has work|still running|already|running|archived|last repo/i.test(s)?409:/required|not a usable|tagged twice/i.test(s)?400:502);t.status(a).json({error:s})}});E.get("/api/tracks/:id/reshape",(e,t)=>{t.json(Ub(Yc(e.params.id))??{running:!1})});function Ub(e){return e?{running:!e.finishedAt,step:e.step,error:e.error??null,inPlace:e.inPlace===!0,added:e.added??[],removed:e.removed??[],scratch:e.scratch===!0,views:e.views??0,checkpoint:e.checkpoint??null,startedAt:e.startedAt??null,finishedAt:e.finishedAt??null}:null}E.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ga(n,r),s=await $e(n).catch(()=>null),a=await EM({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=Bt(a.workspace).find(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await XA(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Ie.join("ci",i.name):"ci",d=Ie.join(a.cwd,".bostrat",u),p=Ie.join(".bostrat",u,`pr-${o.number}-fail.log`);await St.promises.mkdir(d,{recursive:!0}),await St.promises.writeFile(Ie.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
|
|
766
|
+
`)}catch{t.status(204).end()}});E.post("/api/git/committed",async(e,t)=>{try{let n=await Yc(e.get(tr));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});let r=String(e.body?.sha||"").trim();if(!/^[0-9a-f]{7,40}$/i.test(r))return t.json({ok:!1,error:"sha required"});t.json({ok:!0});let o=n.box.cwd?$e.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?$e.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+$e.sep))?s:o;AT(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`))}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{sha:r,cause:o}=e.body||{};t.json({ok:!0,event:await ET(n,String(r||""),String(o||""))})}catch(n){let r=n?.message||String(n);t.status(/unknown rework/i.test(r)?404:/already answered/i.test(r)?409:400).json({error:r})}});E.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await _T(n,String(e.body?.sha||""))})}catch(n){let r=n?.message||String(n);t.status(/no standing answer/i.test(r)?409:400).json({error:r})}});E.get("/api/usage/rework",async(e,t)=>{try{t.json(await _R(await ye(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/telemetry",async(e,t)=>{try{if(!uM(ri.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await lM(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/repos",async(e,t)=>{try{let n=await nr(),r=new Set((await Promise.all(n.map(a=>Re(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await gi()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/github/token",async(e,t)=>{try{t.json(await js(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/github/status",(e,t)=>{t.json({configured:Gl(),calls:HA(),latency:GA(),webhook:MO()})});E.post("/api/github/event",Jt.json({limit:"64kb"}),(e,t)=>{let n=RO(e.body,{onAccept:r=>YO(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});E.post("/api/github/refresh",(e,t)=>{vk(),t.json({ok:!0})});E.get("/api/gmail/search",async(e,t)=>{try{let n=await BR(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await jR(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function Cl({repo:e=null,number:t=null,branch:n=null}){let r=e?await Re(e):null;if(r&&t!=null){let s=await ut(r,t),a=s&&await ue(s.trackId);if(a)return a}if(!n)return null;let o=await ye();return Sd(o,n,s=>Ad(s,{branch:n,repo:e,slug:r}))}async function HM({repo:e=null,number:t=null,branch:n=null}){let r=await Cl({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Le(r))return r;if(!n)return null;let o=e?await Re(e).catch(()=>null):null,s=await ye();return Sd(s,n,a=>!Le(a)&&Ad(a,{branch:n,repo:e,slug:o}))}async function Tn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Cl({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Re(s).catch(()=>null):null);await C({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function rV(e){let t=(await ye()).filter(n=>!Le(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Re(n.path);if(r)for(let o of n.prs){if(await ut(r,o.number))continue;let s=await Sd(t,o.headRefName,a=>Ad(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Ut({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}E.get("/api/git/prs",async(e,t)=>{try{let n=await QA();await rV(n.repos).catch(()=>{}),await cf(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:d}=e.body||{},p=null,f=null,w=null;try{if(s){let x=o||"merge";if(!lc.has(x))throw new Error(`invalid merge method: ${x}`);let b=Number(r);if(!Number.isInteger(b)||b<=0)throw new Error("invalid PR number");let I=await Re((await fr(n)).path);if(!I)throw new Error("repo has no GitHub remote");let $=await Cl({repo:n,number:b,branch:l}).catch(()=>null);if(!$)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=$,f=await ep($,"merge",{count:1,summary:`arming auto-merge on PR #${b}`}),a&&await uc(n,b),await Ut({repo:I,number:b,trackId:$.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await sc(I,b,{merge:{method:x}}))throw new Error("couldn't record the auto-merge arm");return await ns(I,b,i===!0),await rs(I,b,c===!0&&i!==!0),en(),await Tn("auto-armed",{number:b,url:d,title:u,branch:l,repo:n,track:$,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:b,auto:!0})}p=await Cl({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await ep(p,"merge",{count:1,summary:`merging PR #${r}`}));let m=await ba(n,r,{method:o||"squash"});await Tn("merged",{number:m.number,url:d,title:u,branch:l,repo:n});let g=await Re(n).catch(()=>null),y=!1;if(g&&(i===!0&&await ns(g,m.number,!0).catch(()=>{}),c===!0&&i!==!0&&await rs(g,m.number,!0).catch(()=>{}),await wr(g,m.number).catch(()=>{}),await bs(g,m.number).catch(()=>{}),y=await hr(g,m.number).catch(()=>!1),await oo(g,m.number,"merged").catch(()=>{})),i===!0&&!y){let x=await Cl({repo:n,number:m.number,branch:l}).catch(()=>null);x&&!x.archivedAt&&await ys(x.id).catch(()=>{})}t.json(m)}catch(m){w=m;let g=m?.message||String(m),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&f&&await wg(p,f,w?"failed":"completed",w).catch(()=>{})}});E.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await Re((await fr(n)).path).catch(()=>null),l=c?await ac(c,i).catch(()=>null):null;try{await Vh(n,i)}catch(u){if(!l)throw u}en(),await Tn("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});E.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await Re(n).catch(()=>null),s=await oT(n,{method:r||"merge",onMerged:a=>{Tn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&wr(o,a.number).catch(()=>{}).then(()=>bs(o,a.number)).catch(()=>{}).then(()=>hr(o,a.number)).catch(()=>{}).then(()=>oo(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});E.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:rT()})});E.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{},i=null,c=null,l=null;try{let u=a||"merge";if(!lc.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await ue(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await mn()).filter(m=>m.trackId===d.id&&m.state!=="merged"&&m.state!=="closed").sort(dc);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await ep(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let m of p)await ns(m.repo,m.number,o===!0).catch(()=>{}),await rs(m.repo,m.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let m of p){let g={repo:m.repo,number:m.number,ok:!0,action:"armed"};f.push(g);try{let y=await ss(m.repo);if(!y)throw new Error(`no local checkout for ${m.repo}`);let x=await ya(y,m.number);w.push({r:g,l:m,repoPath:y,pr:x,plan:eT(x,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:m,l:g,repoPath:y,pr:x,plan:b}of tT(w))try{if(b.action==="skip")m.action="skipped",m.reason=b.reason;else if(b.action==="merge")await ba(y,g.number,{method:u}),await Tn("merged",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d}),await wr(g.repo,g.number).catch(()=>{}),await bs(g.repo,g.number).catch(()=>{}),await hr(g.repo,g.number).catch(()=>{}),await oo(g.repo,g.number,"merged").catch(()=>{}),m.action="merged";else{if(b.action==="update-arm"&&(await uc(y,g.number).catch(()=>{}),m.action="updated-armed"),!await sc(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await Tn("auto-armed",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d,...m.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(I){m.ok=!1,m.action="failed",m.reason=I?.message||String(I)}if(en(),!f.some(m=>m.ok)){if(o===!0)for(let m of p)await ns(m.repo,m.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let m of p)await rs(m.repo,m.number,!1).catch(()=>{});return t.status(502).json({error:f.map(m=>`${m.repo}#${m.number}: ${m.reason}`).join("; "),results:f})}t.json({ok:!0,trackId:d.id,results:f})}catch(u){l=u;let d=u?.message||String(u),p=/invalid|required/i.test(d)?400:502;t.status(p).json({error:d})}finally{i&&c&&await wg(i,c,l?"failed":"completed",l).catch(()=>{})}});E.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await ue(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await mn()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await ac(a.repo,a.number).catch(()=>null),c=await ss(a.repo).catch(()=>null);c&&await Vh(c,a.number).catch(()=>{}),i&&(await Tn("auto-canceled",{number:a.number,url:a.url,title:a.title,branch:a.headRef,repo:c,track:r}),s.push({repo:a.repo,number:a.number}))}en(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.post("/api/git/prs/open",async(e,t)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let i=await ue(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=jt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(m=>{let g=u.find(y=>y.name===m||y.repo===m||y.base===m||y.dir===m);if(!g)throw new Error(`invalid repo "${m}" \u2014 not tagged on this Track`);return g});else if(d=await us(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let f=[];for(let m of d)try{let g=await Jh(m.dir,{title:r,body:o,base:s}),y=m.repo||await Re(m.dir).catch(()=>null);y&&g.number&&await Ut({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Tn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??m.name}}),f.push({repo:m.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){f.push({repo:m.name,slug:m.repo??null,ok:!1,error:g?.message||String(g)})}let w=f.filter(m=>m.ok);return w.length?t.json({ok:!0,multi:!0,results:f,url:w[0].url,number:w[0].number}):t.status(502).json({error:f.map(m=>`${m.repo}: ${m.error}`).join("; "),results:f})}let c=await Jh(i.cwd,{title:r,body:o,base:s}),l=await Re(i.cwd).catch(()=>null);l&&c.number&&await Ut({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Tn("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});E.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await us(n),o=new Map(r.map(a=>[a.base,a])),s=jt(n.workspace).map(a=>{let i=o.get(a.base);return{name:a.name,base:a.base,baseRef:a.baseRef??null,repo:a.repo??null,dirty:i?.dirty??!1,ahead:i?.ahead??0,changed:!!i}});t.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await wp(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await gp(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});E.post("/api/tracks/:id/reshape",async(e,t)=>{let{repos:n,skipPermissions:r}=e.body||{};try{let o=await Vg(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...Jb(o)})}catch(o){let s=o?.message||String(o),a=o?.status||(/not found/i.test(s)?404:/has work|still running|already|running|archived|last repo/i.test(s)?409:/required|not a usable|tagged twice/i.test(s)?400:502);t.status(a).json({error:s})}});E.get("/api/tracks/:id/reshape",(e,t)=>{t.json(Jb(Zc(e.params.id))??{running:!1})});function Jb(e){return e?{running:!e.finishedAt,step:e.step,error:e.error??null,inPlace:e.inPlace===!0,added:e.added??[],removed:e.removed??[],scratch:e.scratch===!0,views:e.views??0,checkpoint:e.checkpoint??null,startedAt:e.startedAt??null,finishedAt:e.finishedAt??null}:null}E.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ya(n,r),s=await Re(n).catch(()=>null),a=await HM({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=jt(a.workspace).find(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await sT(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?$e.join("ci",i.name):"ci",d=$e.join(a.cwd,".bostrat",u),p=$e.join(".bostrat",u,`pr-${o.number}-fail.log`);await vt.promises.mkdir(d,{recursive:!0}),await vt.promises.writeFile($e.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
|
|
766
767
|
${y.log??"(no fetchable log \u2014 see link)"}
|
|
767
768
|
`).join(`
|
|
768
|
-
`));let f=l.map(y=>y.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",h=await qt(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${w}. Failing check${l.length===1?"":"s"}: ${f}. The failure log is at ${p} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Ut({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await hA(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Tn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:h.leadBox,queued:!!h.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ga(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await $e(n).catch(()=>null),a=await EM({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=Bt(a.workspace).find(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await qt(a.id,`PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName} \u2014 has merge conflicts with ${o.baseRefName}.${c} Bring ${o.baseRefName} into this branch (fetch origin, then merge origin/${o.baseRefName} \u2014 don't rebase this pushed PR branch), and resolve every conflict so that BOTH sides' intent is preserved. Run the relevant tests, then commit and push to update the PR. If any conflict is a genuine ambiguity \u2014 where you can't confidently tell which side's behavior should win, or reconciling would drop work from either side \u2014 STOP and ask me here rather than guessing, laying out the specific choice and your recommendation.`,{kind:"reconcile"}),u=s;u&&(await Ut({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await mA(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Tn("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=to.filter(a=>e.body.actions.includes(a)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0;await co(`pr:${e.params.id}:${n}`,async()=>{let a=await le(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await q(a),c=i.find(d=>d.type==="pr.offered"&&d.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let d=await Eb(a,c,{actions:o,notify:s});if(d)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:d.pr})}let l=null;o&&(l=await qt(a.id,fa(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:c.payload.repos||null,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase")}),{kind:o.includes("pr")?"pr-go":"push-go"}));let u=o?o.includes("pr")?"pr":o.includes("push")?"push":o.includes("commit")?"commit":"rebase":"dismiss";await C({id:a.id,cwd:a.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:c.boxId,payload:{ts:Date.now(),offerId:n,action:u,actions:o,...s?{notify:!0}:{}}}),s&&Dg(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await le(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await _b(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/unknown offer/i.test(s)?404:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});var Ml=e=>t=>({...t,url:PR(t,e.headers)});E.get("/api/views",async(e,t)=>{try{let n=await Pw({trackId:e.query.track||void 0});t.json({views:n.map(Ml(e)),maxLive:uo})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/views/:id",async(e,t)=>{let n=await OE(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Ml(e)(n),session:Ta(n.slug)})});E.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await le(n):null;if(!i&&s&&(i=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Ie.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Bw({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});t.json({ok:!0,view:Ml(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});E.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Ml(e)(await ME(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Ml(e)(await CE(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/views/:id",async(e,t)=>{try{t.json(await NE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var jG=[["linear",xs,$y],["jira",Bp,_y]],Pb=new Map;E.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await Ey(),r={};for(let[o,s,a]of jG){let i=await s();if(!i){Pb.delete(o),r[o]={configured:!1};continue}let c=Pb.get(o);if(!c||Date.now()-c.at>300*1e3){let l;try{l={configured:!0,ok:!0,...await a(i)}}catch(u){l={configured:!0,ok:!1,error:u?.message||String(u)}}c={at:Date.now(),body:l},Pb.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await Ey()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await h$(o),i=n?await le(n):null;!i&&r&&(i=(await we()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Ie.sep)))||null),i&&await C({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var Rs=async(e,t)=>{let n=e?await le(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Ie.sep)))||null),n};E.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await ky()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.get("/api/roadmap",async(e,t)=>{try{t.json(await xy())}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Rs(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (circuit name or id) required"});let a=await qa(o);await Cp(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});E.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Rs(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Cp(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var _M=async(e,t,n)=>{if(e)return{ref:e,track:await Rs(t,n)};let r=await Rs(t,n),o=r?await Sy(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};E.post("/api/blueprints/publish",async(e,t)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=e.body||{};try{if(!i||!String(i).trim())return t.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await _M(o,n,r),l=await a$({circuitRef:c,newCircuitName:s,name:a,markdown:i});t.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);t.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});E.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await _M(e.query.circuit,e.query.track,e.query.cwd);t.json(await vy(n))}catch(n){let r=n?.message||String(n);t.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});E.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l}=e.body||{};try{let u=await Rs(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await l$(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...d})}catch(u){let d=u?.message||String(u);t.status(/required/i.test(d)?400:502).json({error:d})}});E.get("/api/decisions",async(e,t)=>{try{let n=await Rs(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await u$(n.id))}catch(n){let r=n?.message||String(n);t.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});E.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await Rs(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Sy(a.id);if(!i)return t.status(400).json({error:"this Track isn't in a circuit \u2014 link one first (bostrat-circuit link \u2026)"});let c=await i$(a,i,s);t.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);t.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});E.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await le(n):null;if(!s&&r&&(s=(await we()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Ie.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await Va(s,o,{source:n?"api":"cli"});t.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);t.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await le(r):null;if(!o&&n&&(o=(await we()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Ie.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await R$(),ticket:await Yn(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});E.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Yn(e.params.id)})});E.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await le(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Va(n,(e.body||{}).ref,{source:"api"});t.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);t.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});E.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Uy(e.params.id)})});var hf=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;E.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await N$(e.params.id))}catch(n){let r=n?.message||String(n);t.status(hf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Hy(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(hf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await P$(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(hf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await le(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await D$(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(hf(s)).json({error:s})}});E.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await ey(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});E.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await le(n):null;if(!s&&r&&(s=(await we()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Ie.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await j$(s,o)})}catch(s){let a=s?.message||String(s);t.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await B$()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});E.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await le(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await L$(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal|unknown team/i.test(a)?404:/already answered/i.test(a)?409:/required|no ticketing|pick one/i.test(a)?400:502).json({error:a})}});E.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Oc({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/mocks/:id",async(e,t)=>{let n=await br(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Cl={dotfiles:"allow"};E.get("/api/mocks/:id/png",async(e,t)=>{let n=await br(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=gn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=$c(n,r,"png");if(!o)return t.status(404).json({error:"no image for this version (poster extraction failed)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Cl,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});E.get("/api/mocks/:id/media",async(e,t)=>{let n=await br(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=gn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=$c(n,r,"video");if(!o)return t.status(404).json({error:"this version has no video (image or html sourced)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Cl,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});E.get("/api/mocks/:id/html",async(e,t)=>{let n=await br(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=gn(n,e.query.v??null);if(!r?.htmlRel)return t.status(404).json({error:"this version has no HTML source (image-sourced)"});t.set("content-security-policy","sandbox"),t.sendFile(nn(n,r.v).html,Cl,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});E.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Wd(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let d=a?await le(a):null;if(!d&&c&&(d=(await we()).find(h=>h.cwd&&(c===h.cwd||c.startsWith(h.cwd+Ie.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(w=>w.name===d.leadBox),f=await JE({trackId:d.id,name:i,html:n?null:s.html,image:r,video:o,cwd:d.cwd,width:l,group:u,box:d.leadBox,agent:p?.agent||null});t.json({ok:!0,mock:f})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});E.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Wd(n)?n:null;try{let o=await YE(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});E.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await QE(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await qt(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await g_(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await e_(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/flows",async(e,t)=>{try{t.json({flows:await p_({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/flows/:id",async(e,t)=>{let n=await f_(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});E.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await le(n):null;if(!a&&s&&(a=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Ie.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await h_({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});E.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await m_(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/flows/:id",async(e,t)=>{try{t.json(await w_(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await we(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Ie.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await T_({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/runbooks/:id",async(e,t)=>{let n=await Zw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});E.get("/api/runbooks/:id/md",async(e,t)=>{let n=await Zw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=S_(n,e.query.v??null);if(!r)return t.status(404).json({error:"no such version"});if(t.set("content-security-policy","sandbox"),t.set("cache-control","private, max-age=31536000, immutable"),t.type("text/markdown; charset=utf-8"),n.remote){let o=await E_(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Sr(n,r.v),Cl,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});E.get("/api/loops",async(e,t)=>{t.json(await Zi())});E.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await we()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Ie.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Zi();if(i.source!=="plane")return t.status(503).json({error:i.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${i.error||"no detail"})`});let c=i.loops.find(u=>u.trackId===a.id);if(!c)return t.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await zh({loopId:c.id,outcome:n,note:r});if(!l.ok)return t.status(l.status||503).json({error:l.error||"report failed"});t.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});E.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await le(n):null;if(!s&&r&&(s=(await we()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Ie.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await HR(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var ri=async(e,t)=>{let n=e?await le(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Ie.sep)))||null),n};E.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ri(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,result:await KT(s,o,{ship:{changedRepos:ls}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});E.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ri(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await VT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});E.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await ri(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:pw,...await ZT(r)})});var hM=new Set(["reconcile","fixing-ci","rebase","merge"]);E.get("/api/status",async(e,t)=>{let n=await ri(null,typeof e.query?.cwd=="string"?e.query.cwd:null).catch(()=>null);if(!n)return t.status(400).json({error:"a cwd inside a Track workspace is required"});t.json({ok:!0,trackId:n.id,status:n.status})});E.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await ri(n,r);if(!c)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let l=o==="fix-ci"?"fixing-ci":o;if(l!=null&&!hM.has(l))throw new Error(`phase must be one of ${[...hM].join(" | ")}`);let u=s==null?null:String(s).trim();if(u&&u.length>120)throw new Error("summary is too long (cap is 120 characters)");let d=OG();await C(c,{type:"track.phase.changed",actor:"agent",source:"cli",boxId:c.leadBox,provider:c.boxes?.find(p=>p.name===c.leadBox)?.agent??null,payload:{ts:Date.now(),phase:l||null,phaseId:d,summary:u,scope:a&&typeof a=="object"?a:null,...l?{}:{reason:i||"completed"}}}),t.json({ok:!0,trackId:c.id,phase:l||null,phaseId:d})}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await le(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await JT(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:qt,unarchiveTrack:gp})})}catch(a){let i=a?.message||String(a),c=a?.code==="removed"?410:/unknown offer/i.test(i)?404:/already answered/i.test(i)?409:/required|not on this card/i.test(i)?400:/unreachable/i.test(i)?503:502;t.status(c).json({error:i})}});E.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await le(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await GT(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});E.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await le(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await zT(s,n,r===!0,{followupId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal/i.test(a)?404:/already answered/i.test(a)?409:400).json({error:a})}});Xe.on("event",e=>{let t=e?.type==="pr.state.changed"?e.payload?.change:null;if(!t||!e.trackId)return;let n=t==="opened"?"pr.opened":t==="ci-fixed"?"checks.green":null,r=e.payload||{},o={repo:r.repo??null,prNumber:r.number??null,prTitle:r.title??null,prUrl:r.url??null};!n&&t!=="pushed"||le(e.trackId).then(async s=>{if(s&&(n&&await wc(s,n,o),t==="opened"||t==="pushed")){let a=XT(await q(s).catch(()=>[]));a&&await wc(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var IM=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await le(n):null;if(!s&&r&&(s=(await we()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Ie.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Zi();if(a.source!=="plane")return t.status(503).json({error:a.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${a.error||"no detail"})`}),null;let i;try{i=KR(a.loops,o)}catch(c){return t.status(/matches \d+ loops/.test(c.message)?409:404).json({error:c.message}),null}return{track:s,loop:i}};E.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await IM(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await GR(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await IM(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await VR(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await ri(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await xy()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?fb:kl;t.json({ok:!0,trackId:a.id,proposal:await oO(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var Hb=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;E.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await le(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await sO(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(Hb(a)).json({error:a})}});E.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await le(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await JR(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(Hb(a)).json({error:a})}});E.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await le(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await YR(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(Hb(s)).json({error:s})}});E.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await le(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await WR(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});E.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await le(n):null;if(!a&&s&&(a=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Ie.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await __({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});E.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await I_(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});E.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await $_(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await R_(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/changelog/draft",async(e,t)=>{try{let n=uO(e.query.since||null);t.json({since:n,repos:mb(),...await dO(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var $M=async({trackId:e,cwd:t})=>{let n=e?await le(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Ie.sep)))||null),n};E.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await $M({trackId:o,cwd:s});if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await pO(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|no `- `|over the|secret VALUE|mentions "/i.test(i)?400:500).json({error:i})}});E.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await $M({trackId:r,cwd:o});if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await fO(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var LG=120,Db=400,ni=null,mM=null;E.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=e.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return t.status(400).json({error:"body (the message) required"});if(i.length>Db)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Db} cap; a notification is a nudge, put the detail in chat`});let c=Mc(`${n||""}
|
|
769
|
-
${i}`);if(c.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${c.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let l=a?await
|
|
769
|
+
`));let f=l.map(y=>y.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",m=await qt(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${w}. Failing check${l.length===1?"":"s"}: ${f}. The failure log is at ${p} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Ut({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await vA(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Tn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:m.leadBox,queued:!!m.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ya(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Re(n).catch(()=>null),a=await HM({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=jt(a.workspace).find(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await qt(a.id,`PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName} \u2014 has merge conflicts with ${o.baseRefName}.${c} Bring ${o.baseRefName} into this branch (fetch origin, then merge origin/${o.baseRefName} \u2014 don't rebase this pushed PR branch), and resolve every conflict so that BOTH sides' intent is preserved. Run the relevant tests, then commit and push to update the PR. If any conflict is a genuine ambiguity \u2014 where you can't confidently tell which side's behavior should win, or reconciling would drop work from either side \u2014 STOP and ask me here rather than guessing, laying out the specific choice and your recommendation.`,{kind:"reconcile"}),u=s;u&&(await Ut({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await SA(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Tn("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=ro.filter(a=>e.body.actions.includes(a)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0;await uo(`pr:${e.params.id}:${n}`,async()=>{let a=await ue(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await q(a),c=i.find(d=>d.type==="pr.offered"&&d.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let d=await Nb(a,c,{actions:o,notify:s});if(d)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:d.pr})}let l=null;o&&(l=await qt(a.id,ma(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:c.payload.repos||null,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase")}),{kind:o.includes("pr")?"pr-go":"push-go"}));let u=o?o.includes("pr")?"pr":o.includes("push")?"push":o.includes("commit")?"commit":"rebase":"dismiss";await C({id:a.id,cwd:a.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:c.boxId,payload:{ts:Date.now(),offerId:n,action:u,actions:o,...s?{notify:!0}:{}}}),s&&Fg(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ue(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await Pb(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/unknown offer/i.test(s)?404:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});var Pl=e=>t=>({...t,url:XR(t,e.headers)});E.get("/api/views",async(e,t)=>{try{let n=await Lw({trackId:e.query.track||void 0});t.json({views:n.map(Pl(e)),maxLive:fo})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/views/:id",async(e,t)=>{let n=await LE(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Pl(e)(n),session:Ea(n.slug)})});E.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ue(n):null;if(!i&&s&&(i=(await ye()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+$e.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!hb(e.headers))return t.status(412).json({error:$$});let c=await Uw({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});t.json({ok:!0,view:Pl(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});E.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Pl(e)(await FE(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Pl(e)(await UE(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/views/:id",async(e,t)=>{try{t.json(await HE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var oV=[["linear",vs,Cy],["jira",Fp,Oy]],Wb=new Map;E.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await Ry(),r={};for(let[o,s,a]of oV){let i=await s();if(!i){Wb.delete(o),r[o]={configured:!1};continue}let c=Wb.get(o);if(!c||Date.now()-c.at>300*1e3){let l;try{l={configured:!0,ok:!0,...await a(i)}}catch(u){l={configured:!0,ok:!1,error:u?.message||String(u)}}c={at:Date.now(),body:l},Wb.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await Ry()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await v$(o),i=n?await ue(n):null;!i&&r&&(i=(await ye()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+$e.sep)))||null),i&&await C({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var Os=async(e,t)=>{let n=e?await ue(e):null;return!n&&t&&(n=(await ye()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+$e.sep)))||null),n};E.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await Ay()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.get("/api/roadmap",async(e,t)=>{try{t.json(await Ty())}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Os(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (circuit name or id) required"});let a=await Ka(o);await Dp(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});E.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Os(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Dp(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var WM=async(e,t,n)=>{if(e)return{ref:e,track:await Os(t,n)};let r=await Os(t,n),o=r?await _y(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};E.post("/api/blueprints/publish",async(e,t)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=e.body||{};try{if(!i||!String(i).trim())return t.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await WM(o,n,r),l=await m$({circuitRef:c,newCircuitName:s,name:a,markdown:i});t.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);t.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});E.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await WM(e.query.circuit,e.query.track,e.query.cwd);t.json(await Ey(n))}catch(n){let r=n?.message||String(n);t.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});E.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l}=e.body||{};try{let u=await Os(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await g$(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...d})}catch(u){let d=u?.message||String(u);t.status(/required/i.test(d)?400:502).json({error:d})}});E.get("/api/decisions",async(e,t)=>{try{let n=await Os(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await y$(n.id))}catch(n){let r=n?.message||String(n);t.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});E.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await Os(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await _y(a.id);if(!i)return t.status(400).json({error:"this Track isn't in a circuit \u2014 link one first (bostrat-circuit link \u2026)"});let c=await h$(a,i,s);t.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);t.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});E.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ue(n):null;if(!s&&r&&(s=(await ye()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+$e.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await Ja(s,o,{source:n?"api":"cli"});t.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);t.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ue(r):null;if(!o&&n&&(o=(await ye()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+$e.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await G$(),ticket:await Xn(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});E.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Xn(e.params.id)})});E.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Ja(n,(e.body||{}).ref,{source:"api"});t.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);t.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});E.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await zy(e.params.id)})});var yf=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;E.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await Y$(e.params.id))}catch(n){let r=n?.message||String(n);t.status(yf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Jy(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(yf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await X$(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(yf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ue(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Z$(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(yf(s)).json({error:s})}});E.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await oy(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});E.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ue(n):null;if(!s&&r&&(s=(await ye()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+$e.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await eR(s,o)})}catch(s){let a=s?.message||String(s);t.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await Q$()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});E.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ue(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await tR(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal|unknown team/i.test(a)?404:/already answered/i.test(a)?409:/required|no ticketing|pick one/i.test(a)?400:502).json({error:a})}});E.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Cc({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/mocks/:id",async(e,t)=>{let n=await xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Dl={dotfiles:"allow"};E.get("/api/mocks/:id/png",async(e,t)=>{let n=await xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=gn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Oc(n,r,"png");if(!o)return t.status(404).json({error:"no image for this version (poster extraction failed)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Dl,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});E.get("/api/mocks/:id/media",async(e,t)=>{let n=await xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=gn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Oc(n,r,"video");if(!o)return t.status(404).json({error:"this version has no video (image or html sourced)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Dl,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});E.get("/api/mocks/:id/html",async(e,t)=>{let n=await xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=gn(n,e.query.v??null);if(!r?.htmlRel)return t.status(404).json({error:"this version has no HTML source (image-sourced)"});t.set("content-security-policy","sandbox"),t.sendFile(nn(n,r.v).html,Dl,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});E.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Gd(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let d=a?await ue(a):null;if(!d&&c&&(d=(await ye()).find(m=>m.cwd&&(c===m.cwd||c.startsWith(m.cwd+$e.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(w=>w.name===d.leadBox),f=await r_({trackId:d.id,name:i,html:n?null:s.html,image:r,video:o,cwd:d.cwd,width:l,group:u,box:d.leadBox,agent:p?.agent||null});t.json({ok:!0,mock:f})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});E.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Gd(n)?n:null;try{let o=await o_(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});E.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await i_(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await qt(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await T_(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await c_(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/flows",async(e,t)=>{try{t.json({flows:await k_({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/flows/:id",async(e,t)=>{let n=await x_(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});E.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ue(n):null;if(!a&&s&&(a=(await ye()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+$e.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await v_({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});E.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await S_(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/flows/:id",async(e,t)=>{try{t.json(await A_(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await ye(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+$e.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await C_({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/runbooks/:id",async(e,t)=>{let n=await ng(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});E.get("/api/runbooks/:id/md",async(e,t)=>{let n=await ng(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=O_(n,e.query.v??null);if(!r)return t.status(404).json({error:"no such version"});if(t.set("content-security-policy","sandbox"),t.set("cache-control","private, max-age=31536000, immutable"),t.type("text/markdown; charset=utf-8"),n.remote){let o=await N_(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Tr(n,r.v),Dl,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});E.get("/api/loops",async(e,t)=>{t.json(await ec())});E.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await ye()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+$e.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await ec();if(i.source!=="plane")return t.status(503).json({error:i.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${i.error||"no detail"})`});let c=i.loops.find(u=>u.trackId===a.id);if(!c)return t.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await Zm({loopId:c.id,outcome:n,note:r});if(!l.ok)return t.status(l.status||503).json({error:l.error||"report failed"});t.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});E.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ue(n):null;if(!s&&r&&(s=(await ye()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+$e.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await oO(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var si=async(e,t)=>{let n=e?await ue(e):null;return!n&&t&&(n=(await ye()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+$e.sep)))||null),n};E.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await si(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,result:await QT(s,o,{ship:{changedRepos:us}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});E.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await si(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await tE(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});E.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await si(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:ww,...await aE(r)})});var RM=new Set(["reconcile","fixing-ci","rebase","merge"]);E.get("/api/status",async(e,t)=>{let n=await si(null,typeof e.query?.cwd=="string"?e.query.cwd:null).catch(()=>null);if(!n)return t.status(400).json({error:"a cwd inside a Track workspace is required"});t.json({ok:!0,trackId:n.id,status:n.status})});E.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await si(n,r);if(!c)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let l=o==="fix-ci"?"fixing-ci":o;if(l!=null&&!RM.has(l))throw new Error(`phase must be one of ${[...RM].join(" | ")}`);let u=s==null?null:String(s).trim();if(u&&u.length>120)throw new Error("summary is too long (cap is 120 characters)");let d=XG();await C(c,{type:"track.phase.changed",actor:"agent",source:"cli",boxId:c.leadBox,provider:c.boxes?.find(p=>p.name===c.leadBox)?.agent??null,payload:{ts:Date.now(),phase:l||null,phaseId:d,summary:u,scope:a&&typeof a=="object"?a:null,...l?{}:{reason:i||"completed"}}}),t.json({ok:!0,trackId:c.id,phase:l||null,phaseId:d})}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await ue(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await rE(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:qt,unarchiveTrack:kp})})}catch(a){let i=a?.message||String(a),c=a?.code==="removed"?410:/unknown offer/i.test(i)?404:/already answered/i.test(i)?409:/required|not on this card/i.test(i)?400:/unreachable/i.test(i)?503:502;t.status(c).json({error:i})}});E.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await eE(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});E.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await ue(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await nE(s,n,r===!0,{followupId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal/i.test(a)?404:/already answered/i.test(a)?409:400).json({error:a})}});Je.on("event",e=>{let t=e?.type==="pr.state.changed"?e.payload?.change:null;if(!t||!e.trackId)return;let n=t==="opened"?"pr.opened":t==="ci-fixed"?"checks.green":null,r=e.payload||{},o={repo:r.repo??null,prNumber:r.number??null,prTitle:r.title??null,prUrl:r.url??null};!n&&t!=="pushed"||ue(e.trackId).then(async s=>{if(s&&(n&&await yc(s,n,o),t==="opened"||t==="pushed")){let a=sE(await q(s).catch(()=>[]));a&&await yc(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var qM=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await ue(n):null;if(!s&&r&&(s=(await ye()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+$e.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await ec();if(a.source!=="plane")return t.status(503).json({error:a.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${a.error||"no detail"})`}),null;let i;try{i=iO(a.loops,o)}catch(c){return t.status(/matches \d+ loops/.test(c.message)?409:404).json({error:c.message}),null}return{track:s,loop:i}};E.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await qM(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await cO(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await qM(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await lO(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await si(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await Ty()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?xb:Sl;t.json({ok:!0,trackId:a.id,proposal:await kO(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var Yb=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;E.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await ue(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await xO(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(Yb(a)).json({error:a})}});E.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await ue(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await dO(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(Yb(a)).json({error:a})}});E.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await ue(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await pO(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(Yb(s)).json({error:s})}});E.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await ue(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await sO(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});E.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ue(n):null;if(!a&&s&&(a=(await ye()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+$e.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await P_({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});E.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await D_(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});E.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await B_(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await j_(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/changelog/draft",async(e,t)=>{try{let n=EO(e.query.since||null);t.json({since:n,repos:Sb(),...await _O(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var KM=async({trackId:e,cwd:t})=>{let n=e?await ue(e):null;return!n&&t&&(n=(await ye()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+$e.sep)))||null),n};E.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await KM({trackId:o,cwd:s});if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await IO(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|no `- `|over the|secret VALUE|mentions "/i.test(i)?400:500).json({error:i})}});E.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await KM({trackId:r,cwd:o});if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await $O(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var sV=120,qb=400,oi=null,OM=null;E.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=e.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return t.status(400).json({error:"body (the message) required"});if(i.length>qb)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${qb} cap; a notification is a nudge, put the detail in chat`});let c=Nc(`${n||""}
|
|
770
|
+
${i}`);if(c.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${c.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let l=a?await ue(a):null;if(!l&&s&&(l=(await ye()).find(w=>w.cwd&&(s===w.cwd||s.startsWith(w.cwd+$e.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(f=>f.name===l.leadBox),d=(f,w)=>String(f).replace(/\s+/g," ").trim().slice(0,w),p={title:n?d(n,sV):l.name,body:d(i,qb),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await C(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:p}),t.json({ok:!0,notification:p,delivered:oi?oi.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});E.post("/api/dictation",async(e,t)=>{if(!Buffer.isBuffer(e.body)||e.body.length===0)return t.status(400).json({error:"expected a raw audio body"});try{t.json(await AM(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});E.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await il(),terms:await Ub(),problem:await SM()})});E.post("/api/dictation/learn",async(e,t)=>{let{transcript:n,finalText:r}=e.body||{};if(typeof n!="string"||typeof r!="string")return t.status(400).json({error:"transcript and finalText are required"});t.json({learned:await vM(n,r)})});E.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await ue(e.params.id))return t.status(404).json({error:"track not found"});t.json(await TM())});E.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});if(n.archivedAt)return t.status(409).json({error:"track is archived"});t.json(await EM())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});E.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{model:r,usage:o,seconds:s}=e.body||{};t.json({ok:!0,...await _M(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});E.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c,ticket:l,circuit:u}=e.body||{};try{let d=await yp({name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c!==!1}),p=null;if(l)try{await Ja(d,l,{source:"create"})}catch(w){p=w?.message||String(w)}let f=null;if(u)try{await Dp(d,await Ka(u),{source:"picker"})}catch(w){f=w?.message||String(w)}t.json({ok:!0,track:d,...p?{ticketWarning:p}:{},...f?{circuitWarning:f}:{}})}catch(d){let p=d?.message||String(d);t.status(/required|unknown agent|invalid|must be/i.test(p)?400:500).json({error:p})}});E.get("/api/tracks/:id",async(e,t)=>{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:GM(Wa(e.params.id)),reshape:Jb(Zc(e.params.id)),subtasks:ks(e.params.id).map(Bl),pendingOffers:await Ng(n)})});E.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Zg(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await zy(e.params.id).catch(()=>{}),t.json(n)}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await ys(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});E.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await ty(e.params.id,e.body?.name)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/loop run Tracks/i.test(r)?409:/required|too long/i.test(r)?400:500;t.status(o).json({error:r})}});E.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await kp(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});E.get("/api/tracks/:id/messages",async(e,t)=>{let n=await pp(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});E.get("/api/tracks/:id/events",async(e,t)=>{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),t.flushHeaders();let r=i=>t.write(`id: ${i.seq}
|
|
770
771
|
data: ${JSON.stringify(i)}
|
|
771
772
|
|
|
772
|
-
`),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await q(n))i.seq>o&&r(i);let s=
|
|
773
|
+
`),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await q(n))i.seq>o&&r(i);let s=Mk(n.id,r),a=setInterval(()=>t.write(`: hb
|
|
773
774
|
|
|
774
|
-
`),25e3);e.on("close",()=>{clearInterval(a),s()})});E.get("/api/tracks/:id/search",async(e,t)=>{let n=await
|
|
775
|
-
`);E.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await qt(e.params.id,
|
|
775
|
+
`),25e3);e.on("close",()=>{clearInterval(a),s()})});E.get("/api/tracks/:id/search",async(e,t)=>{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=String(e.query.q||"").trim();if(!r)return t.status(400).json({error:"q (query) is required"});let o=Math.min(Math.max(Number(e.query.k)||8,1),50),s=Ji(await q(n)),a=Iu(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});E.get("/api/memory",async(e,t)=>{t.json({stores:await Jk(),harvest:Kk()})});E.delete("/api/memory/:key/:file",async(e,t)=>{let n=String(e.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return t.status(400).json({error:"bad store key"});try{t.json({ok:!0,...await Yk(n,String(e.params.file||""))})}catch(r){let o=r?.message||String(r);t.status(/not found/i.test(o)?404:/bad fact/i.test(o)?400:500).json({error:o})}});var aV=["Run a memory consolidation pass on this workspace's `.bostrat/memory/` directory:","1. Read `MEMORY.md` and every fact file.","2. Merge duplicates and facts that describe the same thing (keep the best-written one; fold unique details in; give the survivor a `supersedes:` entry naming what it absorbed, delete the absorbed file, and remove its index line).","3. Resolve contradictions in favor of the newest evidence \u2014 check the code where feasible before deciding.","4. Mark clearly-stale facts: correct them in place or delete them (file + index line).","5. Bump `metadata.modified` (ISO-8601, now) on every fact you touch.","6. Keep `MEMORY.md` one line per fact, under 200 lines.","When done, summarize what you merged, corrected, and deleted \u2014 that summary is the review record."].join(`
|
|
776
|
+
`);E.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await qt(e.params.id,aV)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:/not running/i.test(r)?400:500).json({error:r})}});E.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await xp(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});E.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r,producer:o}=e.body||{};try{t.json(await qt(e.params.id,n,{attachments:r,producer:typeof o=="string"?o:null,dismissPrompt:!0}))}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});if(s?.transferredTo)return t.status(409).json({error:a,transferredTo:s.transferredTo});t.status(/not found/i.test(a)?404:/archived/i.test(a)?409:/required|not running/i.test(a)?400:500).json({error:a})}});E.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(n.archivedAt)return t.status(409).json({error:"track is archived"});if(!n.cwd)return t.status(409).json({error:"track has no workspace yet"});let r=Buffer.isBuffer(e.body)?e.body:null,o=await q_(n.cwd,{filename:e.query.filename,buffer:r});t.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);t.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});E.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(!n.cwd)return t.status(404).json({error:"track has no workspace"});let r=$e.basename(String(e.params.file||""));if(!r||!sg($e.extname(r).slice(1)))return t.status(400).json({error:"not an upload path"});t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox");let o=og(n.cwd),s,a;try{s=await vt.promises.realpath(o),a=await vt.promises.realpath($e.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+$e.sep))return t.status(404).json({error:"upload not found"});t.sendFile(r,{root:o},i=>{i&&!t.headersSent&&t.status(404).json({error:"upload not found"})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});var iV=/^[0-9a-fA-F-]{8,64}$/;E.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});let{box:r,uuid:o}=e.params,s=Number(e.params.idx);if(!iV.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(p=>p.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=un(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=VG.createInterface({input:vt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let p of u){if(!p.includes(c))continue;let f;try{f=JSON.parse(p)}catch{continue}if(f.uuid===o){l=f,u.close();break}}let d=l?gm(l)[s]:null;if(!d||!/^image\//.test(d.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",d.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(d.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await hp(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});E.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await jg(e.params.id);t.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o,custom:s}=e.body||{};try{t.json(await fp(e.params.id,{promptId:n,answers:r,text:o,custom:s}))}catch(a){let i=a?.message||String(a),c=/not found/i.test(i)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected|custom answer|didn't take/i.test(i)?409:500;t.status(c).json({error:i})}});E.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await Yg({provider:e.params.provider,fresh:e.body?.fresh===!0});t.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);t.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});E.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await Dg(e.params.id,{promptId:n,questionIndex:r}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/no pending prompt|changed since|not running|not supported|out of range|review screen/i.test(s)?409:500;t.status(a).json({error:s})}});E.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Wg(e.params.id,typeof n=="string"?n:"",{rev:typeof r=="number"?r:null}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required/i.test(s)?400:500;t.status(a).json({error:s})}});E.get("/api/tracks/:id/usage",async(e,t)=>{let n=await ue(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=n.boxes?.find(s=>s.name===n.leadBox)||null,o=e.query.fresh==="1"||e.query.fresh==="true";t.json(await ef(r,{fresh:o}))});E.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await qg(e.params.id,n))}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/required|unknown model|not running/i.test(o)?400:500;t.status(s).json({error:o})}});E.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await fy(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:Bl(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return t.status(429).json({error:"usage_cap",message:i,cap:a.usageCap});let c=/not found/i.test(i)?404:/required|unknown agent|git repo|not running|can't resolve/i.test(i)?400:500;t.status(c).json({error:i})}});E.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:ks(e.params.id).map(Bl)})});E.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Pg(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});E.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:Bl(_p(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});E.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:Bl(my(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function Bl(e){return e?{id:e.id,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,step:e.step,running:!e.finishedAt,box:e.box,branch:e.branch,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}E.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await vp(e.params.id,n,r!==!1,o);t.json({ok:!0,step:s.step,toAgent:s.toAgent,fromBox:s.fromBox,skipPermissions:s.skipPermissions})}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});t.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});E.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await Ug(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});E.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(GM(Wa(e.params.id))??{running:!1})});E.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await ly(e.params.id);t.json({ok:!0,step:n.step,startedAt:n.startedAt})}catch(n){let r=n?.message||String(n);t.status(/already running/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});E.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=cy(e.params.id);if(!n)return t.json({running:!1});t.json({running:!n.finishedAt,step:n.step,error:n.error,startedAt:n.startedAt,finishedAt:n.finishedAt,...n.result??{}})});E.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Ap(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:400).json({error:r})}});E.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await dy({...e.body||{},trackId:n}))}catch(r){let o=r?.message||String(r);t.status(/already running|already hosted/i.test(o)?409:/not found/i.test(o)?404:400).json({error:o})}});function GM(e){return e?{running:!e.finishedAt,step:e.step,error:e.error,fromBox:e.fromBox,toBox:e.toBox,toAgent:e.toAgent,skipPermissions:e.skipPermissions,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}E.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:lu(),paths:f0,trace:await p0({limit:n})})});var Kb=$e.resolve(PM,"..","..","client","dist");vt.existsSync(Kb)&&(E.use(Jt.static(Kb)),E.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile($e.join(Kb,"index.html"),Dl)));var VM=JG.createServer(E),cV=new ZG({noServer:!0}),zM=(e,t,n)=>{if(!(vl(e)||ri.allowed(ri.clientIp(e))||Vb.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
|
|
776
777
|
\r
|
|
777
|
-
`),t.destroy();return}if(
|
|
778
|
+
`),t.destroy();return}if(YR(e,t,n))return;if(!VR(e,zb,{enforce:BM})){t.write(`HTTP/1.1 401 Unauthorized\r
|
|
778
779
|
\r
|
|
779
|
-
`),t.destroy();return}let r=
|
|
780
|
+
`),t.destroy();return}let r=N0(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
|
|
780
781
|
\r
|
|
781
|
-
`),t.destroy();return}let o=r.sessionName;if(!
|
|
782
|
+
`),t.destroy();return}let o=r.sessionName;if(!Be(o)){t.write(`HTTP/1.1 400 Bad Request\r
|
|
782
783
|
\r
|
|
783
|
-
`),t.destroy();return}let{cols:s,rows:a}=r;
|
|
784
|
+
`),t.destroy();return}let{cols:s,rows:a}=r;cV.handleUpgrade(e,t,n,i=>O0(i,o,{cols:s,rows:a}))};VM.on("upgrade",zM);var JM=process.env.BOSTRAT_CERT_DIR||$e.join(process.env.HOME||Ol.tmpdir(),".bostrat","certs"),MM=Number(process.env.BOSTRAT_TLS_PORT)||3443,CM=$e.join(JM,"bostrat.globopi.key"),NM=$e.join(JM,"bostrat.globopi.crt");if(vt.existsSync(CM)&&vt.existsSync(NM)){let e=YG.createServer({key:vt.readFileSync(CM),cert:vt.readFileSync(NM)},E);e.on("upgrade",zM),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(MM,gf,()=>{console.log(`[bostrat-agent] https listening on ${gf||"0.0.0.0"}:${MM}`)})}VM.listen(IM,gf,()=>{console.log(`[bostrat-agent] listening on ${gf||"0.0.0.0"}:${IM}`);let e=YI(process.env);e&&console.warn(`[bostrat-agent] \u26A0 SECURITY: plane-linked node bound to ${e.host?e.host:"ALL interfaces (BOSTRAT_HOST=all)"} \u2014 the API + Views are reachable off-loopback (LAN/VPN), where the IP allowlist is spoofable and Views need no token. The plane tunnel does not require this; set BOSTRAT_HOST=127.0.0.1 once any local reverse-proxy/WireGuard path is retired (F-2).`),console.log(`[bostrat-agent] tmux socket: ${Ft}`),console.log(`[bostrat-agent] auto-trigger default: ${DM}%`),console.log(`[bostrat-agent] ip allowlist: ${ri.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Vb.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),ay().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),zg().then(t=>t&&console.log(`[bostrat-agent] rolled back ${t} interrupted reshape(s)`)).catch(t=>console.error("[bostrat-agent] reshape reconcile failed:",t?.message||t)),py().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),ny().then(t=>t&&console.log(`[bostrat-agent] healed ${t} half-demoted transferred track(s)`)).catch(t=>console.error("[bostrat-agent] demoted-track reconcile failed:",t?.message||t)).then(()=>ry()).then(t=>t&&console.log(`[bostrat-agent] reaped ${t} orphaned box(es) on archived track(s)`)).catch(t=>console.error("[bostrat-agent] archived-orphan sweep failed:",t?.message||t)),Jg().then(t=>console.log(`[bostrat-agent] standing instructions refreshed (${t.refreshed} updated, ${t.removed} legacy CLAUDE.md removed${t.codexGlobal?`, codex global ${t.codexGlobal}`:""})`)).catch(t=>console.error("[bostrat-agent] standing-instructions refresh failed:",t?.message||t)),wV(),zI({listTracks:ye}),aI({trackOf:Cg}),dV(),pV(),hV(),FS({listTracks:ye,getTrack:ue}).then(t=>console.log(`[bostrat-agent] spend caps ${t.configured?"armed":"unconfigured (fail-open)"} \u2014 seeded ${Object.keys(t.spent).length} provider counter(s)`)).catch(t=>console.error("[bostrat-agent] spend-caps seed failed (staying fail-open):",t?.message||t)),Y_()&&Q_({listTracks:ye}),h0().then(t=>console.log(`[bostrat-agent] git hook shims at ${t}`)).catch(t=>console.error("[bostrat-agent] git hook shims failed (commits go unstamped):",t?.message||t)),JO(),QO(),nR({resolveTrack:ue}),pR({listTracks:ye,createTrack:yp,archiveTrack:ys,listRepos:nr,resolveTrack:ue,sayToLead:qt,answerPrompt:fp,startLeadHandoff:vp,interruptLead:hp,listSubtaskJobs:ks,cancelSubtask:_p,readEvents:q,appendEvent:C,divertShip:Nb,answerPrExists:Pb,knownAgents:Jc}),lV(),Mi().then(t=>{t||console.warn(`[boot] no host tmux server on ${Ft} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),fM(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(oi=a$({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:zb,nodeId:process.env.BOSTRAT_NODE_ID||Ol.hostname(),name:process.env.BOSTRAT_NODE_NAME||Ol.hostname(),listTracks:ye,detectAgents:dp,sampleMetrics:$R,deliverySample:()=>TE(Bg()),onHashKey:kE,onViewBase:M$,onTracksTransferred:uy,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||Ol.hostname()} \u2192 plane spine sync has stalled: ${n} event(s) unanswered for ${s} min (${o} door). New Tracks won't open from the plane until it recovers; the node is redialing with backoff.`;console.error(`[plane-link] ${a}`),process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync stalled",Tags:"rotating_light"},body:a}).catch(()=>{}),OM=t},onRecovered:async({downMs:t})=>{let n=Math.round(t/6e4);process.env.BOSTRAT_NTFY_URL&&n>=5&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync recovered",Tags:"white_check_mark"},body:`Spine sync to the plane recovered after ${n} min; the backlog is delivered.`}).catch(()=>{}),OM=null},onConnected:()=>{zO()},onRemoved:({reason:t,via:n})=>{let r=`${process.env.BOSTRAT_NODE_NAME||Ol.hostname()} was removed from Bostrat (${t}, via ${n}) and is now dormant: it will not redial. The box and its data are untouched; destroy the machine or re-provision it with a new node token.`;console.error(`[plane-link] ${r}`),process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: node removed, now dormant",Tags:"zzz"},body:r}).catch(()=>{})},onUpdateAvailable:async t=>{try{Gb={latest:t.latest,current:t.current},await zn({...t,policy:$t()}),$t()==="auto"&&await LM({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>nV(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await zn({current:t,latest:a,min:n,installKind:o,required:!0,policy:$t(),status:"available",reason:"refused"}),$t()!=="off"&&a){let i=await Pp({to:a,kind:sn,reason:"hard-floor"});i.ok?(Nl.cancel(),await zn({current:t,latest:a,min:n,installKind:o,required:!0,policy:$t(),status:"updating",reason:"hard-floor"})):console.error(`[self-update] hard-floor update not started: ${i.reason} \u2014 ${s}`)}}catch(a){console.error(`[plane-link] hard-floor handling failed: ${a?.message||a}`)}},updatePolicy:$t}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Ws().catch(()=>{}),U_().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),rR().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),d_().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),I_().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),CA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{oi?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function lV(){uV(),Hd().catch(()=>{}),setInterval(()=>Hd().catch(()=>{}),1e4)}function uV(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-roadmap","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-status","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=$e.resolve(PM,"..","bin",e),n=$e.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!vt.existsSync(t))continue;vt.mkdirSync(n,{recursive:!0});let r=$e.join(n,e);(vt.existsSync(r)?vt.readlinkSync(r):null)!==t&&(vt.rmSync(r,{force:!0}),vt.symlinkSync(t,r)),console.log(`[bostrat-agent] ${e} CLI linked at ${r}`)}catch(t){console.error(`[bostrat-agent] ${e} CLI link failed:`,t?.message||t)}}function dV(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await ye(),r=await MR({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{e=!1}}};setInterval(t,6e4),t()}function pV(){let e=null,t=async()=>{try{let n=oa(),r=0,o=[],s=null,a=null;try{let u=await ye(),d=await sb(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await RR(u,{days:7}),a=(await ib(u,{window:"7d"})).categorization}catch{}let i=[...n.problems,...a?.problems||[]];s&&!s.ok&&i.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let c=o.filter(u=>u!=="unknown");c.length&&i.push(`${r} unpriced turn(s) \u2014 add rates for: ${c.join(", ")}`);let l=i.join(`
|
|
784
785
|
`);if(!i.length){e!==""&&console.log(`[pricing] table ok \u2014 rates verified ${n.tableVerifiedAt??"never"}`),e="";return}for(let u of i)console.warn(`[pricing] \u26A0 ${u}`);l!==e&&process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: cost instrument needs attention",Tags:"warning"},body:i.join(`
|
|
785
|
-
`).slice(0,900)}).catch(()=>{}),e=l}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var
|
|
786
|
+
`).slice(0,900)}).catch(()=>{}),e=l}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var fV=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,mV=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function hV(){let e=async()=>{try{let n=await zk();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await ye()).filter(a=>!Le(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await Vk([...new Set(o)]);s.harvested&&console.log(`[memory] reconciler harvested ${s.harvested} fact(s) from ${o.length} live workspace(s)`)}catch{}};setTimeout(()=>{e(),setInterval(e,fV).unref()},mV).unref()}function wV(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await ye();for(let n of t)Le(n)||!n.boxes?.some(r=>r.state==="live")||(await pp(n.id).catch(()=>{}),await qd(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}
|